diff --git a/api_generator/api_generator/config.py b/api_generator/api_generator/config.py index 20080b56b..f40e4a49b 100644 --- a/api_generator/api_generator/config.py +++ b/api_generator/api_generator/config.py @@ -10,11 +10,6 @@ class Platform(str, Enum): WEB = 'web' -class DescriptionLanguage(str, Enum): - EN = 'en' - RU = 'ru' - - class GeneratedLanguage(str, Enum): SWIFT = 'swift' KOTLIN = 'kotlin' diff --git a/api_generator/api_generator/generator.py b/api_generator/api_generator/generator.py index 830d71ff9..151aeeac4 100644 --- a/api_generator/api_generator/generator.py +++ b/api_generator/api_generator/generator.py @@ -1,7 +1,14 @@ from .config import Config, GeneratedLanguage from .schema.preprocessing import schema_preprocessing from .schema.modeling import build_objects -from .generators import Generator, SwiftGenerator, KotlinGenerator, DocumentationGenerator, TypeScriptGenerator +from .generators import ( + Generator, + SwiftGenerator, + KotlinGenerator, + DocumentationGenerator, + TypeScriptGenerator, + PythonGenerator, +) def __build_generator(config: Config) -> Generator: @@ -11,6 +18,7 @@ def __build_generator(config: Config) -> Generator: GeneratedLanguage.KOTLIN: KotlinGenerator, GeneratedLanguage.DOCUMENTATION: DocumentationGenerator, GeneratedLanguage.TYPE_SCRIPT: TypeScriptGenerator, + GeneratedLanguage.PYTHON: PythonGenerator, } generator = generator_dict.get(lang, None) if generator is None: diff --git a/api_generator/api_generator/generators/__init__.py b/api_generator/api_generator/generators/__init__.py index 091921fc4..06fb1baf5 100644 --- a/api_generator/api_generator/generators/__init__.py +++ b/api_generator/api_generator/generators/__init__.py @@ -3,5 +3,6 @@ from .swift import SwiftGenerator from .kotlin import KotlinGenerator from .documentation import DocumentationGenerator from .type_script import TypeScriptGenerator +from .python import PythonGenerator -__all__ = [Generator, SwiftGenerator, KotlinGenerator, DocumentationGenerator, TypeScriptGenerator] +__all__ = [Generator, SwiftGenerator, KotlinGenerator, DocumentationGenerator, TypeScriptGenerator, PythonGenerator] diff --git a/api_generator/api_generator/generators/base.py b/api_generator/api_generator/generators/base.py index efc1e799a..e30adfa67 100644 --- a/api_generator/api_generator/generators/base.py +++ b/api_generator/api_generator/generators/base.py @@ -65,12 +65,12 @@ class Generator(ABC): def _generate_files(self, objects: List[Declarable]): for obj in objects: declaration = [] - for line in str(self._main_declaration(obj)).strip().split('\n'): + for line in str(self._main_declaration(obj)).rstrip().split('\n'): if line.isspace(): declaration.append('') else: declaration.append(line) - declaration = '\n'.join(declaration).strip() + declaration = '\n'.join(declaration) if not declaration: continue head_for_file = self._head_for_file + '\n' if self._head_for_file.strip() else '' diff --git a/api_generator/api_generator/generators/documentation/generator.py b/api_generator/api_generator/generators/documentation/generator.py index 1241358b9..8601aab86 100644 --- a/api_generator/api_generator/generators/documentation/generator.py +++ b/api_generator/api_generator/generators/documentation/generator.py @@ -11,13 +11,14 @@ from .documentation_entities import ( from .translations import translations from .utils import bold, code, paragraph from ..base import Generator -from ...config import Config, Platform, DescriptionLanguage +from ...config import Config, Platform from ...schema.modeling.entities import ( Declarable, Entity, EntityEnumeration, StringEnumeration, - Property + Property, + DescriptionLanguage ) from ...schema.modeling.text import Text diff --git a/api_generator/api_generator/generators/documentation/translations.py b/api_generator/api_generator/generators/documentation/translations.py index 03493fb45..01ee82e2e 100644 --- a/api_generator/api_generator/generators/documentation/translations.py +++ b/api_generator/api_generator/generators/documentation/translations.py @@ -1,5 +1,5 @@ from typing import Dict -from ...config import DescriptionLanguage +from ...schema.modeling.entities import DescriptionLanguage __full_translations: Dict[str, Dict[str, str]] = { "div_generator_android": { diff --git a/api_generator/api_generator/generators/python/__init__.py b/api_generator/api_generator/generators/python/__init__.py new file mode 100644 index 000000000..65530a5ef --- /dev/null +++ b/api_generator/api_generator/generators/python/__init__.py @@ -0,0 +1,3 @@ +from .generator import PythonGenerator + +__all__ = [PythonGenerator] diff --git a/api_generator/api_generator/generators/python/generator.py b/api_generator/api_generator/generators/python/generator.py new file mode 100644 index 000000000..39403f930 --- /dev/null +++ b/api_generator/api_generator/generators/python/generator.py @@ -0,0 +1,229 @@ +from typing import cast, List + +from .python_entities import ( + update_base, + as_python_commentary, + _make_python_imports, + _python_full_name, + PythonEntity, + PythonProperty +) +from ..base import Generator +from ...schema.modeling.text import Text, EMPTY +from ...schema.modeling.entities import ( + StringEnumeration, + EntityEnumeration, + Entity, + Declarable, +) +from ... import utils + + +class PythonGenerator(Generator): + def _filename(self, name: str) -> str: + return f'{utils.snake_case(name)}.py' + + def generate(self, objects: List[Declarable]): + objects_py: List[Declarable] = list(map(lambda obj: update_base(obj), objects)) + super(PythonGenerator, self).generate(objects_py) + self.__generate_package_file(objects_py) + + def __generate_package_file(self, objects: List[Declarable]): + file_content = Text('# Generated code. Do not modify.') + file_content += EMPTY + + def sort_key(d: Declarable): + return d.name + uniqs = [] + for obj in sorted(objects, key=sort_key): + uniqs.append(utils.capitalize_camel_case(obj.name)) + if isinstance(obj, PythonEntity): + uniqs.extend(self.__inner_types_classes(obj)) + + if len(uniqs) > len(list(set(uniqs))): + raise ValueError('Inner type classes not uniqs') + + for obj in sorted(objects, key=sort_key): + imports = [utils.capitalize_camel_case(obj.name)] + if isinstance(obj, PythonEntity): + imports += self.__inner_types_classes(obj) + imports = ', '.join(imports) + file_content += f'from .{utils.snake_case(obj.name)} import {imports}' + + file_content += EMPTY + with_inners = [] + for obj in sorted(objects, key=sort_key): + if isinstance(obj, PythonEntity): + with_inners.append(utils.capitalize_camel_case(obj.name)) + with_inners += self.__inner_entity_classes(obj) + + for e in with_inners: + file_content += f'{e}.update_forward_refs()' + + file_content += EMPTY + + with open(f'{self._config.output_path}/__init__.py', 'w') as file: + file.write(str(file_content)) + + def __inner_types_classes(self, entity: PythonEntity) -> List[str]: + def declaration_of(decl_type, method) -> List[str]: + def sort_predicate(d: Declarable): + return d.name + classes = [] + inner_types = sorted(filter(lambda t: isinstance(t, decl_type), entity.inner_types), key=sort_predicate) + for inner_type in inner_types: + if isinstance(inner_type, decl_type): + classes += method(inner_type) + return classes + + result = [] + + result.extend(declaration_of(StringEnumeration, lambda str_enum: [_python_full_name(str_enum)])) + result.extend(declaration_of(EntityEnumeration, lambda ent_enum: [_python_full_name(ent_enum)])) + result.extend(declaration_of(Entity, lambda ent: [_python_full_name(ent)] + self.__inner_types_classes(ent))) + + return result + + def __inner_entity_classes(self, entity: PythonEntity) -> List[str]: + result = [] + def sort_predicate(d: Declarable): + return d.name + + for inner_type in sorted(entity.inner_types, key=sort_predicate): + if isinstance(inner_type, PythonEntity): + result.append(_python_full_name(inner_type)) + result += self.__inner_entity_classes(inner_type) + return result + + def _entity_declaration(self, entity: PythonEntity) -> Text: + result = Text() + imports = entity.imports + if imports is not None: + result += imports + result += EMPTY + result += EMPTY + result += self.__entity_declaration_without_imports(entity) + return result + + def __entity_declaration_without_imports(self, entity: PythonEntity) -> Text: + result = Text() + description = entity.description_doc() + if description.strip(): + result += as_python_commentary(description) + py_full_name = _python_full_name(entity) + result += f'class {py_full_name}(BaseDiv):' + result += EMPTY + result += entity.generate_init(filename=utils.snake_case(py_full_name)).indented(indent_width=4) + if entity.should_generate_as_python_class: + declaration = entity.class_properties_declaration + else: + declaration = entity.dynamic_properties_declaration + if declaration.lines: + result += EMPTY + result += declaration + + inner_types_declaration = self.__inner_types_declaration(entity) + if inner_types_declaration.lines: + result += EMPTY + result += EMPTY + result += inner_types_declaration + + result += EMPTY + result += EMPTY + result += f'{py_full_name}.update_forward_refs()' + return result + + def __inner_entity_declaration_without_imports(self, entity: PythonEntity, filename: str) -> Text: + result = Text() + description = entity.description_doc() + if description: + result += as_python_commentary(description) + py_full_name = _python_full_name(entity) + result += f'class {py_full_name}(BaseDiv):' + result += EMPTY + result += entity.generate_init(filename).indented(indent_width=4) + + if entity.should_generate_as_python_class: + declaration = entity.class_properties_declaration + else: + declaration = Text() + for p in cast(List[PythonProperty], entity.instance_properties): + declaration += p.make_declaration(filename).indented(indent_width=4) + if declaration.lines: + result += EMPTY + result += declaration + + inner_types_declaration = self.__inner_types_declaration(entity) + if inner_types_declaration.lines: + result += EMPTY + result += EMPTY + result += inner_types_declaration + + result += EMPTY + result += EMPTY + result += f'{py_full_name}.update_forward_refs()' + return result + + def __inner_types_declaration(self, entity: PythonEntity) -> Text: + def declaration_of(decl_type, decl_method) -> Text: + def sort_predicate(d: Declarable): + return d.name + inner_types_decl = Text() + inner_types = sorted(filter(lambda t: isinstance(t, decl_type), entity.inner_types), key=sort_predicate) + for ind, inner_type in enumerate(inner_types): + inner_types_decl += decl_method(inner_type) + if ind != (len(inner_types) - 1): + inner_types_decl += EMPTY + inner_types_decl += EMPTY + return inner_types_decl + + declarations = [declaration_of(StringEnumeration, self._string_enumeration_declaration), + declaration_of(EntityEnumeration, self.__entity_enumeration_declaration_without_imports), + declaration_of(Entity, + lambda prop: self.__inner_entity_declaration_without_imports( + prop, + utils.snake_case(_python_full_name(entity)) + )) + ] + result = Text() + declarations = list(filter(lambda d: d.lines, declarations)) + for ind, decl in enumerate(declarations): + result += decl + if ind != (len(declarations) - 1): + result += EMPTY + result += EMPTY + return result + + def _entity_enumeration_declaration(self, entity_enumeration: EntityEnumeration) -> Text: + result = Text() + imports = sorted(list(filter(None, + map( + lambda e: _python_full_name(e[1]) if e[1] is not None else None, + entity_enumeration.entities + )))) + imports = _make_python_imports(items=imports) + if imports != EMPTY: + result += imports + result += EMPTY + result += self.__entity_enumeration_declaration_without_imports(entity_enumeration) + return result + + @staticmethod + def __entity_enumeration_declaration_without_imports(entity_enumeration: EntityEnumeration) -> Text: + result = Text() + result += 'from typing import Union' + result += EMPTY + result += f'{_python_full_name(entity_enumeration)} = Union[' + entities = list(filter(None, map(lambda e: e[1], entity_enumeration.entities))) + for e in entities: + full_name = _python_full_name(e) + result += Text(f'{utils.snake_case(full_name)}.{full_name},').indented(indent_width=4) + result += ']' + return result + + def _string_enumeration_declaration(self, string_enumeration: StringEnumeration) -> Text: + result = Text() + result += f'class {_python_full_name(string_enumeration)}(str, enum.Enum):' + for _, value in string_enumeration.cases: + result += Text(f"{utils.upper_snake_case(value)} = '{value}'").indented(indent_width=4) + return result diff --git a/api_generator/api_generator/generators/python/python_entities.py b/api_generator/api_generator/generators/python/python_entities.py new file mode 100644 index 000000000..fc0937e73 --- /dev/null +++ b/api_generator/api_generator/generators/python/python_entities.py @@ -0,0 +1,355 @@ +from __future__ import annotations +from typing import List, Optional, cast + +from ...schema.modeling.entities import ( + Declarable, + PropertyType, + Property, + Entity, + Array, + Bool, + BoolInt, + Color, + Dictionary, + Double, + Int, + Object, + StaticString, + String, + Url +) +from ... import utils +from ...schema.modeling.text import Text, EMPTY + + +def update_base(obj: Declarable) -> Declarable: + if isinstance(obj, Entity): + obj.__class__ = PythonEntity + cast(PythonEntity, obj).update_base() + return obj + + +def update_property_type_base(property_type: PropertyType): + if isinstance(property_type, Array): + property_type.__class__ = PythonArray + cast(PythonArray, property_type).update_base() + elif isinstance(property_type, Bool): + property_type.__class__ = PythonBool + elif isinstance(property_type, BoolInt): + property_type.__class__ = PythonBoolInt + elif isinstance(property_type, Color): + property_type.__class__ = PythonColor + elif isinstance(property_type, Dictionary): + property_type.__class__ = PythonDictionary + elif isinstance(property_type, Double): + property_type.__class__ = PythonDouble + elif isinstance(property_type, Int): + property_type.__class__ = PythonInt + elif isinstance(property_type, Object): + property_type.__class__ = PythonObject + cast(PythonObject, property_type).update_base() + elif isinstance(property_type, StaticString): + property_type.__class__ = PythonStaticString + elif isinstance(property_type, String): + property_type.__class__ = PythonString + elif isinstance(property_type, Url): + property_type.__class__ = PythonUrl + else: + raise NotImplementedError + + +def _python_full_name(obj: Declarable) -> str: + full_name = utils.capitalize_camel_case(obj.name) + if obj.parent is not None: + full_name = utils.capitalize_camel_case(obj.parent.name) + full_name + return full_name + + +def _make_python_imports(items: List[str]) -> Text: + if not items: + return EMPTY + result = Text() + for item in items: + result += f'from . import {utils.snake_case(item)}' + return result + + +def as_python_commentary(s: str) -> Optional[Text]: + result = Text() + words = s.replace('
  • ', '').replace('
  • ', '').split(' ') + line = '' + for word in words: + if not line: + line = str(word) + elif (len(line) + len(word)) > 80: + result += f'# {line}' + line = str(word) + else: + line += f' {word}' + result += f'# {line}' + return result + + +class PythonEntity(Entity): + def update_base(self): + for prop in self.properties: + prop.__class__ = PythonProperty + cast(PythonProperty, prop).update_base() + for inner_type in self.inner_types: + update_base(inner_type) + + @property + def static_properties(self) -> List[Property]: + return list(filter(lambda p: isinstance(p.property_type, StaticString), self.properties)) + + @property + def referenced_top_level_types(self) -> List[str]: + return list(filter(None, map(lambda p: p.property_type_py.referenced_top_level_type_name, self.properties))) + + @property + def imports(self) -> Optional[Text]: + types = self.referenced_top_level_types + for inner_type in self.inner_types: + if isinstance(inner_type, PythonEntity): + types += inner_type.referenced_top_level_types + python_full_name = _python_full_name(self) + unique_types = list(filter(lambda t: t != python_full_name, set(types))) + return None if not unique_types else _make_python_imports(sorted(unique_types)) + + def generate_init(self, filename: str) -> Text: + main_required = ['self', '*'] + required = [] + static_properties = self.static_properties + instance_properties = self.instance_properties + optional = list(map(lambda p: f'{p.escaped_name}: str = {p.static_value}', static_properties)) + for p in cast(List[PythonProperty], instance_properties): + if p.optional: + optional.append(f'{p.escaped_name}: typing.Optional[{p.property_type_py.type_name(filename)}] = None') + else: + required.append(f'{p.escaped_name}: {p.property_type_py.type_name(filename)}') + result = Text() + result += 'def __init__(' + result += Text(', '.join(main_required) + ',').indented(indent_width=4) + for p in required + optional: + result += Text(p + ',').indented(indent_width=4) + result += '):' + super_init = Text('super().__init__(') + for p in cast(List[PythonProperty], static_properties + instance_properties): + escaped_name = p.escaped_name + super_init += Text(f'{escaped_name}={escaped_name},').indented(indent_width=4) + super_init += ')' + result += super_init.indented(indent_width=4) + return result + + @property + def should_generate_as_python_class(self) -> bool: + return len(self.static_properties) != 0 + + @property + def class_properties_declaration(self) -> Text: + result = Text() + for p in cast(List[PythonProperty], self.static_properties): + field = f'default={p.static_value}' + commentary = p.commentary + if commentary is not None: + commentary = ' '.join(commentary.lines).replace('\n', '').replace('# ', '').replace("'", "\\'") + field += f", description='{commentary}'" + result += Text(f'{p.escaped_name}: str = Field({field})').indented(indent_width=4) + dynamic_declaration = self.dynamic_properties_declaration + if dynamic_declaration.lines: + result += dynamic_declaration + return result + + @property + def dynamic_properties_declaration(self) -> Text: + result = Text() + py_filename = _python_full_name(self) + props = cast(List[PythonProperty], self.instance_properties) + for ind, p in enumerate(props): + result += p.make_declaration(filename=py_filename).indented(indent_width=4) + return result + + +class PythonProperty(Property): + def update_base(self): + update_property_type_base(self.property_type) + + @property + def escaped_name(self) -> str: + return utils.snake_case(self.name) + + @property + def property_type_py(self) -> PythonPropertyType: + return cast(PythonPropertyType, self.property_type) + + def constructor_required_value(self, filename: str) -> Optional[str]: + if self.optional: + return None + return f'{self.escaped_name}: {self.property_type_py.type_name(filename)}' + + def constructor_optional_value(self, filename: str) -> Optional[str]: + if not self.optional: + return None + return f'{self.escaped_name}: typing.Optional[{self.property_type_py.type_name(filename)}] = None' + + @property + def static_value(self) -> str: + if isinstance(self.property_type, StaticString): + return f"'{self.property_type.value}'" + else: + raise TypeError(f'{self.property_type} is not a static type') + + @property + def commentary(self) -> Optional[Text]: + result = Text() + description = self.description_doc() + if description: + result += as_python_commentary(description) + if self.is_deprecated: + result += '@deprecated' + if result.lines: + return result + return None + + def make_declaration(self, filename: str) -> Text: + fields: List[str] = [] + + constraints = self.property_type_py.constraints + if constraints: + fields.append(constraints) + + commentary = self.commentary + if commentary is not None: + commentary = ' '.join(commentary.lines).replace('\n', '').replace('# ', '').replace("'", "\\'") + fields.append(f"description='{commentary}'") + + if utils.snake_case(self.name) != self.name: + fields.append(f"name='{self.name}'") + + if self.optional: + prefix = 'typing.Optional[' + suffix = ']' + else: + prefix = '' + suffix = '' + type_decl = f'{prefix}{self.property_type_py.type_name(filename)}{suffix}' + + return Text(f'{self.escaped_name}: {type_decl} = Field({", ".join(fields)})') + + +class PythonPropertyType(PropertyType): + @property + def referenced_top_level_type_name(self) -> Optional[str]: + if isinstance(self, Object): + obj = self.object + if obj is not None and obj.parent is None: + return _python_full_name(obj) + return None + elif isinstance(self, PythonArray): + return self.property_type_py.referenced_top_level_type_name + return None + + def type_name(self, filename: str) -> str: + if isinstance(self, Int): + return 'int' + elif isinstance(self, Double): + return 'float' + elif isinstance(self, (Bool, BoolInt)): + return 'bool' + elif isinstance(self, (Color, String, Url)): + return 'str' + elif isinstance(self, StaticString): + raise TypeError(f'{self} is a static type') + elif isinstance(self, Dictionary): + return 'typing.Dict[str, typing.Any]' + elif isinstance(self, PythonArray): + return f'typing.List[{self.property_type_py.type_name(filename)}]' + elif isinstance(self, Object): + if self.object is None: + raise ValueError(f'Invalid {self}') + obj = self.object + if utils.snake_case(filename) == utils.snake_case(_python_full_name(obj)) or \ + obj.parent is not None: + return _python_full_name(obj) + py_full_name = _python_full_name(obj) + return f'{utils.snake_case(py_full_name)}.{py_full_name}' + + @property + def constraints(self) -> str: + if isinstance(self, (Bool, BoolInt, Dictionary)): + return '' + elif isinstance(self, Array): + result = '' + if self.min_items > 0: + result += f'min_items={self.min_items}' + return result + elif isinstance(self, Color): + return 'format="color"' + elif isinstance(self, (Double, Int)): + return '' + elif isinstance(self, Object): + return '' + elif isinstance(self, StaticString): + return '' + elif isinstance(self, Url): + return 'format="uri"' + elif isinstance(self, String): + result = '' + if self.min_length > 0: + result += f'min_length={self.min_length}' + return result + else: + raise TypeError + + +class PythonArray(PythonPropertyType, Array): + def update_base(self): + if not isinstance(self.property_type, PythonPropertyType): + update_property_type_base(self.property_type) + + @property + def property_type_py(self) -> PythonPropertyType: + return cast(PythonPropertyType, self.property_type) + + +class PythonBool(PythonPropertyType, Bool): + pass + + +class PythonBoolInt(PythonPropertyType, BoolInt): + pass + + +class PythonColor(PythonPropertyType, Color): + pass + + +class PythonDictionary(PythonPropertyType, Dictionary): + pass + + +class PythonDouble(PythonPropertyType, Double): + pass + + +class PythonInt(PythonPropertyType, Int): + pass + + +class PythonObject(PythonPropertyType, Object): + def update_base(self): + if isinstance(self.object, Entity): + self.object.__class__ = PythonEntity + cast(PythonEntity, self.object).update_base() + + +class PythonStaticString(PythonPropertyType, StaticString): + pass + + +class PythonString(PythonPropertyType, String): + pass + + +class PythonUrl(PythonPropertyType, Url): + pass diff --git a/api_generator/api_generator/generators/type_script/generator.py b/api_generator/api_generator/generators/type_script/generator.py index 856224336..9516dba0e 100644 --- a/api_generator/api_generator/generators/type_script/generator.py +++ b/api_generator/api_generator/generators/type_script/generator.py @@ -59,7 +59,7 @@ class TypeScriptGenerator(Generator): return d.name inner_types_decl = Text() inner_types = sorted(filter(lambda t: isinstance(t, decl_type), entity.inner_types), key=sort_predicate) - for ind, p in enumerate(inner_types): + for p in inner_types: if isinstance(p, decl_type): inner_types_decl += decl_method(p) inner_types_decl += EMPTY diff --git a/api_generator/api_generator/schema/modeling/entities.py b/api_generator/api_generator/schema/modeling/entities.py index 25e6e901a..80feb0de9 100644 --- a/api_generator/api_generator/schema/modeling/entities.py +++ b/api_generator/api_generator/schema/modeling/entities.py @@ -10,12 +10,11 @@ import re from ..utils import is_dict_with_keys_of_type, is_list_of_type from .utils import ( alias, - fixing_reserved_typename, - description_doc + fixing_reserved_typename ) from ...utils import capitalize_camel_case -from ...config import Config, GeneratedLanguage, GenerationMode, Platform, TEMPLATE_SUFFIX, DescriptionLanguage +from ...config import Config, GeneratedLanguage, GenerationMode, Platform, TEMPLATE_SUFFIX from ..preprocessing.entities import ElementLocation from ..preprocessing.errors import UnresolvedReferenceError from .errors import GenericError, InvalidFieldRepresentationError @@ -23,6 +22,18 @@ from .errors import GenericError, InvalidFieldRepresentationError from . import builders +class DescriptionLanguage(str, Enum): + EN = 'en' + RU = 'ru' + + +def description_doc(description_translations: Dict[str, str], lang: DescriptionLanguage, description: str) -> str: + try: + return description_translations[lang.value] + except KeyError: + return description + + class Declarable(ABC): def __init__(self) -> None: self._parent: Optional[Declarable] = None diff --git a/api_generator/api_generator/schema/modeling/utils.py b/api_generator/api_generator/schema/modeling/utils.py index 9d46a4136..f5282ba9c 100644 --- a/api_generator/api_generator/schema/modeling/utils.py +++ b/api_generator/api_generator/schema/modeling/utils.py @@ -1,6 +1,6 @@ from typing import Dict, Optional, List -from ...config import GeneratedLanguage, Platform, DescriptionLanguage +from ...config import GeneratedLanguage, Platform from ..utils import get_value_with_optional_by_lang @@ -24,10 +24,3 @@ def platforms(dictionary: Dict[str, any]) -> Optional[List[Platform]]: if platforms_list is None: return None return list(map(lambda raw: Platform[raw.upper()], platforms_list)) - - -def description_doc(description_translations: Dict[str, str], lang: DescriptionLanguage, description: str) -> str: - try: - return description_translations[lang.value] - except KeyError: - return description diff --git a/api_generator/api_generator/utils.py b/api_generator/api_generator/utils.py index ca3bf6233..6df876a4e 100644 --- a/api_generator/api_generator/utils.py +++ b/api_generator/api_generator/utils.py @@ -28,6 +28,14 @@ def capitalize_camel_case(string: str) -> str: return ''.join(map(lambda component: component.capitalize(), name_components(string))) +def snake_case(string: str) -> str: + return '_'.join(map(lambda component: component.lower(), filter(lambda s: s, name_components(string)))) + + +def upper_snake_case(string: str) -> str: + return '_'.join(map(lambda component: component.upper(), filter(lambda s: s, name_components(string)))) + + def lower_camel_case(string: str) -> str: components = name_components(string) if not components: diff --git a/api_generator/tests/configs/python_config.json b/api_generator/tests/configs/python_config.json new file mode 100644 index 000000000..2faf5f91e --- /dev/null +++ b/api_generator/tests/configs/python_config.json @@ -0,0 +1,4 @@ +{ + "lang": "python", + "header": "# Generated code. Do not modify.\n\nfrom __future__ import annotations\nfrom pydivkit.core import BaseDiv, Field\nimport enum\nimport typing\n" +} diff --git a/api_generator/tests/references/python/__init__.py b/api_generator/tests/references/python/__init__.py new file mode 100644 index 000000000..73b237272 --- /dev/null +++ b/api_generator/tests/references/python/__init__.py @@ -0,0 +1,43 @@ +# Generated code. Do not modify. + +from .entity import Entity +from .entity_with_array import EntityWithArray +from .entity_with_array_of_nested_items import EntityWithArrayOfNestedItems, EntityWithArrayOfNestedItemsItem +from .entity_with_array_with_transform import EntityWithArrayWithTransform +from .entity_with_complex_property import EntityWithComplexProperty, EntityWithComplexPropertyProperty +from .entity_with_complex_property_with_default_value import EntityWithComplexPropertyWithDefaultValue, EntityWithComplexPropertyWithDefaultValueProperty +from .entity_with_entity_property import EntityWithEntityProperty +from .entity_with_optional_complex_property import EntityWithOptionalComplexProperty, EntityWithOptionalComplexPropertyProperty +from .entity_with_optional_property import EntityWithOptionalProperty +from .entity_with_optional_string_enum_property import EntityWithOptionalStringEnumProperty, EntityWithOptionalStringEnumPropertyProperty +from .entity_with_property_with_default_value import EntityWithPropertyWithDefaultValue, EntityWithPropertyWithDefaultValueNested +from .entity_with_required_property import EntityWithRequiredProperty +from .entity_with_simple_properties import EntityWithSimpleProperties +from .entity_with_strict_array import EntityWithStrictArray +from .entity_with_string_array_property import EntityWithStringArrayProperty +from .entity_with_string_enum_property import EntityWithStringEnumProperty, EntityWithStringEnumPropertyProperty +from .entity_with_string_enum_property_with_default_value import EntityWithStringEnumPropertyWithDefaultValue, EntityWithStringEnumPropertyWithDefaultValueValue +from .entity_without_properties import EntityWithoutProperties + +EntityWithArray.update_forward_refs() +EntityWithArrayOfNestedItems.update_forward_refs() +EntityWithArrayOfNestedItemsItem.update_forward_refs() +EntityWithArrayWithTransform.update_forward_refs() +EntityWithComplexProperty.update_forward_refs() +EntityWithComplexPropertyProperty.update_forward_refs() +EntityWithComplexPropertyWithDefaultValue.update_forward_refs() +EntityWithComplexPropertyWithDefaultValueProperty.update_forward_refs() +EntityWithEntityProperty.update_forward_refs() +EntityWithOptionalComplexProperty.update_forward_refs() +EntityWithOptionalComplexPropertyProperty.update_forward_refs() +EntityWithOptionalProperty.update_forward_refs() +EntityWithOptionalStringEnumProperty.update_forward_refs() +EntityWithPropertyWithDefaultValue.update_forward_refs() +EntityWithPropertyWithDefaultValueNested.update_forward_refs() +EntityWithRequiredProperty.update_forward_refs() +EntityWithSimpleProperties.update_forward_refs() +EntityWithStrictArray.update_forward_refs() +EntityWithStringArrayProperty.update_forward_refs() +EntityWithStringEnumProperty.update_forward_refs() +EntityWithStringEnumPropertyWithDefaultValue.update_forward_refs() +EntityWithoutProperties.update_forward_refs() diff --git a/api_generator/tests/references/python/entity.py b/api_generator/tests/references/python/entity.py new file mode 100644 index 000000000..c2789a635 --- /dev/null +++ b/api_generator/tests/references/python/entity.py @@ -0,0 +1,46 @@ +# Generated code. Do not modify. + +from __future__ import annotations +from pydivkit.core import BaseDiv, Field +import enum +import typing + +from . import entity_with_array +from . import entity_with_array_of_nested_items +from . import entity_with_array_with_transform +from . import entity_with_complex_property +from . import entity_with_complex_property_with_default_value +from . import entity_with_entity_property +from . import entity_with_optional_complex_property +from . import entity_with_optional_property +from . import entity_with_optional_string_enum_property +from . import entity_with_property_with_default_value +from . import entity_with_required_property +from . import entity_with_simple_properties +from . import entity_with_strict_array +from . import entity_with_string_array_property +from . import entity_with_string_enum_property +from . import entity_with_string_enum_property_with_default_value +from . import entity_without_properties + +from typing import Union + +Entity = Union[ + entity_with_array.EntityWithArray, + entity_with_array_of_nested_items.EntityWithArrayOfNestedItems, + entity_with_array_with_transform.EntityWithArrayWithTransform, + entity_with_complex_property.EntityWithComplexProperty, + entity_with_complex_property_with_default_value.EntityWithComplexPropertyWithDefaultValue, + entity_with_entity_property.EntityWithEntityProperty, + entity_with_optional_complex_property.EntityWithOptionalComplexProperty, + entity_with_optional_property.EntityWithOptionalProperty, + entity_with_optional_string_enum_property.EntityWithOptionalStringEnumProperty, + entity_with_property_with_default_value.EntityWithPropertyWithDefaultValue, + entity_with_required_property.EntityWithRequiredProperty, + entity_with_simple_properties.EntityWithSimpleProperties, + entity_with_strict_array.EntityWithStrictArray, + entity_with_string_array_property.EntityWithStringArrayProperty, + entity_with_string_enum_property.EntityWithStringEnumProperty, + entity_with_string_enum_property_with_default_value.EntityWithStringEnumPropertyWithDefaultValue, + entity_without_properties.EntityWithoutProperties, +] diff --git a/api_generator/tests/references/python/entity_with_array.py b/api_generator/tests/references/python/entity_with_array.py new file mode 100644 index 000000000..2456e186f --- /dev/null +++ b/api_generator/tests/references/python/entity_with_array.py @@ -0,0 +1,27 @@ +# Generated code. Do not modify. + +from __future__ import annotations +from pydivkit.core import BaseDiv, Field +import enum +import typing + +from . import entity + + +class EntityWithArray(BaseDiv): + + def __init__( + self, *, + array: typing.List[entity.Entity], + type: str = 'entity_with_array', + ): + super().__init__( + type=type, + array=array, + ) + + type: str = Field(default='entity_with_array') + array: typing.List[entity.Entity] = Field(min_items=1) + + +EntityWithArray.update_forward_refs() diff --git a/api_generator/tests/references/python/entity_with_array_of_nested_items.py b/api_generator/tests/references/python/entity_with_array_of_nested_items.py new file mode 100644 index 000000000..f6f191b88 --- /dev/null +++ b/api_generator/tests/references/python/entity_with_array_of_nested_items.py @@ -0,0 +1,46 @@ +# Generated code. Do not modify. + +from __future__ import annotations +from pydivkit.core import BaseDiv, Field +import enum +import typing + +from . import entity + + +class EntityWithArrayOfNestedItems(BaseDiv): + + def __init__( + self, *, + items: typing.List[EntityWithArrayOfNestedItemsItem], + type: str = 'entity_with_array_of_nested_items', + ): + super().__init__( + type=type, + items=items, + ) + + type: str = Field(default='entity_with_array_of_nested_items') + items: typing.List[EntityWithArrayOfNestedItemsItem] = Field(min_items=1) + + +class EntityWithArrayOfNestedItemsItem(BaseDiv): + + def __init__( + self, *, + entity: entity.Entity, + property: str, + ): + super().__init__( + entity=entity, + property=property, + ) + + entity: entity.Entity = Field() + property: str = Field(min_length=1) + + +EntityWithArrayOfNestedItemsItem.update_forward_refs() + + +EntityWithArrayOfNestedItems.update_forward_refs() diff --git a/api_generator/tests/references/python/entity_with_array_with_transform.py b/api_generator/tests/references/python/entity_with_array_with_transform.py new file mode 100644 index 000000000..d8f24e110 --- /dev/null +++ b/api_generator/tests/references/python/entity_with_array_with_transform.py @@ -0,0 +1,25 @@ +# Generated code. Do not modify. + +from __future__ import annotations +from pydivkit.core import BaseDiv, Field +import enum +import typing + + +class EntityWithArrayWithTransform(BaseDiv): + + def __init__( + self, *, + array: typing.List[str], + type: str = 'entity_with_array_with_transform', + ): + super().__init__( + type=type, + array=array, + ) + + type: str = Field(default='entity_with_array_with_transform') + array: typing.List[str] = Field(min_items=1) + + +EntityWithArrayWithTransform.update_forward_refs() diff --git a/api_generator/tests/references/python/entity_with_complex_property.py b/api_generator/tests/references/python/entity_with_complex_property.py new file mode 100644 index 000000000..ae1a2d7b5 --- /dev/null +++ b/api_generator/tests/references/python/entity_with_complex_property.py @@ -0,0 +1,41 @@ +# Generated code. Do not modify. + +from __future__ import annotations +from pydivkit.core import BaseDiv, Field +import enum +import typing + + +class EntityWithComplexProperty(BaseDiv): + + def __init__( + self, *, + property: EntityWithComplexPropertyProperty, + type: str = 'entity_with_complex_property', + ): + super().__init__( + type=type, + property=property, + ) + + type: str = Field(default='entity_with_complex_property') + property: EntityWithComplexPropertyProperty = Field() + + +class EntityWithComplexPropertyProperty(BaseDiv): + + def __init__( + self, *, + value: str, + ): + super().__init__( + value=value, + ) + + value: str = Field(format="uri") + + +EntityWithComplexPropertyProperty.update_forward_refs() + + +EntityWithComplexProperty.update_forward_refs() diff --git a/api_generator/tests/references/python/entity_with_complex_property_with_default_value.py b/api_generator/tests/references/python/entity_with_complex_property_with_default_value.py new file mode 100644 index 000000000..769a26578 --- /dev/null +++ b/api_generator/tests/references/python/entity_with_complex_property_with_default_value.py @@ -0,0 +1,41 @@ +# Generated code. Do not modify. + +from __future__ import annotations +from pydivkit.core import BaseDiv, Field +import enum +import typing + + +class EntityWithComplexPropertyWithDefaultValue(BaseDiv): + + def __init__( + self, *, + type: str = 'entity_with_complex_property_with_default_value', + property: typing.Optional[EntityWithComplexPropertyWithDefaultValueProperty] = None, + ): + super().__init__( + type=type, + property=property, + ) + + type: str = Field(default='entity_with_complex_property_with_default_value') + property: typing.Optional[EntityWithComplexPropertyWithDefaultValueProperty] = Field() + + +class EntityWithComplexPropertyWithDefaultValueProperty(BaseDiv): + + def __init__( + self, *, + value: str, + ): + super().__init__( + value=value, + ) + + value: str = Field() + + +EntityWithComplexPropertyWithDefaultValueProperty.update_forward_refs() + + +EntityWithComplexPropertyWithDefaultValue.update_forward_refs() diff --git a/api_generator/tests/references/python/entity_with_entity_property.py b/api_generator/tests/references/python/entity_with_entity_property.py new file mode 100644 index 000000000..3db16e048 --- /dev/null +++ b/api_generator/tests/references/python/entity_with_entity_property.py @@ -0,0 +1,27 @@ +# Generated code. Do not modify. + +from __future__ import annotations +from pydivkit.core import BaseDiv, Field +import enum +import typing + +from . import entity + + +class EntityWithEntityProperty(BaseDiv): + + def __init__( + self, *, + type: str = 'entity_with_entity_property', + entity: typing.Optional[entity.Entity] = None, + ): + super().__init__( + type=type, + entity=entity, + ) + + type: str = Field(default='entity_with_entity_property') + entity: typing.Optional[entity.Entity] = Field() + + +EntityWithEntityProperty.update_forward_refs() diff --git a/api_generator/tests/references/python/entity_with_optional_complex_property.py b/api_generator/tests/references/python/entity_with_optional_complex_property.py new file mode 100644 index 000000000..e8a29f575 --- /dev/null +++ b/api_generator/tests/references/python/entity_with_optional_complex_property.py @@ -0,0 +1,41 @@ +# Generated code. Do not modify. + +from __future__ import annotations +from pydivkit.core import BaseDiv, Field +import enum +import typing + + +class EntityWithOptionalComplexProperty(BaseDiv): + + def __init__( + self, *, + type: str = 'entity_with_optional_complex_property', + property: typing.Optional[EntityWithOptionalComplexPropertyProperty] = None, + ): + super().__init__( + type=type, + property=property, + ) + + type: str = Field(default='entity_with_optional_complex_property') + property: typing.Optional[EntityWithOptionalComplexPropertyProperty] = Field() + + +class EntityWithOptionalComplexPropertyProperty(BaseDiv): + + def __init__( + self, *, + value: str, + ): + super().__init__( + value=value, + ) + + value: str = Field(format="uri") + + +EntityWithOptionalComplexPropertyProperty.update_forward_refs() + + +EntityWithOptionalComplexProperty.update_forward_refs() diff --git a/api_generator/tests/references/python/entity_with_optional_property.py b/api_generator/tests/references/python/entity_with_optional_property.py new file mode 100644 index 000000000..f440abadd --- /dev/null +++ b/api_generator/tests/references/python/entity_with_optional_property.py @@ -0,0 +1,25 @@ +# Generated code. Do not modify. + +from __future__ import annotations +from pydivkit.core import BaseDiv, Field +import enum +import typing + + +class EntityWithOptionalProperty(BaseDiv): + + def __init__( + self, *, + type: str = 'entity_with_optional_property', + property: typing.Optional[str] = None, + ): + super().__init__( + type=type, + property=property, + ) + + type: str = Field(default='entity_with_optional_property') + property: typing.Optional[str] = Field(min_length=1) + + +EntityWithOptionalProperty.update_forward_refs() diff --git a/api_generator/tests/references/python/entity_with_optional_string_enum_property.py b/api_generator/tests/references/python/entity_with_optional_string_enum_property.py new file mode 100644 index 000000000..fbbf700b3 --- /dev/null +++ b/api_generator/tests/references/python/entity_with_optional_string_enum_property.py @@ -0,0 +1,30 @@ +# Generated code. Do not modify. + +from __future__ import annotations +from pydivkit.core import BaseDiv, Field +import enum +import typing + + +class EntityWithOptionalStringEnumProperty(BaseDiv): + + def __init__( + self, *, + type: str = 'entity_with_optional_string_enum_property', + property: typing.Optional[EntityWithOptionalStringEnumPropertyProperty] = None, + ): + super().__init__( + type=type, + property=property, + ) + + type: str = Field(default='entity_with_optional_string_enum_property') + property: typing.Optional[EntityWithOptionalStringEnumPropertyProperty] = Field() + + +class EntityWithOptionalStringEnumPropertyProperty(str, enum.Enum): + FIRST = 'first' + SECOND = 'second' + + +EntityWithOptionalStringEnumProperty.update_forward_refs() diff --git a/api_generator/tests/references/python/entity_with_property_with_default_value.py b/api_generator/tests/references/python/entity_with_property_with_default_value.py new file mode 100644 index 000000000..1f793b59f --- /dev/null +++ b/api_generator/tests/references/python/entity_with_property_with_default_value.py @@ -0,0 +1,55 @@ +# Generated code. Do not modify. + +from __future__ import annotations +from pydivkit.core import BaseDiv, Field +import enum +import typing + + +class EntityWithPropertyWithDefaultValue(BaseDiv): + + def __init__( + self, *, + type: str = 'entity_with_property_with_default_value', + int: typing.Optional[int] = None, + nested: typing.Optional[EntityWithPropertyWithDefaultValueNested] = None, + url: typing.Optional[str] = None, + ): + super().__init__( + type=type, + int=int, + nested=nested, + url=url, + ) + + type: str = Field(default='entity_with_property_with_default_value') + int: typing.Optional[int] = Field() + nested: typing.Optional[EntityWithPropertyWithDefaultValueNested] = Field(description='non_optional is used to suppress auto-generation of default value for object withall-optional fields.') + url: typing.Optional[str] = Field(format="uri") + + +# non_optional is used to suppress auto-generation of default value for object with +# all-optional fields. +class EntityWithPropertyWithDefaultValueNested(BaseDiv): + + def __init__( + self, *, + non_optional: str, + int: typing.Optional[int] = None, + url: typing.Optional[str] = None, + ): + super().__init__( + int=int, + non_optional=non_optional, + url=url, + ) + + int: typing.Optional[int] = Field() + non_optional: str = Field() + url: typing.Optional[str] = Field(format="uri") + + +EntityWithPropertyWithDefaultValueNested.update_forward_refs() + + +EntityWithPropertyWithDefaultValue.update_forward_refs() diff --git a/api_generator/tests/references/python/entity_with_required_property.py b/api_generator/tests/references/python/entity_with_required_property.py new file mode 100644 index 000000000..1b2492b68 --- /dev/null +++ b/api_generator/tests/references/python/entity_with_required_property.py @@ -0,0 +1,25 @@ +# Generated code. Do not modify. + +from __future__ import annotations +from pydivkit.core import BaseDiv, Field +import enum +import typing + + +class EntityWithRequiredProperty(BaseDiv): + + def __init__( + self, *, + property: str, + type: str = 'entity_with_required_property', + ): + super().__init__( + type=type, + property=property, + ) + + type: str = Field(default='entity_with_required_property') + property: str = Field(min_length=1) + + +EntityWithRequiredProperty.update_forward_refs() diff --git a/api_generator/tests/references/python/entity_with_simple_properties.py b/api_generator/tests/references/python/entity_with_simple_properties.py new file mode 100644 index 000000000..22661b369 --- /dev/null +++ b/api_generator/tests/references/python/entity_with_simple_properties.py @@ -0,0 +1,50 @@ +# Generated code. Do not modify. + +from __future__ import annotations +from pydivkit.core import BaseDiv, Field +import enum +import typing + + +# Entity with simple properties. +class EntityWithSimpleProperties(BaseDiv): + + def __init__( + self, *, + type: str = 'entity_with_simple_properties', + boolean: typing.Optional[bool] = None, + boolean_int: typing.Optional[bool] = None, + color: typing.Optional[str] = None, + double: typing.Optional[float] = None, + id: typing.Optional[int] = None, + integer: typing.Optional[int] = None, + positive_integer: typing.Optional[int] = None, + string: typing.Optional[str] = None, + url: typing.Optional[str] = None, + ): + super().__init__( + type=type, + boolean=boolean, + boolean_int=boolean_int, + color=color, + double=double, + id=id, + integer=integer, + positive_integer=positive_integer, + string=string, + url=url, + ) + + type: str = Field(default='entity_with_simple_properties') + boolean: typing.Optional[bool] = Field(description='Boolean property.') + boolean_int: typing.Optional[bool] = Field(description='Boolean value in numeric format. @deprecated') + color: typing.Optional[str] = Field(format="color", description='Color.') + double: typing.Optional[float] = Field(description='Floating point number.') + id: typing.Optional[int] = Field(description='ID. Can\'t contain expressions.') + integer: typing.Optional[int] = Field(description='Integer.') + positive_integer: typing.Optional[int] = Field(description='Positive integer.') + string: typing.Optional[str] = Field(min_length=1, description='String.') + url: typing.Optional[str] = Field(format="uri") + + +EntityWithSimpleProperties.update_forward_refs() diff --git a/api_generator/tests/references/python/entity_with_strict_array.py b/api_generator/tests/references/python/entity_with_strict_array.py new file mode 100644 index 000000000..0b7d9f378 --- /dev/null +++ b/api_generator/tests/references/python/entity_with_strict_array.py @@ -0,0 +1,27 @@ +# Generated code. Do not modify. + +from __future__ import annotations +from pydivkit.core import BaseDiv, Field +import enum +import typing + +from . import entity + + +class EntityWithStrictArray(BaseDiv): + + def __init__( + self, *, + array: typing.List[entity.Entity], + type: str = 'entity_with_strict_array', + ): + super().__init__( + type=type, + array=array, + ) + + type: str = Field(default='entity_with_strict_array') + array: typing.List[entity.Entity] = Field(min_items=1) + + +EntityWithStrictArray.update_forward_refs() diff --git a/api_generator/tests/references/python/entity_with_string_array_property.py b/api_generator/tests/references/python/entity_with_string_array_property.py new file mode 100644 index 000000000..335f3bbf4 --- /dev/null +++ b/api_generator/tests/references/python/entity_with_string_array_property.py @@ -0,0 +1,25 @@ +# Generated code. Do not modify. + +from __future__ import annotations +from pydivkit.core import BaseDiv, Field +import enum +import typing + + +class EntityWithStringArrayProperty(BaseDiv): + + def __init__( + self, *, + array: typing.List[str], + type: str = 'entity_with_string_array_property', + ): + super().__init__( + type=type, + array=array, + ) + + type: str = Field(default='entity_with_string_array_property') + array: typing.List[str] = Field(min_items=1) + + +EntityWithStringArrayProperty.update_forward_refs() diff --git a/api_generator/tests/references/python/entity_with_string_enum_property.py b/api_generator/tests/references/python/entity_with_string_enum_property.py new file mode 100644 index 000000000..f647599be --- /dev/null +++ b/api_generator/tests/references/python/entity_with_string_enum_property.py @@ -0,0 +1,30 @@ +# Generated code. Do not modify. + +from __future__ import annotations +from pydivkit.core import BaseDiv, Field +import enum +import typing + + +class EntityWithStringEnumProperty(BaseDiv): + + def __init__( + self, *, + property: EntityWithStringEnumPropertyProperty, + type: str = 'entity_with_string_enum_property', + ): + super().__init__( + type=type, + property=property, + ) + + type: str = Field(default='entity_with_string_enum_property') + property: EntityWithStringEnumPropertyProperty = Field() + + +class EntityWithStringEnumPropertyProperty(str, enum.Enum): + FIRST = 'first' + SECOND = 'second' + + +EntityWithStringEnumProperty.update_forward_refs() diff --git a/api_generator/tests/references/python/entity_with_string_enum_property_with_default_value.py b/api_generator/tests/references/python/entity_with_string_enum_property_with_default_value.py new file mode 100644 index 000000000..f4c47b66e --- /dev/null +++ b/api_generator/tests/references/python/entity_with_string_enum_property_with_default_value.py @@ -0,0 +1,31 @@ +# Generated code. Do not modify. + +from __future__ import annotations +from pydivkit.core import BaseDiv, Field +import enum +import typing + + +class EntityWithStringEnumPropertyWithDefaultValue(BaseDiv): + + def __init__( + self, *, + type: str = 'entity_with_string_enum_property_with_default_value', + value: typing.Optional[EntityWithStringEnumPropertyWithDefaultValueValue] = None, + ): + super().__init__( + type=type, + value=value, + ) + + type: str = Field(default='entity_with_string_enum_property_with_default_value') + value: typing.Optional[EntityWithStringEnumPropertyWithDefaultValueValue] = Field() + + +class EntityWithStringEnumPropertyWithDefaultValueValue(str, enum.Enum): + FIRST = 'first' + SECOND = 'second' + THIRD = 'third' + + +EntityWithStringEnumPropertyWithDefaultValue.update_forward_refs() diff --git a/api_generator/tests/references/python/entity_without_properties.py b/api_generator/tests/references/python/entity_without_properties.py new file mode 100644 index 000000000..640102512 --- /dev/null +++ b/api_generator/tests/references/python/entity_without_properties.py @@ -0,0 +1,22 @@ +# Generated code. Do not modify. + +from __future__ import annotations +from pydivkit.core import BaseDiv, Field +import enum +import typing + + +class EntityWithoutProperties(BaseDiv): + + def __init__( + self, *, + type: str = 'entity_without_properties', + ): + super().__init__( + type=type, + ) + + type: str = Field(default='entity_without_properties') + + +EntityWithoutProperties.update_forward_refs() diff --git a/api_generator/tests/test_api_generator.py b/api_generator/tests/test_api_generator.py index 2f83f1004..fb63a5208 100644 --- a/api_generator/tests/test_api_generator.py +++ b/api_generator/tests/test_api_generator.py @@ -69,6 +69,12 @@ def test_type_script_generator(): references_folder_name='type_script') +def test_python_generator(): + assert_test_generator(config_filename='python_config.json', + schema_path=TEST_SCHEMA_PATH, + references_folder_name='python') + + def assert_test_generator(config_filename: str, schema_path: str, references_folder_name: str): config = Config(config_path=utils.path_generator_tests(os.path.join('configs', config_filename)), schema_path=schema_path,