Skip to content

Commit

Permalink
Refactor imports
Browse files Browse the repository at this point in the history
  • Loading branch information
vemel committed Dec 19, 2024
1 parent a379542 commit 33287b7
Show file tree
Hide file tree
Showing 25 changed files with 203 additions and 107 deletions.
55 changes: 55 additions & 0 deletions mypy_boto3_builder/import_helpers/import_helper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
"""
Wrapper for ImportString usage.
Copyright 2024 Vlad Emelianov
"""

from typing import Final

from mypy_boto3_builder.exceptions import StructureError
from mypy_boto3_builder.import_helpers.import_parent import ImportParent
from mypy_boto3_builder.import_helpers.import_string import ImportString


class Import:
"""
Wrapper for ImportString usage.
"""

future: Final = ImportString(ImportParent.future.value)
builtins: Final = ImportString(ImportParent.builtins.value)
boto3: Final = ImportString(ImportParent.boto3.value)
botocore: Final = ImportString(ImportParent.botocore.value)
typing: Final = ImportString(ImportParent.typing.value)
awscrt: Final = ImportString(ImportParent.awscrt.value)
s3transfer: Final = ImportString(ImportParent.s3transfer.value)
aiobotocore: Final = ImportString(ImportParent.aiobotocore.value)
aioboto3: Final = ImportString(ImportParent.aioboto3.value)
typing_extensions: Final = ImportString(ImportParent.typing_extensions.value)
types: Final = ImportString(ImportParent.types.value)
sys: Final = ImportString(ImportParent.sys.value)

@classmethod
def local(cls, module_name: str) -> ImportString:
"""
Create local import string.
"""
if not module_name:
raise StructureError("Module name cannot be empty for local import")
return ImportString("", module_name)

@classmethod
def from_str(cls, import_string: str) -> ImportString:
"""
Create from string.
"""
return cls.from_parts(*import_string.split("."))

@classmethod
def from_parts(cls, parent: str, *parts: str) -> ImportString:
"""
Create from string.
"""
if not parent:
raise StructureError("Parent cannot be empty")
return ImportString(parent, *parts)
53 changes: 53 additions & 0 deletions mypy_boto3_builder/import_helpers/import_parent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
"""
Enum with all parent imports.
Copyright 2024 Vlad Emelianov
"""

from enum import Enum
from typing import Final


class ImportParent(Enum):
"""
Enum with all parent imports.
"""

future = "__future__"
builtins = "builtins"
boto3 = "boto3"
botocore = "botocore"
typing = "typing"
awscrt = "awscrt"
s3transfer = "s3transfer"
aiobotocore = "aiobotocore"
aioboto3 = "aioboto3"
typing_extensions = "typing_extensions"
types = "types"
sys = "sys"

@classmethod
def is_third_party(cls, parent_name: str) -> bool:
"""
Whether import is from 3rd party module.
"""
return parent_name in _THIRD_PARTY

@classmethod
def is_builtins(cls, parent_name: str) -> bool:
"""
Whether import is from Python `builtins` module.
"""
return parent_name == cls.builtins.value


_THIRD_PARTY: Final = frozenset(
(
ImportParent.boto3.value,
ImportParent.botocore.value,
ImportParent.aioboto3.value,
ImportParent.aiobotocore.value,
ImportParent.s3transfer.value,
ImportParent.awscrt.value,
)
)
4 changes: 2 additions & 2 deletions mypy_boto3_builder/import_helpers/import_record_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
from collections.abc import Iterable, Iterator
from typing import Final

from mypy_boto3_builder.import_helpers.import_helper import Import
from mypy_boto3_builder.import_helpers.import_record import ImportRecord
from mypy_boto3_builder.import_helpers.import_string import Import


class ImportRecordGroup:
Expand All @@ -27,7 +27,7 @@ def add(self, *records: ImportRecord) -> None:
Add record to group.
"""
for record in records:
if Import.is_builtins(record.source):
if record.source.is_builtins():
continue
if record.needs_sys_fallback():
self.add(self._SYS_IMPORT_RECORD)
Expand Down
64 changes: 9 additions & 55 deletions mypy_boto3_builder/import_helpers/import_string.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

from mypy_boto3_builder.enums.service_module_name import ServiceModuleName
from mypy_boto3_builder.exceptions import BuildInternalError, StructureError
from mypy_boto3_builder.import_helpers.import_parent import ImportParent
from mypy_boto3_builder.package_data import (
Boto3StubsPackageData,
TypesAioBotocorePackageData,
Expand Down Expand Up @@ -53,13 +54,6 @@ def __init__(self, parent: str, *parts: str) -> None:

self.parts: Final[tuple[str, ...]] = tuple(all_parts)

@classmethod
def from_str(cls, import_string: str) -> Self:
"""
Create from string.
"""
return cls(*import_string.split("."))

def __str__(self) -> str:
"""
Render as a part of a valid Python import statement.
Expand Down Expand Up @@ -90,11 +84,13 @@ def __gt__(self, other: Self) -> bool:
if self == other:
return False

