Skip to content

Commit

Permalink
Add constant name convention config
Browse files Browse the repository at this point in the history
Notes:
- Add screaming snake case scheme
- Downgrade sphinx there is some issue with 3.5.0
- Closes #407
  • Loading branch information
tefra committed Feb 14, 2021
1 parent 8713415 commit 4455be9
Show file tree
Hide file tree
Showing 9 changed files with 63 additions and 22 deletions.
1 change: 0 additions & 1 deletion docs/api/xml-nodes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ for models and their fields.

XmlNode
ElementNode
AnyTypeNode
WildcardNode
UnionNode
PrimitiveNode
3 changes: 2 additions & 1 deletion docs/examples/config.sample.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<Config xmlns="http://pypi.org/project/xsdata" version="21.1">
<Config xmlns="http://pypi.org/project/xsdata" version="21.2">
<Output wsdl="false" maxLineLength="79">
<Package>generated</Package>
<Format>pydata</Format>
Expand All @@ -10,6 +10,7 @@
<Conventions>
<ClassName case="pascalCase" safePrefix="type"/>
<FieldName case="snakeCase" safePrefix="value"/>
<ConstantName case="screamingSnakeCase" safePrefix="value"/>
<ModuleName case="snakeCase" safePrefix="mod"/>
<PackageName case="snakeCase" safePrefix="pkg"/>
</Conventions>
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ dev =
pytest-cov
tox
docs =
sphinx
sphinx==3.4.3
sphinx-autobuild
sphinx-autodoc-typehints
sphinx-copybutton
Expand Down
2 changes: 1 addition & 1 deletion tests/formats/dataclass/test_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def test_constant_name(self):
self.assertEqual("NONE_VALUE", self.filters.constant_name("None", "cls"))
self.assertEqual("BR_EAK_VALUE", self.filters.constant_name("BrEak", "cls"))
self.assertEqual("VALUE_1", self.filters.constant_name("1", "cls"))
self.assertEqual("BANG", self.filters.constant_name("boom", "cls"))
self.assertEqual("Bang", self.filters.constant_name("boom", "cls"))

def test_module_name(self):
self.filters.module_aliases["http://github.com/tefra/xsdata"] = "xsdata"
Expand Down
2 changes: 2 additions & 0 deletions tests/models/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ def test_create(self):
" <Conventions>\n"
' <ClassName case="pascalCase" safePrefix="type"/>\n'
' <FieldName case="snakeCase" safePrefix="value"/>\n'
' <ConstantName case="screamingSnakeCase" safePrefix="value"/>\n'
' <ModuleName case="snakeCase" safePrefix="mod"/>\n'
' <PackageName case="snakeCase" safePrefix="pkg"/>\n'
" </Conventions>\n"
Expand Down Expand Up @@ -79,6 +80,7 @@ def test_read(self):
" <Conventions>\n"
' <ClassName case="pascalCase" safePrefix="type"/>\n'
' <FieldName case="snakeCase" safePrefix="value"/>\n'
' <ConstantName case="screamingSnakeCase" safePrefix="value"/>\n'
' <ModuleName case="snakeCase" safePrefix="mod"/>\n'
' <PackageName case="snakeCase" safePrefix="pkg"/>\n'
" </Conventions>\n"
Expand Down
11 changes: 11 additions & 0 deletions tests/utils/test_text.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from xsdata.utils.text import mixed_pascal_case
from xsdata.utils.text import mixed_snake_case
from xsdata.utils.text import pascal_case
from xsdata.utils.text import screaming_snake_case
from xsdata.utils.text import snake_case
from xsdata.utils.text import split_words

Expand All @@ -21,6 +22,16 @@ def test_snake_case(self):
self.assertEqual("user_name", snake_case("user_name"))
self.assertEqual("suser_name", snake_case("SUserNAME"))

