dependency-injection-pattern 0.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,22 @@
1
+ # pragma: no cover
2
+ from typing import overload
3
+
4
+ from di.core.helpers import get_service_name
5
+
6
+ class ProvideException(Exception):
7
+ """
8
+ The ProvideException is raised when provider cannot provide service.
9
+ """
10
+
11
+ @overload
12
+ def __init__(self, service: type | str) -> None:
13
+ ...
14
+ @overload
15
+ def __init__(self, service: type | str, reason: str) -> None:
16
+ ...
17
+ def __init__(self, service: type | str, reason: str | None = None):
18
+ service = get_service_name(service)
19
+ if reason:
20
+ super().__init__(f"Cannot provide service '{service}': {reason}")
21
+ else:
22
+ super().__init__(f"Cannot provide service '{service}'")
@@ -0,0 +1,9 @@
1
+ # pragma: no cover
2
+ class SealException(Exception):
3
+ """
4
+ The SealException is raised when container is being sealed and a preliminary check reveals that one or more
5
+ services cannot be provided. This could be due to a singleton service depending on a transient or scoped service which
6
+ isn't allowed..
7
+ """
8
+ def __init__(self, msg: str):
9
+ super().__init__(msg)
@@ -0,0 +1,38 @@
1
+ from typing import Any, cast
2
+ from typingutils import get_optional_type
3
+
4
+ from di.core.helpers import get_provided_service_from_annotation
5
+ from di.core.reflection.undefined import Undefined
6
+
7
+ class Dependency:
8
+ __slots__ = [ "__name", "__service", "__factory", "__optional", "__default" ]
9
+
10
+ def __init__(self, name: str, service: type[Any], default: Any ):
11
+ self.__name = name
12
+ service, self.__optional = cast(tuple[type[Any], bool], get_optional_type(service))
13
+ self.__service, self.__factory = cast(tuple[type[Any], bool], get_provided_service_from_annotation(service))
14
+ self.__default = default
15
+
16
+ @property
17
+ def name(self) -> str:
18
+ return self.__name # pragma: no cover
19
+
20
+ @property
21
+ def service(self) -> type[Any]:
22
+ return self.__service
23
+
24
+ @property
25
+ def is_optional(self) -> bool:
26
+ return self.__optional
27
+
28
+ @property
29
+ def is_factory(self) -> bool:
30
+ return self.__factory
31
+
32
+ @property
33
+ def has_default(self) -> bool:
34
+ return self.__default is not Undefined
35
+
36
+ @property
37
+ def default(self) -> Any:
38
+ return self.__default # pragma: no cover
@@ -0,0 +1,105 @@
1
+ from typing import TypeVar, Callable, Generic, Any, cast
2
+ from typingutils import get_optional_type, issubclass_typing, isinstance_typing
3
+
4
+ from di.core.reflection import Undefined, ParameterKind, reflect_function, get_constructor
5
+ from di.core.scope import Scope
6
+ from di.core.named_service import NamedService
7
+ from di.core.service_request import ServiceRequest
8
+
9
+ from di.core.exceptions.implementation_exception import ImplementationException
10
+ from di.core.exceptions.factory_provide_exception import FactoryProvideException
11
+ from di.core.exceptions.provide_exception import ProvideException
12
+ from di.core.protocols.container import Container
13
+ from di.core.factories.dependency import Dependency
14
+
15
+ T = TypeVar('T')
16
+
17
+ class Factory(Generic[T]):
18
+ __slots__ = ["__container", "__service", "__implementation", "__ctor", "__dependencies"]
19
+
20
+ def __init__(self, container: Container, service: type[T], implementation: type[T] | Callable[..., T] | T | None = None):
21
+ self.__container = container
22
+ self.__service = service
23
+ self.__implementation = service if implementation is None else implementation
24
+ self.__dependencies: dict[str, Dependency] = {}
25
+
26
+ if not implementation:
27
+ if hasattr(service, "__origin__"):
28
+ sig = reflect_function(getattr(service, "__call__"), service)
29
+ else:
30
+ sig = get_constructor(service)
31
+ elif isinstance(implementation, type):
32
+ sig = get_constructor(cast(type, implementation))
33
+ if not service is NamedService and not issubclass_typing(implementation, service):
34
+ raise ImplementationException(service, implementation, "Implementation class is not derived from service")
35
+ elif implementation is service:
36
+ raise ImplementationException(service, implementation, "Implementation equals service")
37
+ elif isinstance_typing(implementation, service, recursive=True):
38
+ sig = None
39
+ elif callable(implementation):
40
+ sig = reflect_function(implementation)
41
+ if sig.return_type:
42
+ implementation_type, _ = get_optional_type(sig.return_type)
43
+ else:
44
+ implementation_type = None
45
+
46
+ if service is NamedService:
47
+ pass
48
+ elif not implementation_type:
49
+ raise ImplementationException(service, implementation, "Implementation is missing return annotation")
50
+ elif not issubclass_typing(implementation_type, service):
51
+ raise ImplementationException(service, implementation, "Implementation does not resolve into a class derived from service")
52
+ elif service is NamedService:
53
+ sig = None
54
+ else:
55
+ raise ImplementationException(service, implementation, "Implementation does not resolve into a class derived from service")
56
+
57
+ if sig != None:
58
+ parameters = [ p for p in sig.parameters if p.kind == ParameterKind.POSITIONAL_OR_KEYWORD ]
59
+ missing_annotations = [ p.name for p in parameters if not p.parameter_type ]
60
+ self.__dependencies = { p.name: Dependency(p.name, p.parameter_type, p.default) for p in parameters }
61
+
62
+ if len(missing_annotations) > 0:
63
+ parameters_missing_ann = ", ".join([f"'{p}'" for p in missing_annotations])
64
+ raise ImplementationException(service, implementation, f"Parameter(s) {parameters_missing_ann} missing annotation")
65
+
66
+ def ctor(scope: Scope | None = None) -> T:
67
+ provider = container.provider()
68
+ try:
69
+ args = [
70
+ provider._provide( # pyright: ignore[reportPrivateUsage]
71
+ ServiceRequest(
72
+ p.name,
73
+ cast(type[T], p.parameter_type),
74
+ None if p.default is Undefined else p.default
75
+ ),
76
+ scope
77
+ ) for p in parameters
78
+ ]
79
+ return cast(Callable[[Any], T], self.__implementation)(*args)
80
+ except ProvideException as ex:
81
+ failed_args = {
82
+ p.name: cast(type, p.parameter_type)
83
+ for p in parameters
84
+ if not provider.provides(cast(type, p.parameter_type))
85
+ }
86
+ raise FactoryProvideException(service, failed_args) from ex
87
+
88
+ self.__ctor = ctor
89
+
90
+ @property
91
+ def container(self) -> Container:
92
+ return self.__container # pragma: no cover
93
+
94
+ @property
95
+ def service(self) -> type[T]:
96
+ return self .__service
97
+
98
+ @property
99
+ def dependencies(self) -> dict[str, Dependency]:
100
+ return self.__dependencies
101
+
102
+ def provide(self, scope: Scope | None = None) -> T:
103
+ return self.__ctor(scope)
104
+
105
+
@@ -0,0 +1,18 @@
1
+
2
+ from typing import TypeVar, Callable
3
+
4
+ from di.core.scope import Scope
5
+ from di.core.factories.factory import Factory
6
+ from di.core.protocols.container import Container
7
+
8
+ T = TypeVar('T')
9
+
10
+ class ScopedFactory(Factory[T]):
11
+ __slots__ = []
12
+
13
+ def __init__(self, container: Container, service: type[T], implementation: type[T] | Callable[..., T] | None = None):
14
+ super().__init__(container, service, implementation)
15
+
16
+ def provide(self, scope: Scope | None = None) -> T:
17
+ scope = scope or self.container.default_scope
18
+ return scope.provide(self.service, lambda : Factory[T].provide(self, scope))
@@ -0,0 +1,32 @@
1
+ from typing import TypeVar, Callable, cast
2
+ from typingutils import is_type, isinstance_typing
3
+
4
+ from di.core.log import LOG
5
+ from di.core.helpers import get_service_name
6
+ from di.core.scope import Scope
7
+ from di.core.named_service import NamedService
8
+ from di.core.factories.factory import Factory
9
+ from di.core.protocols.container import Container
10
+
11
+ T = TypeVar('T')
12
+
13
+ class SingletonFactory(Factory[T]):
14
+ __slots__ = ["__inst"]
15
+
16
+ def __init__(self, container: Container, service: type[T], implementation: type[T] | Callable[..., T] | T | None = None):
17
+ super().__init__(container, service, implementation)
18
+
19
+ if implementation and is_type(service) and isinstance_typing(implementation, service, recursive=True):
20
+ self.__inst: T | None = cast(T, implementation)
21
+ elif callable(implementation):
22
+ self.__inst: T | None = None
23
+ elif service is NamedService:
24
+ self.__inst: T | None = implementation
25
+ else:
26
+ self.__inst: T | None = None
27
+
28
+ def provide(self, scope: Scope | None = None) -> T:
29
+ if self.__inst is None:
30
+ LOG.debug(f"Creating singleton object for service '{get_service_name(self.service)}'")
31
+ self.__inst = super().provide(scope)
32
+ return self.__inst
@@ -0,0 +1,17 @@
1
+ from typing import TypeVar, Callable
2
+
3
+ from di.core.scope import Scope
4
+ from di.core.factories.factory import Factory
5
+ from di.core.protocols.container import Container
6
+
7
+ T = TypeVar('T')
8
+
9
+ class TransientFactory(Factory[T]):
10
+ __slots__ = []
11
+
12
+ def __init__(self, container: Container, service: type[T], implementation: type[T] | Callable[..., T] | None = None):
13
+ super().__init__(container, service, implementation)
14
+
15
+ def provide(self, scope: Scope | None = None) -> T:
16
+ return Factory[T].provide(self, scope)
17
+
di/core/factory.py ADDED
@@ -0,0 +1,24 @@
1
+ from typing import TypeVar, Generic
2
+
3
+ from di.core.scope import Scope
4
+
5
+ T = TypeVar("T")
6
+
7
+ class Factory(Generic[T]):
8
+ """
9
+ The Factory[T] class is used to get the Provider to provide a factory instead of a service implementation ie. a lazy implementation.
10
+
11
+ Example:
12
+ class SomeClass:
13
+ def __init__(self, service: Factory[Service]):
14
+ svc = service() # => Service
15
+ """
16
+
17
+ def __new__(cls):
18
+ raise Exception("The Factory class is not intended for instantation") # pragma: no cover
19
+
20
+ def provide(self, scope: Scope | None = None) -> T: # pragma: no cover
21
+ raise NotImplementedError
22
+
23
+ def __call__(self, scope: Scope | None = None) -> T: # pragma: no cover
24
+ raise NotImplementedError
di/core/helpers.py ADDED
@@ -0,0 +1,51 @@
1
+ from typing import MutableMapping, Protocol, TypeVar, cast, runtime_checkable
2
+ from di.core.factory import Factory
3
+ from types import TracebackType
4
+ from typingutils import AnyType, issubclass_typing, get_type_name
5
+
6
+ from di.core.factory import Factory
7
+
8
+
9
+ T = TypeVar('T', covariant=True)
10
+
11
+ @runtime_checkable
12
+ class ContextManager(Protocol[T]): # pragma: no cover
13
+ def __enter__(self) -> T: ...
14
+ def __exit__(self, __exc_type: type[BaseException] | None, __exc_value: BaseException | None, __traceback: TracebackType | None) -> None: ...
15
+
16
+
17
+ def get_service_name(service: AnyType | str) -> str: # pragma: no cover
18
+ if isinstance(service, str):
19
+ return service
20
+ elif hasattr(service, "__name__"):
21
+ return getattr(service, "__name__")
22
+ else:
23
+ return get_type_name(service)
24
+
25
+ def clean_service_name(service: str) -> str:
26
+ return service.lower()
27
+
28
+ def get_provided_service_from_annotation(annotation: AnyType) -> tuple[AnyType, bool]:
29
+ if issubclass_typing(annotation, Factory):
30
+ return cast(tuple[type], getattr(annotation, "__args__"))[0], True
31
+ else:
32
+ return annotation, False
33
+
34
+
35
+ __CONTEXT_SERVICES__: MutableMapping[type, bool] = {}
36
+
37
+ def is_context(cls: type) -> bool:
38
+ if not cls in __CONTEXT_SERVICES__:
39
+ # reflection = reflect_class(cls)
40
+
41
+ # if "__enter__" in reflection.functions and "__exit__" in reflection.functions:
42
+ # result = reflection.functions["__enter__"].return_type is cls
43
+ # else:
44
+ # result = False
45
+ if issubclass(cls, ContextManager):
46
+ result = True
47
+ else:
48
+ result = False
49
+
50
+ __CONTEXT_SERVICES__[cls] = result
51
+ return __CONTEXT_SERVICES__[cls]
di/core/log.py ADDED
@@ -0,0 +1,4 @@
1
+ from logging import getLogger, DEBUG
2
+
3
+ LOG = getLogger("dependency-injection")
4
+ LOG.setLevel(DEBUG)
@@ -0,0 +1,3 @@
1
+ class NamedService():
2
+ def __new__(cls):
3
+ raise Exception("The NamedService is a special class not meant to be instantiated") # pragma: no cover
@@ -0,0 +1,25 @@
1
+ from typing import Protocol, TypeVar, runtime_checkable
2
+
3
+ from di.core.protocols.provider import Provider
4
+ from di.core.protocols.factory import Factory
5
+ from di.core.scope import Scope
6
+ from di.core.service_request import ServiceRequest
7
+
8
+
9
+ T = TypeVar("T")
10
+
11
+ @runtime_checkable
12
+ class Container(Protocol): # pragma: no cover
13
+
14
+ @property
15
+ def default_scope(self) -> Scope:
16
+ ...
17
+
18
+ def provider(self) -> Provider:
19
+ ...
20
+
21
+ def _defines(self, service: str | type) -> bool:
22
+ ...
23
+
24
+ def _get(self, service: type[T] | ServiceRequest[T]) -> Factory[T] | T | None:
25
+ ...
@@ -0,0 +1,7 @@
1
+ from typing import Protocol, TypeVar, Generic, runtime_checkable
2
+
3
+ T = TypeVar("T", covariant=True)
4
+
5
+ @runtime_checkable
6
+ class Factory(Generic[T], Protocol): # pragma: no cover
7
+ ...
@@ -0,0 +1,24 @@
1
+ from typing import Protocol, Any, TypeVar, overload, runtime_checkable
2
+
3
+ from di.core.scope import Scope
4
+ from di.core.service_request import ServiceRequest
5
+
6
+ T = TypeVar("T")
7
+
8
+ @runtime_checkable
9
+ class Provider(Protocol): # pragma: no cover
10
+
11
+ def provides(self, service: str | type[Any]) -> bool:
12
+ ...
13
+
14
+ @overload
15
+ def provide(self, service: type[T]) -> T:
16
+ ...
17
+ @overload
18
+ def provide(self, service: type[T], scope: Scope) -> T:
19
+ ...
20
+ def provide(self, service: type[T], scope: Scope | None = None) -> T:
21
+ ...
22
+
23
+ def _provide(self, service: type[T] | ServiceRequest[T], scope: Scope | None = None) -> T:
24
+ ...
di/core/provider.py ADDED
@@ -0,0 +1,85 @@
1
+ from typing import TypeVar, Any, cast, overload
2
+ from typingutils import issubclass_typing, get_optional_type
3
+
4
+ from di.core.exceptions.factory_provide_exception import FactoryProvideException
5
+ from di.core.scope import Scope
6
+ from di.core.factory import Factory as PublicFactory
7
+ from di.core.factories.factory import Factory
8
+ from di.core.service_request import ServiceRequest
9
+ from di.core.protocols.container import Container
10
+
11
+ T = TypeVar('T')
12
+
13
+ class Provider:
14
+ """
15
+ The Provider is connected to the Container and provides the services defined.
16
+ """
17
+ __slots__ = ["__container"]
18
+
19
+ def __init__(self, container: Container):
20
+ self.__container = container
21
+
22
+
23
+ def provides(self, service: str | type[Any]) -> bool:
24
+ """
25
+ Indicates whether or not the specified service can be provided.
26
+
27
+ Args:
28
+ service (str | type[Any]) The service interface or name.
29
+
30
+ Returns:
31
+ bool: Returns True if specified service can be provided.
32
+ """
33
+ return self.__container._defines(service) # pyright: ignore[reportPrivateUsage]
34
+
35
+ @overload
36
+ def provide(self, service: type[T]) -> T:
37
+ """
38
+ Provides the specified service.
39
+
40
+ Args:
41
+ service (type[Any]) The service interface.
42
+
43
+ """
44
+ ...
45
+ @overload
46
+ def provide(self, service: type[T], scope: Scope) -> T:
47
+ """
48
+ Provides the specified service.
49
+
50
+ Args:
51
+ service (type[Any]) The service interface.
52
+ scope (Scope) A custom scope.
53
+ """
54
+ ...
55
+ def provide(self, service: type[T], scope: Scope | None = None) -> T:
56
+ return self._provide(service, scope)
57
+
58
+
59
+ def _provide(self, service: type[T] | ServiceRequest[T], scope: Scope | None = None) -> T:
60
+ scope = scope or self.__container.default_scope
61
+ svc_type = service.type if isinstance(service, ServiceRequest) else service
62
+ svc_type, is_optional = get_optional_type(svc_type)
63
+
64
+ if svc_type and issubclass_typing(svc_type, PublicFactory):
65
+ def factory() -> T:
66
+ return self._provide(cast(type[T], getattr(svc_type, "__args__")[0]))
67
+ return factory # pyright: ignore[reportReturnType]
68
+ else:
69
+ result = self.__container._get(cast(type[T], service)) # pyright: ignore[reportPrivateUsage]
70
+
71
+ if result == None:
72
+ # optional requirements may return None
73
+ if is_optional:
74
+ return None # pyright: ignore[reportReturnType]
75
+ else:
76
+ raise FactoryProvideException(svc_type) # pragma: no cover
77
+
78
+ elif isinstance(result, Factory):
79
+ result = cast(T | None, result.provide(scope))
80
+ if result or is_optional:
81
+ return cast(T, result)
82
+ else:
83
+ raise FactoryProvideException(svc_type)
84
+ else:
85
+ return cast(T, result)
@@ -0,0 +1,126 @@
1
+ from typing import Any, cast
2
+ from typingutils import AnyFunction
3
+ from types import FrameType, MethodType
4
+ from sys import modules
5
+ from inspect import Parameter as InspectParameter, FrameInfo, signature as get_signature, stack, unwrap
6
+
7
+ from di.core.reflection.undefined import Undefined
8
+ from di.core.reflection.signature import Signature
9
+ from di.core.reflection.parameter import Parameter
10
+ from di.core.reflection.parameter_kind import ParameterKind
11
+ from di.core.reflection.parameter_mapper import ParameterMapper
12
+
13
+
14
+ def resolve(
15
+ annotation: str,
16
+ globals: dict[str, Any] | None = None,
17
+ builtins: dict[str, Any] | None = None,
18
+ locals: dict[str, Any] | None = None
19
+ ) -> Any:
20
+ if globals: # pragma: no cover
21
+ globals = { **globals , **(builtins or __builtins__)}
22
+
23
+ try:
24
+ result = eval(annotation, globals, locals)
25
+ return result
26
+ except:
27
+ pass
28
+
29
+ # fallback
30
+ for frame in stack()[1:]: # pragma: no cover
31
+ if frame.filename == __file__:
32
+ continue
33
+
34
+ globals = { **frame.frame.f_globals , **frame.frame.f_builtins}
35
+ locals = frame.frame.f_locals
36
+
37
+ try:
38
+ return eval(annotation, globals, locals)
39
+ except:
40
+ pass
41
+
42
+ raise Exception(f"Unable to resolve {annotation}") # pragma: no cover
43
+
44
+
45
+
46
+
47
+ def get_frame(fn: Any, stack: list[FrameInfo], cls: Any | None) -> FrameType | None: # pragma: no cover
48
+ module = None
49
+
50
+ if hasattr(fn, "__module__"):
51
+ module = modules[getattr(fn, "__module__")]
52
+ elif cls and hasattr(cls, "__module__"):
53
+ module = modules[getattr(cls, "__module__")]
54
+
55
+ if module and hasattr(module, "__file__"):
56
+ for frame in stack:
57
+ if frame.filename == module.__file__:
58
+ frame_locals = frame.frame.f_locals.values()
59
+ if cls is not None and cls in frame_locals:
60
+ return frame.frame
61
+ elif fn in frame_locals:
62
+ return frame.frame
63
+
64
+
65
+ def reflect_function(fn: AnyFunction, cls: object | None = None) -> Signature:
66
+ fn = unwrap(fn)
67
+ sig = get_signature(fn)
68
+
69
+ if hasattr(fn, "__self__") and ( self := getattr(fn, "__self__") ):
70
+ cls = self
71
+
72
+ parameters = list(sig.parameters.values())
73
+ globals: dict[str, Any] | None = getattr(fn, "__globals__") if hasattr(fn, "__globals__") else None
74
+ builtins: dict[str, Any] | None = getattr(fn, "__builtins__") if hasattr(fn, "__builtins__") else None
75
+ locals: dict[str, Any] | None = None
76
+
77
+ if frame := get_frame(fn, stack()[1:], cls): # pragma: no cover
78
+ locals = frame.f_locals
79
+
80
+ if parameters:
81
+ first_param = parameters[0].name.lower()
82
+
83
+ if isinstance(fn, MethodType) and first_param in ("self", "cls"):
84
+ parameters = parameters[1:] # pragma: no cover
85
+ elif first_param in ("self", "cls") and hasattr(fn, "__self__"):
86
+ parameters = parameters[1:] # pragma: no cover
87
+ elif first_param == "self":
88
+ if hasattr(fn, "__call__") and ( call := getattr(fn, "__call__") ): # pragma: no cover
89
+ if hasattr(call, "__text_signature__") and ( text_sig := getattr(call, "__text_signature__") ):
90
+ if cast(str, text_sig).startswith("($self"):
91
+ parameters = parameters[1:]
92
+
93
+ for index, parameter in enumerate(parameters):
94
+ changed = False
95
+
96
+ if isinstance(parameter.annotation, str):
97
+ parameter_type = resolve(parameter.annotation, globals, builtins, locals)
98
+ parameter = parameter.replace(annotation = parameter_type)
99
+ changed = True
100
+
101
+ if changed:
102
+ parameters[index] = parameter
103
+
104
+ if sig.return_annotation is InspectParameter.empty:
105
+ return_type = Undefined
106
+ elif isinstance(sig.return_annotation, str):
107
+ return_type = resolve(sig.return_annotation, globals, builtins, locals)
108
+ else:
109
+ return_type = sig.return_annotation
110
+
111
+ return Signature(
112
+ ParameterMapper(
113
+ [
114
+ Parameter(
115
+ p.name,
116
+ ParameterKind(p.kind),
117
+ Undefined if p.annotation is InspectParameter.empty else p.annotation,
118
+ Undefined if p.default is InspectParameter.empty else p.default
119
+ ) for p in parameters
120
+ ]
121
+ ), return_type
122
+ )
123
+
124
+
125
+ def get_constructor(cls: type[Any]) -> Signature:
126
+ return reflect_function(getattr(cls, "__init__"), cls)
@@ -0,0 +1,66 @@
1
+ from typing import Any, cast
2
+ from typingutils import get_type_name
3
+ from inspect import Parameter as InspectParameter
4
+
5
+ from di.core.reflection.undefined import Undefined
6
+ from di.core.reflection.parameter_kind import ParameterKind
7
+
8
+ class Parameter:
9
+ __slots__ = ["__name", "__kind", "__doc", "__type", "__default"]
10
+
11
+ def __init__(
12
+ self,
13
+ name: str,
14
+ kind: ParameterKind,
15
+ parameter_type: type[Any],
16
+ default: Any
17
+ ):
18
+ self.__name = name
19
+ self.__kind = kind
20
+ self.__type = parameter_type
21
+ self.__default = default
22
+
23
+ @property
24
+ def name(self) -> str:
25
+ """The parameter name
26
+ """
27
+ return self.__name
28
+
29
+ @property
30
+ def kind(self) -> ParameterKind:
31
+ """The parameter kind
32
+ """
33
+ return self.__kind
34
+
35
+ @property
36
+ def parameter_type(self) -> type[Any]:
37
+ """The parameter type
38
+ """
39
+ return self.__type
40
+
41
+ @property
42
+ def default(self) -> Any:
43
+ """The parameter default
44
+ """
45
+ return self.__default
46
+
47
+ def __repr__(self) -> str:
48
+ str_type = f": {get_type_name(cast(type, self.__type))}" if self.__type and self.__type != Undefined else ""
49
+ str_default = f"={self.__default}" if self.__default else ""
50
+ return f"{self.__name}{str_type}{str_default}"
51
+
52
+ def __eq__(self, o: object) -> bool: # pragma: no cover
53
+ if isinstance(o, Parameter):
54
+ return (
55
+ self.name == o.name
56
+ and self.kind == o.kind
57
+ and self.parameter_type == o.parameter_type
58
+ )
59
+ elif isinstance(o, InspectParameter):
60
+ return (
61
+ self.name == o.name
62
+ and cast(int, self.kind) == o.kind
63
+ and self.parameter_type == o.annotation
64
+ )
65
+
66
+ return False