if self.is_local() != other.is_local():
return self.is_local() > other.is_local()
self_is_local, other_is_local = self.is_local(), other.is_local()
if self_is_local != other_is_local:
return self_is_local > other_is_local

if Import.is_third_party(self) != Import.is_third_party(other):
return Import.is_third_party(self) > Import.is_third_party(other)
self_is_third_party, other_is_third_party = self.is_third_party(), other.is_third_party()
if self_is_third_party != other_is_third_party:
return self_is_third_party > other_is_third_party

return self.parts > other.parts

Expand Down Expand Up @@ -140,7 +136,7 @@ def is_builtins(self) -> bool:
"""
Whether import is from Python `builtins` module.
"""
return Import.is_builtins(self)
return ImportParent.is_builtins(self.parent)

def is_type_defs(self) -> bool:
"""
Expand All @@ -154,52 +150,10 @@ def is_third_party(self) -> bool:
"""
Whether import is from 3rd party module.
"""
return Import.is_third_party(self)
return ImportParent.is_third_party(self.parent)

def startswith(self, other: "ImportString") -> bool:
"""
Whether import string starts with another import string.
"""
return self.parts[: len(other.parts)] == other.parts


class Import:
"""
Common import strings.
"""

future: Final = ImportString("__future__")
builtins: Final = ImportString("builtins")
boto3: Final = ImportString("boto3")
botocore: Final = ImportString("botocore")
typing: Final = ImportString("typing")
awscrt: Final = ImportString("awscrt")
s3transfer: Final = ImportString("s3transfer")
aiobotocore: Final = ImportString("aiobotocore")
aioboto3: Final = ImportString("aioboto3")
typing_extensions: Final = ImportString("typing_extensions")
types: Final = ImportString("types")
sys: Final = ImportString("sys")

_THIRD_PARTY: Final[set[str]] = {
boto3.parent,
botocore.parent,
aioboto3.parent,
aiobotocore.parent,
s3transfer.parent,
awscrt.parent,
}

@classmethod
def is_third_party(cls, import_string: ImportString) -> bool:
"""
Whether import is from 3rd party module.
"""
return import_string.parent in cls._THIRD_PARTY

@classmethod
def is_builtins(cls, import_string: ImportString) -> bool:
"""
Whether import is from Python `builtins` module.
"""
return import_string.startswith(cls.builtins)
5 changes: 2 additions & 3 deletions mypy_boto3_builder/import_helpers/internal_import_record.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
"""

from mypy_boto3_builder.enums.service_module_name import ServiceModuleName
from mypy_boto3_builder.import_helpers.import_helper import Import
from mypy_boto3_builder.import_helpers.import_record import ImportRecord
from mypy_boto3_builder.import_helpers.import_string import ImportString


class InternalImportRecord(ImportRecord):
Expand All @@ -25,6 +25,5 @@ def __init__(
name: str = "",
alias: str = "",
) -> None:
self._local_source = ImportString(service_module_name.name)
source = ImportString("", *self._local_source.parts)
source = Import.local(service_module_name.name)
super().__init__(source, name=name, alias=alias)
4 changes: 2 additions & 2 deletions mypy_boto3_builder/parsers/parse_wrapper_package.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from collections.abc import Iterable