def test_screaming_snake_case(self):
self.assertEqual("P00P", screaming_snake_case("p00p"))
self.assertEqual("USERNAME", screaming_snake_case("USERName"))
self.assertEqual("USER_NAME", screaming_snake_case("UserNAME"))
self.assertEqual("USER_NAME", screaming_snake_case("USER_name"))
self.assertEqual("USER_NAME", screaming_snake_case("USER-NAME"))
self.assertEqual("USER_NAME", screaming_snake_case("User_Name"))
self.assertEqual("USER_NAME", screaming_snake_case("user_name"))
self.assertEqual("SUSER_NAME", screaming_snake_case("SUserNAME"))

def test_pascal_case(self):
self.assertEqual("P00P", pascal_case("p00p"))
self.assertEqual("Username", pascal_case("USERName"))
Expand Down
16 changes: 13 additions & 3 deletions xsdata/formats/dataclass/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,13 @@ class Filters:

class_case: Callable = field(default=text.pascal_case)
field_case: Callable = field(default=text.snake_case)
constant_case: Callable = field(default=text.screaming_snake_case)
package_case: Callable = field(default=text.snake_case)
module_case: Callable = field(default=text.snake_case)

class_safe_prefix: str = field(default="type")
field_safe_prefix: str = field(default="value")
constant_safe_prefix: str = field(default="value")
package_safe_prefix: str = field(default="pkg")
module_safe_prefix: str = field(default="mod")

Expand Down Expand Up @@ -97,9 +99,10 @@ def field_name(self, name: str, class_name: str) -> str:
Provide the class name as context for the naming schemes.
"""
return self.field_aliases.get(name) or self._field_name(name, class_name)
alias = self.field_aliases.get(name)
if alias:
return alias

def _field_name(self, name: str, class_name: str) -> str:
safe_name = utils.safe_snake(name, self.field_safe_prefix)
return self.field_case(safe_name, class_name=class_name)

Expand All @@ -110,7 +113,12 @@ def constant_name(self, name: str, class_name: str) -> str:
Provide the class name as context for the naming schemes.
"""
return self.field_name(name, class_name).upper()
alias = self.field_aliases.get(name)
if alias:
return alias

safe_name = utils.safe_snake(name, self.constant_safe_prefix)
return self.constant_case(safe_name, class_name=class_name)

