Repository navigation
refactor type hinting #44
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
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 |
|---|---|---|
|
|
@@ -2,7 +2,7 @@ | |
| {%- set used_models = properties|models_in_properties -%} | ||
| {%- if used_models -%}( | ||
| {%- for name in used_models -%} | ||
| Generic[T{{ name }}]{%- if not loop.last -%}, {%- endif -%} | ||
| "{{ name }}"{%- if not loop.last -%}, {%- endif -%} | ||
|
Contributor
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. since your code no longer uses the |
||
| {%- endfor -%} | ||
| ){%- endif -%} | ||
| {%- endmacro -%} | ||
|
|
@@ -24,45 +24,49 @@ | |
| TypeVar, | ||
| ) | ||
|
|
||
| T = TypeVar("T") | ||
| from aws_cloudformation_rpdk_python_lib.interface import ( | ||
| BaseResourceHandlerRequest, | ||
| BaseResourceModel, | ||
| ) | ||
|
|
||
|
|
||
| def set_or_none(value: Optional[Sequence[T]]) -> Optional[AbstractSet[T]]: | ||
| def set_or_none(value: Optional[Sequence[Any]]) -> Optional[AbstractSet[Any]]: | ||
|
Contributor
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. if you keep |
||
| if value: | ||
| return set(value) | ||
| return None | ||
|
|
||
|
|
||
| {% for model, properties in models.items() %} | ||
| T{{ model }} = TypeVar("T{{ model }}", bound="{{ model }}{{ typevar_model_bindings(properties) }}") | ||
| {% endfor %} | ||
| @dataclass | ||
| class ResourceHandlerRequest(BaseResourceHandlerRequest): | ||
| # pylint: disable=invalid-name | ||
| desiredResourceState: Optional["ResourceModel"] | ||
| previousResourceState: Optional["ResourceModel"] | ||
|
|
||
|
|
||
| {% for model, properties in models.items() %} | ||
|
|
||
|
|
||
| @dataclass | ||
| class {{ model }}{{ class_model_bindings(properties) }}: | ||
| class {{ model|resource_name_suffix }}(BaseResourceModel): | ||
|
Contributor
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. sub-models aren't and shouldn't be valid instances of |
||
| {% for name, type in properties.items() %} | ||
| {{ name }}: Optional[{{ type|translate_type }}] | ||
| {% endfor %} | ||
|
|
||
| def _serialize(self) -> Mapping[str, Any]: | ||
| return self.__dict__ | ||
|
|
||
| @classmethod | ||
| def _deserialize( | ||
| cls: Type[T{{ model }}], | ||
| json: Mapping[str, Any], | ||
| ) -> Optional[T{{ model }}]: | ||
| if not json: | ||
| cls: Type["{{ model|resource_name_suffix }}"], | ||
| json_data: Optional[Mapping[str, Any]], | ||
| ) -> Optional["{{ model|resource_name_suffix }}"]: | ||
| if not json_data: | ||
| return None | ||
| return cls( | ||
| {% for name, type in properties.items() %} | ||
| {% if type.container == ContainerType.MODEL %} | ||
| {{ name }}={{ type.type }}._deserialize(json.get("{{ name }}")), # type: ignore | ||
| {{ name }}={{ type.type|resource_name_suffix }}._deserialize(json_data.get("{{ name }}")), | ||
| {% elif type.container == ContainerType.SET %} | ||
| {{ name }}=set_or_none(json.get("{{ name }}")), | ||
| {{ name }}=set_or_none(json_data.get("{{ name }}")), | ||
| {% else %} | ||
| {{ name }}=json.get("{{ name }}"), | ||
| {{ name }}=json_data.get("{{ name }}"), | ||
| {% endif %} | ||
| {% endfor %} | ||
| ) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,76 +1,76 @@ | ||
| from typing import Any, Generic | ||
| from typing import Any | ||
|
|
||
| from .interface import HandlerErrorCode, ProgressEvent, T | ||
| from .interface import HandlerErrorCode, ProgressEvent | ||
|
|
||
|
|
||
| class _HandlerError(Exception, Generic[T]): | ||
| class _HandlerError(Exception): | ||
| def __init__(self, *args: Any): | ||
| self._error_code = HandlerErrorCode[type(self).__name__] | ||
| super().__init__(*args) | ||
|
|
||
| def to_progress_event(self) -> ProgressEvent[T]: | ||
| def to_progress_event(self) -> ProgressEvent: | ||
| return ProgressEvent.failed(self._error_code, str(self)) | ||
|
|
||
|
|
||
| class NotUpdatable(_HandlerError[T]): | ||
| class NotUpdatable(_HandlerError): | ||
| pass | ||
|
|
||
|
|
||
| class InvalidRequest(_HandlerError[T]): | ||
| class InvalidRequest(_HandlerError): | ||
| pass | ||
|
|
||
|
|
||
| class AccessDenied(_HandlerError[T]): | ||
| class AccessDenied(_HandlerError): | ||
| pass | ||
|
|
||
|
|
||
| class InvalidCredentials(_HandlerError[T]): | ||
| class InvalidCredentials(_HandlerError): | ||
| pass | ||
|
|
||
|
|
||
| class AlreadyExists(_HandlerError[T]): | ||
| class AlreadyExists(_HandlerError): | ||
| def __init__(self, type_name: str, identifier: str): | ||
| super().__init__( | ||
| f"Resource of type '{type_name}' with identifier " | ||
| f"'{identifier}' already exists." | ||
| ) | ||
|
|
||
|
|
||
| class NotFound(_HandlerError[T]): | ||
| class NotFound(_HandlerError): | ||
| def __init__(self, type_name: str, identifier: str): | ||
| super().__init__( | ||
| f"Resource of type '{type_name}' with identifier " | ||
| f"'{identifier}' was not found." | ||
| ) | ||
|
|
||
|
|
||
| class ResourceConflict(_HandlerError[T]): | ||
| class ResourceConflict(_HandlerError): | ||
| pass | ||
|
|
||
|
|
||
| class Throttling(_HandlerError[T]): | ||
| class Throttling(_HandlerError): | ||
| pass | ||
|
|
||
|
|
||
| class ServiceLimitExceeded(_HandlerError[T]): | ||
| class ServiceLimitExceeded(_HandlerError): | ||
| pass | ||
|
|
||
|
|
||
| class NotStabilized(_HandlerError[T]): | ||
| class NotStabilized(_HandlerError): | ||
| pass | ||
|
|
||
|
|
||
| class GeneralServiceException(_HandlerError[T]): | ||
| class GeneralServiceException(_HandlerError): | ||
| pass | ||
|
|
||
|
|
||
| class ServiceInternalError(_HandlerError[T]): | ||
| class ServiceInternalError(_HandlerError): | ||
| pass | ||
|
|
||
|
|
||
| class NetworkFailure(_HandlerError[T]): | ||
| class NetworkFailure(_HandlerError): | ||
| pass | ||
|
|
||
|
|
||
| class InternalFailure(_HandlerError[T]): | ||
| class InternalFailure(_HandlerError): | ||
| pass |
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.
there's only one resource model, so this is confusing. it's also pretty heavyweight. maybe something like we do in the Java plugin in a simpler solution? (models already are guaranteed to have unique names, so you only have to disambiguate clashes with languages types. as far as i can see, the same is true for type hints)
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.
ah, I see why you may have done this. interesting mypy errors happen when a variable has the same name as a type (the variable shadows the type for type-hints only)