Skip to content

Commit

Permalink
fix, python: move from lists to sequences when using lists in functio…
Browse files Browse the repository at this point in the history
…n signatures (#3040)
  • Loading branch information
armandobelardo authored Feb 23, 2024
1 parent a06289f commit d98f9ed
Show file tree
Hide file tree
Showing 109 changed files with 5,772 additions and 6,176 deletions.
7 changes: 6 additions & 1 deletion generators/python/sdk/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased

## [0.11.3] - 2024-02-22

- Fix: Transition from lists to sequences within function calls, this is a fix as a result of how mypy handles type variance.
This fix is only for function calls as testing shows that we do not hit the same issue within mypy with list[union[*]] fields on pydantic objects.
This issue outlines it well: https://stackoverflow.com/questions/76138438/incompatible-types-in-assignment-expression-has-type-liststr-variable-has

- Improvement: The Python SDK generator now defaults to `require_optional_fields = False`. This means that any requests that have optional fields no longer require a user to input data (or a `None` value) in.
Example:
Expand Down
2 changes: 1 addition & 1 deletion generators/python/sdk/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.11.2-rc0
0.11.3
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ def get_type_hint_for_type_reference(
self,
type_reference: ir_types.TypeReference,
must_import_after_current_declaration: Optional[Callable[[ir_types.DeclaredTypeName], bool]] = None,
in_endpoint: Optional[bool] = False,
) -> AST.TypeHint:
...

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,12 @@ def get_type_hint_for_type_reference(
self,
type_reference: ir_types.TypeReference,
must_import_after_current_declaration: Optional[Callable[[ir_types.DeclaredTypeName], bool]] = None,
in_endpoint: Optional[bool] = False,
) -> AST.TypeHint:
return self._type_reference_to_type_hint_converter.get_type_hint_for_type_reference(
type_reference,
must_import_after_current_declaration=must_import_after_current_declaration,
in_endpoint=in_endpoint,
)

def get_class_reference_for_type_id(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@ def get_type_hint_for_type_reference(
self,
type_reference: ir_types.TypeReference,
must_import_after_current_declaration: Optional[Callable[[ir_types.DeclaredTypeName], bool]],
in_endpoint: Optional[bool] = False,
) -> AST.TypeHint:
return type_reference.visit(
container=lambda container: self._get_type_hint_for_container(
container=container,
must_import_after_current_declaration=must_import_after_current_declaration,
in_endpoint=in_endpoint,
),
named=lambda type_name: self._get_type_hint_for_named(
type_name=type_name,
Expand All @@ -39,6 +41,7 @@ def _get_set_type_hint_for_named(
self,
name: ir_types.DeclaredTypeName,
must_import_after_current_declaration: Optional[Callable[[ir_types.DeclaredTypeName], bool]],
in_endpoint: Optional[bool],
) -> AST.TypeHint:
is_primative = self._context.get_declaration_for_type_id(name.type_id).shape.visit(
alias=lambda alias_td: alias_td.resolved_type.visit(
Expand All @@ -55,41 +58,65 @@ def _get_set_type_hint_for_named(
)
if is_primative:
return AST.TypeHint.set(inner_hint)
if in_endpoint:
return AST.TypeHint.sequence(inner_hint)
return AST.TypeHint.list(inner_hint)

def _get_type_hint_for_container(
self,
container: ir_types.ContainerType,
must_import_after_current_declaration: Optional[Callable[[ir_types.DeclaredTypeName], bool]],
in_endpoint: Optional[bool],
) -> AST.TypeHint:
return container.visit(
list=lambda wrapped_type: AST.TypeHint.list(
list=lambda wrapped_type: AST.TypeHint.sequence(
self.get_type_hint_for_type_reference(
type_reference=wrapped_type,
must_import_after_current_declaration=must_import_after_current_declaration,
in_endpoint=in_endpoint,
)
)
if in_endpoint
else AST.TypeHint.list(
self.get_type_hint_for_type_reference(
type_reference=wrapped_type,
must_import_after_current_declaration=must_import_after_current_declaration,
in_endpoint=in_endpoint,
)
),
map=lambda map_type: AST.TypeHint.dict(
key_type=self.get_type_hint_for_type_reference(
type_reference=map_type.key_type,
must_import_after_current_declaration=must_import_after_current_declaration,
in_endpoint=in_endpoint,
),
value_type=self.get_type_hint_for_type_reference(
type_reference=map_type.value_type,
must_import_after_current_declaration=must_import_after_current_declaration,
in_endpoint=in_endpoint,
),
),
# Fern sets become Pydanic lists, since Pydantic models aren't hashable
set=lambda wrapped_type: wrapped_type.visit(
container=lambda type_reference: AST.TypeHint.list(
container=lambda type_reference: AST.TypeHint.sequence(
self._get_type_hint_for_container(
container=type_reference,
must_import_after_current_declaration=must_import_after_current_declaration,
in_endpoint=in_endpoint,
)
)
if in_endpoint
else AST.TypeHint.list(
self._get_type_hint_for_container(
container=type_reference,
must_import_after_current_declaration=must_import_after_current_declaration,
in_endpoint=in_endpoint,
)
),
named=lambda type_reference: self._get_set_type_hint_for_named(
type_reference,
must_import_after_current_declaration=must_import_after_current_declaration,
in_endpoint=in_endpoint,
),
primitive=lambda type_reference: AST.TypeHint.set(
self._get_type_hint_for_primitive(primitive=type_reference)
Expand All @@ -100,6 +127,7 @@ def _get_type_hint_for_container(
self.get_type_hint_for_type_reference(
type_reference=wrapped_type,
must_import_after_current_declaration=must_import_after_current_declaration,
in_endpoint=in_endpoint,
)
),
literal=self.visit_literal,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,8 @@ def _get_json_response_body_type(
) -> AST.TypeHint:
return json_response.visit(
response=lambda response: self._context.pydantic_generator_context.get_type_hint_for_type_reference(
response.response_body_type
response.response_body_type,
in_endpoint=True,
),
nested_property_as_response=lambda _: raise_json_nested_property_as_response_unsupported(),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,8 @@ def _get_endpoint_path_parameters(
AST.FunctionParameter(
name=get_parameter_name(path_parameter.name),
type_hint=self._context.pydantic_generator_context.get_type_hint_for_type_reference(
path_parameter.value_type
path_parameter.value_type,
in_endpoint=True,
),
),
)
Expand All @@ -182,7 +183,8 @@ def _get_endpoint_named_parameters(
for query_parameter in endpoint.query_parameters:
if not self._is_type_literal(type_reference=query_parameter.value_type):
query_parameter_type_hint = self._context.pydantic_generator_context.get_type_hint_for_type_reference(
query_parameter.value_type
query_parameter.value_type,
in_endpoint=True,
)
parameters.append(
AST.NamedFunctionParameter(
Expand All @@ -202,7 +204,8 @@ def _get_endpoint_named_parameters(
name=get_parameter_name(header.name.name),
docs=header.docs,
type_hint=self._context.pydantic_generator_context.get_type_hint_for_type_reference(
header.value_type
header.value_type,
in_endpoint=True,
),
),
)
Expand All @@ -216,7 +219,8 @@ def _get_endpoint_named_parameters(
name=get_parameter_name(header.name.name),
docs=header.docs,
type_hint=self._context.pydantic_generator_context.get_type_hint_for_type_reference(
header.value_type
header.value_type,
in_endpoint=True,
),
),
)
Expand Down Expand Up @@ -504,7 +508,8 @@ def _named_parameters_from_path_parameters(
name=get_parameter_name(path_parameter.name),
docs=path_parameter.docs,
type_hint=self._context.pydantic_generator_context.get_type_hint_for_type_reference(
path_parameter.value_type
path_parameter.value_type,
in_endpoint=True,
),
),
)
Expand Down Expand Up @@ -577,7 +582,7 @@ def _get_json_response_body_type(
) -> AST.TypeHint:
return json_response.visit(
response=lambda response: self._context.pydantic_generator_context.get_type_hint_for_type_reference(
response.response_body_type
response.response_body_type,
),
nested_property_as_response=lambda _: raise_json_nested_property_as_response_unsupported(),
)
Expand Down Expand Up @@ -865,21 +870,24 @@ def _get_typehint_for_query_param(
return AST.TypeHint.optional(
AST.TypeHint.union(
self._context.pydantic_generator_context.get_type_hint_for_type_reference(
unwrap_optional_type(query_parameter.value_type)
unwrap_optional_type(query_parameter.value_type),
in_endpoint=True,
),
AST.TypeHint.list(
AST.TypeHint.sequence(
self._context.pydantic_generator_context.get_type_hint_for_type_reference(
unwrap_optional_type(query_parameter.value_type)
unwrap_optional_type(query_parameter.value_type),
in_endpoint=True,
)
),
)
)
elif query_parameter.allow_multiple:
return AST.TypeHint.union(
query_parameter_type_hint,
AST.TypeHint.list(
AST.TypeHint.sequence(
self._context.pydantic_generator_context.get_type_hint_for_type_reference(
unwrap_optional_type(query_parameter.value_type)
unwrap_optional_type(query_parameter.value_type),
in_endpoint=True,
)
),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,16 @@ def get_parameters(self) -> List[AST.NamedFunctionParameter]:
for property in self._get_all_properties_for_inlined_request_body():
if not self._is_type_literal(property.value_type):
type_hint = self._context.pydantic_generator_context.get_type_hint_for_type_reference(
property.value_type
property.value_type,
in_endpoint=True,
)
parameters.append(
AST.NamedFunctionParameter(
name=self._get_property_name(property),
docs=property.docs,
type_hint=self._context.pydantic_generator_context.get_type_hint_for_type_reference(
property.value_type
property.value_type,
in_endpoint=True,
),
initializer=AST.Expression(DEFAULT_BODY_PARAMETER_VALUE) if type_hint.is_optional else None,
),
Expand Down Expand Up @@ -89,7 +91,8 @@ def write(writer: AST.NodeWriter) -> None:
def _are_any_properties_optional(self) -> bool:
return any(
self._context.pydantic_generator_context.get_type_hint_for_type_reference(
body_property.value_type
body_property.value_type,
in_endpoint=True,
).is_optional
for body_property in self._get_all_properties_for_inlined_request_body()
)
Expand All @@ -105,7 +108,8 @@ def get_pre_fetch_statements(self) -> Optional[AST.CodeWriter]:
required_properties: List[ir_types.InlinedRequestBodyProperty] = []
for body_property in self._get_all_properties_for_inlined_request_body():
type_hint = self._context.pydantic_generator_context.get_type_hint_for_type_reference(
body_property.value_type
body_property.value_type,
in_endpoint=True,
)
if type_hint.is_optional:
optional_properties.append(body_property)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ def get_parameters(self) -> List[AST.NamedFunctionParameter]:
AST.NamedFunctionParameter(
name=self._get_request_parameter_name(),
type_hint=self._context.pydantic_generator_context.get_type_hint_for_type_reference(
self._request_body.request_body_type
self._request_body.request_body_type,
in_endpoint=True,
),
)
]
Expand Down
Loading

0 comments on commit d98f9ed

Please sign in to comment.