def module_name(self, name: str) -> str:
"""Convert the given string to a module name according to the selected
Expand Down Expand Up @@ -538,10 +546,12 @@ def index_aliases(aliases: List[GeneratorAlias]) -> Dict:
module_aliases=index_aliases(config.aliases.module_name),
class_case=config.conventions.class_name.case,
field_case=config.conventions.field_name.case,
constant_case=config.conventions.constant_name.case,
package_case=config.conventions.package_name.case,
module_case=config.conventions.module_name.case,
class_safe_prefix=config.conventions.class_name.safe_prefix,
field_safe_prefix=config.conventions.field_name.safe_prefix,
constant_safe_prefix=config.conventions.constant_name.safe_prefix,
package_safe_prefix=config.conventions.package_name.safe_prefix,
module_safe_prefix=config.conventions.module_name.safe_prefix,
docstring_style=config.output.docstring_style,
Expand Down
43 changes: 28 additions & 15 deletions xsdata/models/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,30 +52,39 @@ class NameCase(Enum):
when it encounters non alphanumerical characters or when an upper
case letter follows a lower case letter.
========= ========= ========= ========== ========= =========== ============
Original Pascal Camel Snake Mixed Mixed Snake Mixed Pascal
========= ========= ========= ========== ========= =========== ============
p00p P00P p00P p00p p00p p00p P00p
USERName Username username username USERName USERName USERName
UserNAME UserName userName user_name UserNAME User_NAME UserNAME
USER_name UserName userName user_name USERname USER_name USERname
USER-NAME UserName userName user_name USERNAME USER_NAME USERNAME
User_Name UserName userName user_name UserName User_Name UserName
user_name UserName userName user_name username user_name Username
SUserNAME SuserName suserName suser_name SUserNAME SUser_NAME SUserNAME
========= ========= ========= ========== ========= =========== ============
+-----------+-----------+-----------+------------+-----------------+-----------+-------------+--------------+
| Original | Pascal | Camel | Snake | Screaming Snake | Mixed | Mixed Snake | Mixed Pascal |
+===========+===========+===========+============+=================+===========+=============+==============+
| p00p | P00P | p00P | p00p | P00P | p00p | p00p | P00p |
+-----------+-----------+-----------+------------+-----------------+-----------+-------------+--------------+
| USERName | Username | username | username | USERNAME | USERName | USERName | USERName |
+-----------+-----------+-----------+------------+-----------------+-----------+-------------+--------------+
| UserNAME | UserName | userName | user_name | USER_NAME | UserNAME | User_NAME | UserNAME |
+-----------+-----------+-----------+------------+-----------------+-----------+-------------+--------------+
| USER_name | UserName | userName | user_name | USER_NAME | USERname | USER_name | USERname |
+-----------+-----------+-----------+------------+-----------------+-----------+-------------+--------------+
| USER-NAME | UserName | userName | user_name | USER_NAME | USERNAME | USER_NAME | USERNAME |
+-----------+-----------+-----------+------------+-----------------+-----------+-------------+--------------+
| User_Name | UserName | userName | user_name | USER_NAME | UserName | User_Name | UserName |
+-----------+-----------+-----------+------------+-----------------+-----------+-------------+--------------+
| user_name | UserName | userName | user_name | USER_NAME | username | user_name | Username |
+-----------+-----------+-----------+------------+-----------------+-----------+-------------+--------------+
| SUserNAME | SuserName | suserName | suser_name | SUSER_NAME | SUserNAME | SUser_NAME | SUserNAME |
+-----------+-----------+-----------+------------+-----------------+-----------+-------------+--------------+
:cvar PASCAL: pascalCase
:cvar CAMEL: camelCase
:cvar SNAKE: snakeCase
:cvar SCREAMING_SNAKE:
:cvar MIXED: mixedCase
:cvar MIXED_SNAKE: mixedSnakeCase
:cvar MIXED_PASCAL: mixedPascalCase
"""
:cvar MIXED_SNAKE:
:cvar MIXED_PASCAL:
""" # noqa

PASCAL = "pascalCase"
CAMEL = "camelCase"
SNAKE = "snakeCase"
SCREAMING_SNAKE = "screamingSnakeCase"
MIXED = "mixedCase"
MIXED_SNAKE = "mixedSnakeCase"
MIXED_PASCAL = "mixedPascalCase"
Expand All @@ -93,6 +102,7 @@ def callback(self) -> Callable:
"pascalCase": text.pascal_case,
"camelCase": text.camel_case,
"snakeCase": text.snake_case,
"screamingSnakeCase": text.screaming_snake_case,
"mixedCase": text.mixed_case,
"mixedSnakeCase": text.mixed_snake_case,
"mixedPascalCase": text.mixed_pascal_case,
Expand Down Expand Up @@ -174,6 +184,9 @@ class GeneratorConventions:
field_name: NameConvention = element(
default_factory=lambda: NameConvention(NameCase.SNAKE, "value")
)
constant_name: NameConvention = element(
default_factory=lambda: NameConvention(NameCase.SCREAMING_SNAKE, "value")
)
module_name: NameConvention = element(
default_factory=lambda: NameConvention(NameCase.SNAKE, "mod")
)
Expand Down
5 changes: 5 additions & 0 deletions xsdata/utils/text.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ def snake_case(string: str, **kwargs: Any) -> str:
return "_".join(map(str.lower, split_words(string)))


def screaming_snake_case(string: str, **kwargs: Any) -> str:
"""Convert the given string to screaming snake case."""
return snake_case(string, **kwargs).upper()


def kebab_case(string: str, **kwargs: Any) -> str:
"""Convert the given string to kebab case."""
return "-".join(split_words(string))
Expand Down

0 comments on commit 4455be9

Please sign in to comment.