diff --git a/src/attr/__init__.py b/src/attr/__init__.py index 5c6e0650b..11215c3d1 100644 --- a/src/attr/__init__.py +++ b/src/attr/__init__.py @@ -7,7 +7,7 @@ from functools import partial from typing import Callable, Literal, Protocol -from . import converters, exceptions, filters, setters, validators +from . import exceptions, filters, setters from ._cmp import cmp_using from ._config import get_run_validators, set_run_validators from ._funcs import asdict, assoc, astuple, has, resolve_types @@ -78,6 +78,9 @@ class AttrsInstance(Protocol): ] +_LAZY_SUBMODULES = {"converters", "validators"} + + def _make_getattr(mod_name: str) -> Callable: """ Create a metadata proxy for packaging information that uses *mod_name* in @@ -85,6 +88,13 @@ def _make_getattr(mod_name: str) -> Callable: """ def __getattr__(name: str) -> str: + if name in _LAZY_SUBMODULES: + import importlib + + mod = importlib.import_module(f".{name}", mod_name) + globals()[name] = mod + return mod + if name not in ("__version__", "__version_info__"): msg = f"module {mod_name} has no attribute {name}" raise AttributeError(msg) diff --git a/src/attr/_compat.py b/src/attr/_compat.py index bc68ed9ea..e25a4a87a 100644 --- a/src/attr/_compat.py +++ b/src/attr/_compat.py @@ -1,6 +1,5 @@ # SPDX-License-Identifier: MIT -import inspect import platform import sys import threading @@ -46,6 +45,8 @@ class _AnnotationExtractor: __slots__ = ["sig"] def __init__(self, callable): + import inspect + try: self.sig = inspect.signature(callable) except (ValueError, TypeError): # inspect failed @@ -55,6 +56,8 @@ def get_first_param_type(self): """ Return the type annotation of the first argument if it's not empty. """ + import inspect + if not self.sig: return None @@ -68,6 +71,8 @@ def get_return_type(self): """ Return the return type if it's not empty. """ + import inspect + if ( self.sig and self.sig.return_annotation is not inspect.Signature.empty diff --git a/src/attr/_make.py b/src/attr/_make.py index 793bfd89d..89852f351 100644 --- a/src/attr/_make.py +++ b/src/attr/_make.py @@ -6,7 +6,6 @@ import contextlib import copy import enum -import inspect import itertools import linecache import sys @@ -705,6 +704,8 @@ def __init__( if self._has_pre_init: # Check if the pre init method has more arguments than just `self` # We want to pass arguments if pre init expects arguments + import inspect + pre_init_func = cls.__attrs_pre_init__ pre_init_signature = inspect.signature(pre_init_func) self._pre_init_has_args = len(pre_init_signature.parameters) > 1 @@ -920,6 +921,8 @@ def _create_slots_class(self): # To know to update them. additional_closure_functions_to_update = [] if cached_properties: + import inspect + class_annotations = _get_annotations(self._cls) for name, func in cached_properties.items(): # Add cached properties to names for slotting. diff --git a/src/attrs/__init__.py b/src/attrs/__init__.py index dc1ce4b97..66e740aad 100644 --- a/src/attrs/__init__.py +++ b/src/attrs/__init__.py @@ -25,7 +25,7 @@ from attr._make import ClassProps from attr._next_gen import asdict, astuple, inspect -from . import converters, exceptions, filters, setters, validators +from . import exceptions, filters, setters __all__ = [