-
-
Notifications
You must be signed in to change notification settings - Fork 7.4k
python: adjust basic typing information #17511
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
ffb4be8
5e2c295
5861b4b
0c7b22e
545a200
85ed538
856f203
0230af2
e37fa6c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,6 +6,7 @@ import io | |
| import json | ||
| import re | ||
| import ssl | ||
| from typing import Optional | ||
|
|
||
| import aiohttp | ||
| import aiohttp_retry | ||
|
|
@@ -72,6 +73,7 @@ class RESTClientObject: | |
| ) | ||
|
|
||
| retries = configuration.retries | ||
| self.retry_client: Optional[aiohttp_retry.RetryClient] | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The retry client can be None just below. |
||
| if retries is not None: | ||
| self.retry_client = aiohttp_retry.RetryClient( | ||
| client_session=self.pool_manager, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,6 +11,7 @@ import re # noqa: F401 | |
| {{/vendorExtensions.x-py-model-imports}} | ||
| from typing import Union, Any, List, TYPE_CHECKING, Optional, Dict | ||
| from typing_extensions import Literal, Self | ||
| from pydantic import Field | ||
|
|
||
| {{#lambda.uppercase}}{{{classname}}}{{/lambda.uppercase}}_ANY_OF_SCHEMAS = [{{#anyOf}}"{{.}}"{{^-last}}, {{/-last}}{{/anyOf}}] | ||
|
|
||
|
|
@@ -27,7 +28,7 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}} | |
| actual_instance: Optional[Union[{{#anyOf}}{{{.}}}{{^-last}}, {{/-last}}{{/anyOf}}]] = None | ||
| else: | ||
| actual_instance: Any = None | ||
| any_of_schemas: List[str] = Literal[{{#lambda.uppercase}}{{{classname}}}{{/lambda.uppercase}}_ANY_OF_SCHEMAS] | ||
| any_of_schemas: List[str] = Field(default=Literal[{{#anyOf}}"{{.}}"{{^-last}}, {{/-last}}{{/anyOf}}]) | ||
|
|
||
| model_config = { | ||
| "validate_assignment": True, | ||
|
|
@@ -153,22 +154,20 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}} | |
| if self.actual_instance is None: | ||
| return "null" | ||
|
|
||
| to_json = getattr(self.actual_instance, "to_json", None) | ||
| if callable(to_json): | ||
| if hasattr(self.actual_instance, "to_json") and callable(self.actual_instance.to_json): | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the same construct as before, but actually "types" correctly (this effectively bypasses all the typing information though :D ) |
||
| return self.actual_instance.to_json() | ||
| else: | ||
| return json.dumps(self.actual_instance) | ||
|
|
||
| def to_dict(self) -> Dict: | ||
| def to_dict(self) -> Optional[Union[Dict, {{#anyOf}}{{.}}{{^-last}}, {{/-last}}{{/anyOf}}]]: | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The result type is a bit complicated here:
|
||
| """Returns the dict representation of the actual instance""" | ||
| if self.actual_instance is None: | ||
| return "null" | ||
| return None | ||
|
|
||
| to_json = getattr(self.actual_instance, "to_json", None) | ||
| if callable(to_json): | ||
| if hasattr(self.actual_instance, "to_dict") and callable(self.actual_instance.to_dict): | ||
| return self.actual_instance.to_dict() | ||
| else: | ||
| return json.dumps(self.actual_instance) | ||
| return self.actual_instance | ||
|
Comment on lines
+165
to
+170
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this was a mistake, duplicated code from the I fixed this to be the same code as the |
||
|
|
||
| def to_str(self) -> str: | ||
| """Returns the string representation of the actual instance""" | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -9,10 +9,8 @@ import json | |||||||
| {{#vendorExtensions.x-py-model-imports}} | ||||||||
| {{{.}}} | ||||||||
| {{/vendorExtensions.x-py-model-imports}} | ||||||||
| try: | ||||||||
| from typing import Self | ||||||||
| except ImportError: | ||||||||
| from typing_extensions import Self | ||||||||
| from typing import Optional, Set | ||||||||
| from typing_extensions import Self | ||||||||
|
|
||||||||
| class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}}): | ||||||||
| """ | ||||||||
|
|
@@ -87,15 +85,15 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}} | |||||||
| {{#hasChildren}} | ||||||||
| {{#discriminator}} | ||||||||
| # JSON field name that stores the object type | ||||||||
| __discriminator_property_name: ClassVar[List[str]] = '{{discriminator.propertyBaseName}}' | ||||||||
| __discriminator_property_name: ClassVar[str] = '{{discriminator.propertyBaseName}}' | ||||||||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Typing was wrong here |
||||||||
|
|
||||||||
| # discriminator mappings | ||||||||
| __discriminator_value_class_map: ClassVar[Dict[str, str]] = { | ||||||||
| {{#mappedModels}}'{{{mappingName}}}': '{{{modelName}}}'{{^-last}},{{/-last}}{{/mappedModels}} | ||||||||
| } | ||||||||
|
|
||||||||
| @classmethod | ||||||||
| def get_discriminator_value(cls, obj: Dict) -> str: | ||||||||
| def get_discriminator_value(cls, obj: Dict) -> Optional[str]: | ||||||||
| """Returns the discriminator value (object type) of the data""" | ||||||||
| discriminator_value = obj[cls.__discriminator_property_name] | ||||||||
| if discriminator_value: | ||||||||
|
|
@@ -115,7 +113,7 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}} | |||||||
| return json.dumps(self.to_dict()) | ||||||||
|
|
||||||||
| @classmethod | ||||||||
| def from_json(cls, json_str: str) -> {{^hasChildren}}Self{{/hasChildren}}{{#hasChildren}}{{#discriminator}}Union[{{#children}}Self{{^-last}}, {{/-last}}{{/children}}]{{/discriminator}}{{^discriminator}}Self{{/discriminator}}{{/hasChildren}}: | ||||||||
| def from_json(cls, json_str: str) -> Optional[{{^hasChildren}}Self{{/hasChildren}}{{#hasChildren}}{{#discriminator}}Union[{{#children}}Self{{^-last}}, {{/-last}}{{/children}}]{{/discriminator}}{{^discriminator}}Self{{/discriminator}}{{/hasChildren}}]: | ||||||||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I changed the signature to follow te signature of |
||||||||
| """Create an instance of {{{classname}}} from a JSON string""" | ||||||||
| return cls.from_dict(json.loads(json_str)) | ||||||||
|
|
||||||||
|
|
@@ -135,16 +133,18 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}} | |||||||
| * Fields in `self.additional_properties` are added to the output dict. | ||||||||
| {{/isAdditionalPropertiesTrue}} | ||||||||
| """ | ||||||||
| excluded_fields: Set[str] = set([ | ||||||||
| {{#vendorExtensions.x-py-readonly}} | ||||||||
| "{{{.}}}", | ||||||||
| {{/vendorExtensions.x-py-readonly}} | ||||||||
| {{#isAdditionalPropertiesTrue}} | ||||||||
| "additional_properties", | ||||||||
| {{/isAdditionalPropertiesTrue}} | ||||||||
| ]) | ||||||||
|
|
||||||||
| _dict = self.model_dump( | ||||||||
| by_alias=True, | ||||||||
| exclude={ | ||||||||
| {{#vendorExtensions.x-py-readonly}} | ||||||||
| "{{{.}}}", | ||||||||
| {{/vendorExtensions.x-py-readonly}} | ||||||||
| {{#isAdditionalPropertiesTrue}} | ||||||||
| "additional_properties", | ||||||||
| {{/isAdditionalPropertiesTrue}} | ||||||||
| }, | ||||||||
| exclude=excluded_fields, | ||||||||
|
Comment on lines
+136
to
+147
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There were several bugs here: If the value passed to
I took a simpler way by setting the value outside, "forcing" it's type and passing it down to the method call. |
||||||||
| exclude_none=True, | ||||||||
| ) | ||||||||
| {{#allVars}} | ||||||||
|
|
@@ -234,10 +234,10 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}} | |||||||
| {{/allVars}} | ||||||||
| return _dict | ||||||||
|
|
||||||||
| {{#hasChildren}} | ||||||||
| @classmethod | ||||||||
| def from_dict(cls, obj: Dict) -> {{^hasChildren}}Self{{/hasChildren}}{{#hasChildren}}{{#discriminator}}Union[{{#children}}Self{{^-last}}, {{/-last}}{{/children}}]{{/discriminator}}{{^discriminator}}Self{{/discriminator}}{{/hasChildren}}: | ||||||||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I split this long signature into 2 parts:
|
||||||||
| def from_dict(cls, obj: Dict) -> Optional[{{#discriminator}}Union[{{#children}}Self{{^-last}}, {{/-last}}{{/children}}]{{/discriminator}}{{^discriminator}}Self{{/discriminator}}]: | ||||||||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
openapi-generator/samples/client/echo_api/python/openapi_client/models/query.py Lines 88 to 90 in 8b5b5a7
I'm not sure how to properly fix this though. |
||||||||
| """Create an instance of {{{classname}}} from a dict""" | ||||||||
| {{#hasChildren}} | ||||||||
| {{#discriminator}} | ||||||||
| # look up the object type based on discriminator mapping | ||||||||
| object_type = cls.get_discriminator_value(obj) | ||||||||
|
|
@@ -249,8 +249,11 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}} | |||||||
| json.dumps(obj) + ". Discriminator property name: " + cls.__discriminator_property_name + | ||||||||
| ", mapping: " + json.dumps(cls.__discriminator_value_class_map)) | ||||||||
| {{/discriminator}} | ||||||||
| {{/hasChildren}} | ||||||||
| {{^hasChildren}} | ||||||||
| {{/hasChildren}} | ||||||||
| {{^hasChildren}} | ||||||||
| @classmethod | ||||||||
| def from_dict(cls, obj: Optional[Dict]) -> Optional[Self]: | ||||||||
| """Create an instance of {{{classname}}} from a dict""" | ||||||||
| if obj is None: | ||||||||
| return None | ||||||||
|
|
||||||||
|
|
@@ -277,7 +280,7 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}} | |||||||
| {{^items.items.isPrimitiveType}} | ||||||||
| "{{{baseName}}}": [ | ||||||||
| [{{{items.items.dataType}}}.from_dict(_inner_item) for _inner_item in _item] | ||||||||
| for _item in obj.get("{{{baseName}}}") | ||||||||
| for _item in obj["{{{baseName}}}"] | ||||||||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I changed those because the value is actually checked just after and |
||||||||
| ] if obj.get("{{{baseName}}}") is not None else None{{^-last}},{{/-last}} | ||||||||
| {{/items.items.isPrimitiveType}} | ||||||||
| {{/items.isArray}} | ||||||||
|
|
@@ -287,7 +290,7 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}} | |||||||
| "{{{baseName}}}": obj.get("{{{baseName}}}"){{^-last}},{{/-last}} | ||||||||
| {{/items.isEnumOrRef}} | ||||||||
| {{^items.isEnumOrRef}} | ||||||||
| "{{{baseName}}}": [{{{items.dataType}}}.from_dict(_item) for _item in obj.get("{{{baseName}}}")] if obj.get("{{{baseName}}}") is not None else None{{^-last}},{{/-last}} | ||||||||
| "{{{baseName}}}": [{{{items.dataType}}}.from_dict(_item) for _item in obj["{{{baseName}}}"]] if obj.get("{{{baseName}}}") is not None else None{{^-last}},{{/-last}} | ||||||||
| {{/items.isEnumOrRef}} | ||||||||
| {{/items.isPrimitiveType}} | ||||||||
| {{#items.isPrimitiveType}} | ||||||||
|
|
@@ -320,14 +323,14 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}} | |||||||
| if _v is not None | ||||||||
| else None | ||||||||
| ) | ||||||||
| for _k, _v in obj.get("{{{baseName}}}").items() | ||||||||
| for _k, _v in obj.get("{{{baseName}}}", {}).items() | ||||||||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||||
| ){{^-last}},{{/-last}} | ||||||||
| {{/items.isArray}} | ||||||||
| {{/items.isContainer}} | ||||||||
| {{^items.isContainer}} | ||||||||
| "{{{baseName}}}": dict( | ||||||||
| (_k, {{{items.dataType}}}.from_dict(_v)) | ||||||||
| for _k, _v in obj.get("{{{baseName}}}").items() | ||||||||
| for _k, _v in obj["{{{baseName}}}"].items() | ||||||||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above: |
||||||||
| ) | ||||||||
| if obj.get("{{{baseName}}}") is not None | ||||||||
| else None{{^-last}},{{/-last}} | ||||||||
|
|
@@ -345,7 +348,7 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}} | |||||||
| {{^isContainer}} | ||||||||
| {{^isPrimitiveType}} | ||||||||
| {{^isEnumOrRef}} | ||||||||
| "{{{baseName}}}": {{{dataType}}}.from_dict(obj.get("{{{baseName}}}")) if obj.get("{{{baseName}}}") is not None else None{{^-last}},{{/-last}} | ||||||||
| "{{{baseName}}}": {{{dataType}}}.from_dict(obj["{{{baseName}}}"]) if obj.get("{{{baseName}}}") is not None else None{{^-last}},{{/-last}} | ||||||||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above: |
||||||||
| {{/isEnumOrRef}} | ||||||||
| {{#isEnumOrRef}} | ||||||||
| "{{{baseName}}}": obj.get("{{{baseName}}}"){{^-last}},{{/-last}} | ||||||||
|
|
@@ -370,7 +373,7 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}} | |||||||
|
|
||||||||
| {{/isAdditionalPropertiesTrue}} | ||||||||
| return _obj | ||||||||
| {{/hasChildren}} | ||||||||
| {{/hasChildren}} | ||||||||
|
|
||||||||
| {{#vendorExtensions.x-py-postponed-model-imports.size}} | ||||||||
| {{#vendorExtensions.x-py-postponed-model-imports}} | ||||||||
|
|
||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mypy doesn't like the try/except form and after re-reading the
typing_extensionsdocumentation, the module already does the pass through to the stdlib if the type is implemented there, so we don't need to do this try/import here actually.