from mypy_boto3_builder.import_helpers.import_string import ImportString
from mypy_boto3_builder.import_helpers.import_helper import Import
from mypy_boto3_builder.package_data import BasePackageData
from mypy_boto3_builder.parsers.wrapper_package_parser import WrapperPackageParser
from mypy_boto3_builder.postprocessors.aio_imports import replace_imports_with_aio
Expand Down Expand Up @@ -94,7 +94,7 @@ def parse_types_aioboto3_package(
parser = WrapperPackageParser(package)
for method in parser.get_session_client_methods():
method.return_type = TypeSubscript(
ExternalImport(ImportString("aiobotocore", "session"), "ClientCreatorContext"),
ExternalImport(Import.aiobotocore + "session", "ClientCreatorContext"),
[method.return_type],
)
package.session_class.methods.append(method)
Expand Down
10 changes: 5 additions & 5 deletions mypy_boto3_builder/parsers/wrapper_package_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from botocore.config import Config

from mypy_boto3_builder.enums.service_module_name import ServiceModuleName
from mypy_boto3_builder.import_helpers.import_string import ImportString
from mypy_boto3_builder.import_helpers.import_helper import Import
from mypy_boto3_builder.logger import get_logger
from mypy_boto3_builder.parsers.resource_loader import ResourceLoader
from mypy_boto3_builder.service_name import ServiceName
Expand Down Expand Up @@ -88,7 +88,7 @@ def get_init_client_functions(self, name: str = "client") -> list[Function]:
package_name = self.package.data.get_service_package_name(service_name)
service_name_argument = self._get_service_name_argument(service_name)
return_type = ExternalImport(
source=ImportString(package_name, ServiceModuleName.client.value),
source=Import.from_parts(package_name, ServiceModuleName.client.value),
name=service_name.get_client_name(),
)
arguments = [
Expand Down Expand Up @@ -117,7 +117,7 @@ def get_session_client_methods(self, name: str = "client") -> list[Method]:
package_name = self.package.data.get_service_package_name(service_name)
service_name_argument = self._get_service_name_argument(service_name)
return_type = ExternalImport(
source=ImportString(package_name, ServiceModuleName.client.value),
source=Import.from_parts(package_name, ServiceModuleName.client.value),
name=service_name.get_client_name(),
)
arguments = [
Expand Down Expand Up @@ -147,7 +147,7 @@ def get_init_resource_functions(self, name: str = "resource") -> list[Function]:
package_name = self.package.data.get_service_package_name(service_name)
service_name_argument = self._get_service_name_argument(service_name)
return_type = ExternalImport(
source=ImportString(package_name, ServiceModuleName.service_resource.value),
source=Import.from_parts(package_name, ServiceModuleName.service_resource.value),
name=service_name.get_service_resource_name(),
)
arguments = [
Expand Down Expand Up @@ -176,7 +176,7 @@ def get_session_resource_methods(self, name: str = "resource") -> list[Method]:
package_name = self.package.data.get_service_package_name(service_name)
service_name_argument = self._get_service_name_argument(service_name)
return_type = ExternalImport(
source=ImportString(package_name, ServiceModuleName.service_resource.value),
source=Import.from_parts(package_name, ServiceModuleName.service_resource.value),
name=service_name.get_service_resource_name(),
)
arguments = [
Expand Down
2 changes: 1 addition & 1 deletion mypy_boto3_builder/postprocessors/aio_imports.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from botocore.response import StreamingBody
from botocore.waiter import Waiter

from mypy_boto3_builder.import_helpers.import_string import Import
from mypy_boto3_builder.import_helpers.import_helper import Import
from mypy_boto3_builder.type_annotations.external_import import ExternalImport
from mypy_boto3_builder.type_annotations.fake_annotation import FakeAnnotation
from mypy_boto3_builder.utils.type_checks import is_external_import
Expand Down
2 changes: 1 addition & 1 deletion mypy_boto3_builder/postprocessors/aiobotocore.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from collections.abc import Iterable, Iterator
from typing import Final

from mypy_boto3_builder.import_helpers.import_string import Import
from mypy_boto3_builder.import_helpers.import_helper import Import
from mypy_boto3_builder.postprocessors.aio_imports import replace_imports_with_aio
from mypy_boto3_builder.postprocessors.base import BasePostprocessor
from mypy_boto3_builder.structures.argument import Argument
Expand Down
4 changes: 2 additions & 2 deletions mypy_boto3_builder/structures/collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from collections.abc import Iterator

from mypy_boto3_builder.constants import SERVICE_RESOURCE
from mypy_boto3_builder.import_helpers.import_string import ImportString
from mypy_boto3_builder.import_helpers.import_helper import Import
from mypy_boto3_builder.service_name import ServiceName
from mypy_boto3_builder.structures.class_record import ClassRecord
from mypy_boto3_builder.type_annotations.external_import import ExternalImport
Expand All @@ -34,7 +34,7 @@ def __init__(
use_alias=True,
bases=[
ExternalImport(
ImportString("boto3", "resources", "collection"),
Import.boto3 + "resources" + "collection",
"ResourceCollection",
)
],
Expand Down
4 changes: 2 additions & 2 deletions mypy_boto3_builder/structures/paginator.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

from mypy_boto3_builder.enums.service_module_name import ServiceModuleName
from mypy_boto3_builder.exceptions import BuildInternalError
from mypy_boto3_builder.import_helpers.import_string import ImportString
from mypy_boto3_builder.import_helpers.import_helper import Import
from mypy_boto3_builder.service_name import ServiceName
from mypy_boto3_builder.structures.argument import Argument
from mypy_boto3_builder.structures.class_record import ClassRecord
Expand Down Expand Up @@ -96,7 +96,7 @@ def get_client_method(self) -> Method:
),
],
return_type=ExternalImport(
source=ImportString("", ServiceModuleName.paginator.value),
source=Import.local(ServiceModuleName.paginator.value),
name=self.name,
),
type_ignore="override",
Expand Down
4 changes: 2 additions & 2 deletions mypy_boto3_builder/structures/resource_record.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from collections.abc import Iterator
from typing import TYPE_CHECKING

from mypy_boto3_builder.import_helpers.import_string import ImportString
from mypy_boto3_builder.import_helpers.import_helper import Import
from mypy_boto3_builder.service_name import ServiceName
from mypy_boto3_builder.structures.class_record import ClassRecord
from mypy_boto3_builder.type_annotations.external_import import ExternalImport
Expand All @@ -25,7 +25,7 @@ class ResourceRecord(ClassRecord):
def __init__(self, name: str, service_name: ServiceName) -> None:
super().__init__(
name=name,
bases=[ExternalImport(ImportString("boto3", "resources", "base"), "ServiceResource")],
bases=[ExternalImport(Import.boto3 + "resources" + "base", "ServiceResource")],
use_alias=True,
)
self.service_name: ServiceName = service_name
Expand Down
Loading

0 comments on commit 33287b7

Please sign in to comment.