diff --git a/jsonschema_gentypes/__init__.py b/jsonschema_gentypes/__init__.py index fbd8f849..fd6ae201 100644 --- a/jsonschema_gentypes/__init__.py +++ b/jsonschema_gentypes/__init__.py @@ -3,6 +3,7 @@ """ import keyword +import random import re import textwrap import unicodedata @@ -375,6 +376,10 @@ def imports(self, python_version: tuple[int, ...]) -> list[tuple[str, str]]: return [(self.workaround_package, self._name)] return [(self.package, self._name)] + def __repr__(self) -> str: + """Get the representation of the object.""" + return f"NativeType({self.package!r}.{self._name!r})" + class CombinedType(Type): """ @@ -479,6 +484,7 @@ def __init__(self, name: str, values: list[Union[int, float, bool, str, None]], assert len(values) > 0 super().__init__(name) self.values = values + self.value_names = {value: get_name({"title": f"{name} {value}"}, upper=True) for value in values} self.descriptions = descriptions self.sub_type: Type = CombinedType(NativeType("Union"), [LiteralType(value) for value in values]) @@ -500,7 +506,7 @@ def definition(self, line_length: Optional[int] = None) -> list[str]: elif comments: result += ['"""', *comments, '"""'] for value in self.values: - name = get_name({"title": f"{self._name} {value}"}, upper=True) + name = self.value_names[value] formatted_value = f'"{value}"' if isinstance(value, str) else str(value) result.append(f"{name}: {LiteralType(value).name()} = {formatted_value}") name = self.descriptions[0] if self.descriptions else self._name @@ -688,6 +694,7 @@ def get_name( proposed_name: Optional[str] = None, upper: bool = False, get_name_properties: Optional[str] = None, + postfix: Optional[str] = None, ) -> str: """ Get the name for an element. @@ -704,21 +711,30 @@ def get_name( name = normalize(name) prefix = "" if has_title else "_" + rand = str(random.randint(0, 9999)) if name != "Root" else "" # nosec if upper: # Upper case name = name.upper() # Remove spaces - return prefix + "".join(["_" if char.isspace() else char for char in name]) + output = prefix + "".join(["_" if char.isspace() else char for char in name]) elif get_name_properties == "UpperFirst": # Change just the first letter to upper case name = name[0].upper() + name[1:] # Remove spaces - return prefix + "".join([char for char in name if not char.isspace()]) + output = prefix + "".join([char for char in name if not char.isspace()]) else: # Title case name = name.title() # Remove spaces - return prefix + "".join([char for char in name if not char.isspace()]) + output = prefix + "".join([char for char in name if not char.isspace()]) + if postfix: + output += postfix + if not get_name.__dict__.get("names"): + get_name.__dict__["names"] = set() + elif output in get_name.__dict__["names"]: + output += rand + get_name.__dict__["names"].add(output) + return output def get_description( diff --git a/jsonschema_gentypes/api.py b/jsonschema_gentypes/api.py index 2ab6080c..83288243 100644 --- a/jsonschema_gentypes/api.py +++ b/jsonschema_gentypes/api.py @@ -170,8 +170,13 @@ def get_type( description.append("") description += additional_description if description: - if not isinstance(the_type, NamedType): - if auto_alias: + if auto_alias: + alias = True + if isinstance(the_type, NamedType): + alias = False + elif isinstance(the_type, CombinedType): + alias = not isinstance(the_type.base, NamedType) + if alias: the_type = TypeAlias( self.get_name(schema_meta_data, proposed_name), the_type, description ) @@ -205,8 +210,9 @@ def get_name( ], proposed_name: Optional[str] = None, upper: bool = False, + postfix: Optional[str] = None, ) -> str: - return get_name(schema, proposed_name, upper, self.get_name_properties) + return get_name(schema, proposed_name, upper, self.get_name_properties, postfix=postfix) def resolve_ref( self, diff --git a/jsonschema_gentypes/api_draft_04.py b/jsonschema_gentypes/api_draft_04.py index fa1355d9..330b726a 100644 --- a/jsonschema_gentypes/api_draft_04.py +++ b/jsonschema_gentypes/api_draft_04.py @@ -99,7 +99,7 @@ def object( ) std_dict = None - name = self.get_name(schema_meta_data, proposed_name) + schema.setdefault("used", set()).add("additionalProperties") # type: ignore[typeddict-item] additional_properties = cast( Union[jsonschema_draft_04.JSONSchemaD4, jsonschema_draft_2020_12_applicator.JSONSchemaD2020], @@ -150,8 +150,11 @@ def object( for prop, sub_schema in properties.items() } + name = self.get_name( + schema_meta_data, proposed_name, postfix="Typed" if std_dict is not None else "" + ) type_: Type = TypedDictType( - name if std_dict is None else name + "Typed", + name, struct, get_description(schema_meta_data) if std_dict is None else [], required=required, diff --git a/tests/get_name_properties.py b/tests/get_name_properties.py index c8ba70d9..0bc12669 100644 --- a/tests/get_name_properties.py +++ b/tests/get_name_properties.py @@ -1,6 +1,4 @@ -from typing import TypedDict - -from typing_extensions import Required +from typing import Required, TypedDict class ResponseType(TypedDict, total=False): diff --git a/tests/openapi3.py b/tests/openapi3.py index e47693da..96534692 100644 --- a/tests/openapi3.py +++ b/tests/openapi3.py @@ -73,9 +73,9 @@ class OgcapiCollectionsCollectionidGetQuery(TypedDict, total=False): OgcapiCollectionsCollectionidGetQueryF = Union[Literal["json"], Literal["html"]] -OGCAPICOLLECTIONSCOLLECTIONIDGETQUERYF_JSON: Literal["json"] = "json" +_OGCAPICOLLECTIONSCOLLECTIONIDGETQUERYF_JSON: Literal["json"] = "json" """The values for the 'OgcapiCollectionsCollectionidGetQueryF' enum""" -OGCAPICOLLECTIONSCOLLECTIONIDGETQUERYF_HTML: Literal["html"] = "html" +_OGCAPICOLLECTIONSCOLLECTIONIDGETQUERYF_HTML: Literal["html"] = "html" """The values for the 'OgcapiCollectionsCollectionidGetQueryF' enum""" diff --git a/tests/test_test.py b/tests/test_test.py index 5e1498ae..2ef61209 100644 --- a/tests/test_test.py +++ b/tests/test_test.py @@ -8,18 +8,21 @@ def get_types(schema) -> Type: + jsonschema_gentypes.get_name.__dict__.setdefault("names", set()).clear() resolver = jsonschema_gentypes.resolver.RefResolver("https://example.com/fake", schema) api = jsonschema_gentypes.api_draft_07.APIv7(resolver) return api.get_type(schema, "Base") def get_types_2019_09(schema) -> Type: + jsonschema_gentypes.get_name.__dict__.setdefault("names", set()).clear() resolver = jsonschema_gentypes.resolver.RefResolver("https://example.com/fake", schema) api = jsonschema_gentypes.api_draft_2019_09.APIv201909(resolver) return api.get_type(schema, "Base") def get_types_2020_12(schema) -> Type: + jsonschema_gentypes.get_name.__dict__.setdefault("names", set()).clear() resolver = jsonschema_gentypes.resolver.RefResolver("https://example.com/fake", schema) api = jsonschema_gentypes.api_draft_2020_12.APIv202012(resolver) return api.get_type(schema, "Base") @@ -459,7 +462,7 @@ class TestBasicTypes(TypedDict, total=False): ) -def test_enum(): +def test_dict_enum(): type_ = get_types( { "type": "object", @@ -472,26 +475,37 @@ def test_enum(): ) assert ( "\n".join([d.rstrip() for d in type_.definition(None)]) - == f''' + == ''' -""" -test basic types. -""" -TestBasicTypes = TypedDict('TestBasicTypes', { - 'enum': "_TestBasicTypesEnum", -}, total=False) """ +class TestBasicTypes(TypedDict, total=False): + """ test basic types. """ + + enum: Required["Properties"] + """ + properties. + + Required property + """ ''' ) assert len(type_.depends_on()) == 2 + enum_type = type_.depends_on()[1] + assert len(enum_type.depends_on()) == 2 + enum_type = enum_type.depends_on()[1] assert ( - "\n".join([d.rstrip() for d in type_.depends_on()[1].definition(None)]) + "\n".join([d.rstrip() for d in enum_type.definition(None)]) == ''' -class _TestBasicTypesEnum(Enum): - RED = "red" - AMBER = "amber" - GREEN = "green"''' +Properties = Union[Literal['red'], Literal['amber'], Literal['green']] +""" properties. """ +PROPERTIES_RED: Literal['red'] = "red" +"""The values for the 'properties' enum""" +PROPERTIES_AMBER: Literal['amber'] = "amber" +"""The values for the 'properties' enum""" +PROPERTIES_GREEN: Literal['green'] = "green" +"""The values for the 'properties' enum""" +''' ) @@ -971,10 +985,12 @@ def test_linesplit() -> None: ], ) def test_name(config, title, expected): + jsonschema_gentypes.get_name.__dict__.setdefault("names", set()).clear() assert jsonschema_gentypes.get_name(config, title) == expected def test_name_upper(): + jsonschema_gentypes.get_name.__dict__.setdefault("names", set()).clear() assert jsonschema_gentypes.get_name({"title": "test"}, upper=True) == "TEST"