Skip to content

Commit 493776a

Browse files
committed
improve type hints
1 parent 63467ed commit 493776a

File tree

8 files changed

+90
-65
lines changed

8 files changed

+90
-65
lines changed

objinspect/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import inspect as _inspect
22
from collections.abc import Callable
3+
from typing import Any
34

45
from objinspect._class import Class
56
from objinspect.function import Function
@@ -76,7 +77,7 @@ def inspect(
7677
)
7778

7879

79-
def get_class_from_method(method: Callable):
80+
def get_class_from_method(method: Callable[..., Any]) -> type | None:
8081
qualname = method.__qualname__
8182
module = _inspect.getmodule(method)
8283
if "." in qualname:

objinspect/_class.py

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -45,23 +45,23 @@ class Class:
4545

4646
def __init__(
4747
self,
48-
cls,
49-
init=True,
50-
public=True,
51-
inherited=True,
52-
static_methods=True,
53-
protected=False,
54-
private=False,
55-
classmethod=True,
56-
skip_self=True,
48+
cls: type | object,
49+
init: bool = True,
50+
public: bool = True,
51+
inherited: bool = True,
52+
static_methods: bool = True,
53+
protected: bool = False,
54+
private: bool = False,
55+
classmethod: bool = True,
56+
skip_self: bool = True,
5757
) -> None:
5858
self.cls = cls
5959
self.is_initialized = False
6060
self.skip_self = skip_self
6161
self.receieved_instance = False
6262

6363
try:
64-
self.name: str = self.cls.__name__
64+
self.name: str = getattr(self.cls, "__name__", str(self.cls))
6565
except AttributeError:
6666
self.receieved_instance = True
6767
self.name = f"{self.cls.__class__.__name__} instance"
@@ -90,10 +90,10 @@ def __repr__(self) -> str:
9090
return f"{self.__class__.__name__}(name='{self.name}', methods={len(self._methods)}, has_init={self.has_init}, description={self.description})"
9191

9292
@functools.cached_property
93-
def _class_base(self):
93+
def _class_base(self) -> type:
9494
if self.is_initialized:
95-
return self.cls.__class__
96-
return self.cls
95+
return self.cls.__class__ if hasattr(self.cls, "__class__") else type(self.cls)
96+
return self.cls # type: ignore[return-value]
9797

9898
def _find_methods(self) -> dict[str, Method]:
9999
method_filter = MethodFilter(**self.extractor_kwargs)
@@ -106,7 +106,7 @@ def _find_methods(self) -> dict[str, Method]:
106106
methods[method.name] = method
107107
return methods
108108

109-
def init(self, *args, **kwargs) -> None:
109+
def init(self, *args: Any, **kwargs: Any) -> None:
110110
"""
111111
Initializes the class as an instance using the provided arguments.
112112
@@ -116,10 +116,13 @@ def init(self, *args, **kwargs) -> None:
116116
"""
117117
if self.is_initialized:
118118
raise ValueError(f"Class {self.cls} is already initialized")
119-
self.instance = self.cls(*args, **kwargs)
119+
if callable(self.cls):
120+
self.instance = self.cls(*args, **kwargs)
121+
else:
122+
raise TypeError(f"Cannot initialize object of type {type(self.cls)}")
120123
self.is_initialized = True
121124

122-
def call_method(self, method: str | int, *args, **kwargs) -> Any:
125+
def call_method(self, method: str | int, *args: Any, **kwargs: Any) -> Any:
123126
"""
124127
Calls the specified method on the class or instance.
125128
@@ -160,7 +163,7 @@ def get_method(self, method: str | int) -> Method:
160163
raise TypeError(type(method))
161164

162165
@property
163-
def init_method(self):
166+
def init_method(self) -> Method | None:
164167
try:
165168
return self.get_method("__init__")
166169
except KeyError:
@@ -188,11 +191,16 @@ def dict(self) -> dict[str, Any]:
188191
}
189192

190193
def as_str(
191-
self, *, color: bool = True, indent: int = 2, theme: ClassStrTheme | None = None
194+
self,
195+
*,
196+
color: bool = True,
197+
indent: int = 2,
198+
theme: ClassStrTheme | None = None,
192199
) -> str:
193200
if theme is None:
194201
theme = ClassStrTheme()
195202

203+
string: str
196204
if color:
197205
string = colored("class", theme.class_kw) + " " + colored(self.name, theme.name) + ":"
198206
else:
@@ -202,7 +210,7 @@ def as_str(
202210
if color:
203211
string += "\n" + colored(self.description, theme.description)
204212
else:
205-
string += "\n" + self.description
213+
string += "\n" + str(self.description)
206214
if not len(self.methods):
207215
return string
208216

@@ -211,7 +219,11 @@ def as_str(
211219
return string
212220

213221

214-
def split_init_args(args: dict, cls: Class, method: Method) -> tuple[dict, dict]:
222+
def split_init_args(
223+
args: dict[str, Any],
224+
cls: Class,
225+
method: Method,
226+
) -> tuple[dict[str, Any], dict[str, Any]]:
215227
"""
216228
Split the arguments into those that should be passed to the __init__ method
217229
and those that should be passed to the method call.

objinspect/function.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ class Function:
5656
5757
"""
5858

59-
def __init__(self, func: Callable, skip_self: bool = True) -> None:
59+
def __init__(self, func: Callable[..., Any], skip_self: bool = True) -> None:
6060
self.func = func
6161
self.skip_self = skip_self
6262
self.name: str = self.func.__name__
@@ -113,7 +113,7 @@ def get_param(self, arg: str | int) -> Parameter:
113113
case _:
114114
raise TypeError(type(arg))
115115

116-
def call(self, *args, **kwargs) -> Any:
116+
def call(self, *args: Any, **kwargs: Any) -> Any:
117117
"""
118118
Calls the function and returns the result of its call.
119119
@@ -161,27 +161,28 @@ def as_str(
161161
if theme is None:
162162
theme = FunctionStrTheme()
163163

164-
name_str = self.name if not color else colored(self.name, theme.name)
165-
params = ", ".join([i.as_str(color=color) for i in self.params])
164+
name_str: str = self.name if not color else colored(self.name, theme.name)
165+
params: str = ", ".join([i.as_str(color=color) for i in self.params])
166166
if color:
167167
params = colored("(", theme.bracket) + params + colored(")", theme.bracket)
168168

169-
if self.return_type is not EMPTY:
170-
return_str = type_name(self.return_type)
169+
if self.return_type is not EMPTY and self.return_type is not None: # type: ignore[comparison-overlap]
170+
return_str: str = type_name(self.return_type)
171171
if color:
172172
return_str = colored(return_str, theme.ret)
173173
return_str = " -> " + return_str
174174
else:
175175
return_str = ""
176176

177-
string = f"{name_str}{params}{return_str}"
177+
string: str = f"{name_str}{params}{return_str}"
178178

179179
if description and self.description:
180180
string = ansi_ljust(string, ljust)
181181
description_str = f" # {self.description}"
182182
if color:
183183
description_str = colored(description_str, theme.description)
184-
return string + description_str
184+
string += description_str
185+
return string
185186
return string
186187

187188

objinspect/method.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import inspect
2+
from collections.abc import Callable
23
from inspect import _ParameterKind
4+
from typing import Any
35

46
from objinspect.function import Function
57

@@ -30,12 +32,12 @@ class Method(Function):
3032
3133
"""
3234

33-
def __init__(self, method, cls, skip_self: bool = True):
35+
def __init__(self, method: Callable[..., Any], cls: type, skip_self: bool = True) -> None:
3436
super().__init__(method, skip_self)
3537
self.cls = cls
3638

3739
@property
38-
def class_instance(self):
40+
def class_instance(self) -> object | None:
3941
return getattr(self.func, "__self__", None)
4042

4143
@property
@@ -83,7 +85,7 @@ def __init__(
8385
private: bool = False,
8486
classmethod: bool = False,
8587
) -> None:
86-
self.checks = []
88+
self.checks: list[Callable[[Method], bool]] = []
8789
# fmt: off
8890
if not init: self.checks.append(lambda method: method.name == "__init__")
8991
if not static_methods: self.checks.append(lambda method: method.is_static)
@@ -104,9 +106,13 @@ def extract(self, methods: list[Method]) -> list[Method]:
104106
return [i for i in methods if self.check(i)]
105107

106108

107-
def split_args_kwargs(func_args: dict, func: Function | Method) -> tuple[tuple, dict]:
109+
def split_args_kwargs(
110+
func_args: dict[str, object],
111+
func: Function | Method,
112+
) -> tuple[tuple[object, ...], dict[str, object]]:
108113
"""Split the arguments passed to a function into positional and keyword arguments."""
109-
args, kwargs = [], {}
114+
args: list[object] = []
115+
kwargs: dict[str, object] = {}
110116
for param in func.params:
111117
if param.kind == _ParameterKind.POSITIONAL_ONLY:
112118
args.append(func_args[param.name])

objinspect/parameter.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,34 +53,34 @@ def __init__(
5353
if infer_type and not self.is_typed:
5454
self.type = self.get_infered_type()
5555

56-
def __repr__(self):
56+
def __repr__(self) -> str:
5757
data = f"name='{self.name}', kind={str(self.kind)}, type={self.type}, default={self.default}, description='{self.description}'"
5858
return f"{self.__class__.__name__}({data})"
5959

60-
def get_infered_type(self):
60+
def get_infered_type(self) -> Any:
6161
"""Infer the type of the parameter based on its default value."""
6262
if self.default is EMPTY:
6363
return EMPTY
6464
return type(self.default)
6565

6666
@property
6767
def is_typed(self) -> bool:
68-
return self.type != EMPTY
68+
return self.type is not EMPTY
6969

7070
@property
7171
def is_required(self) -> bool:
72-
return self.default == EMPTY
72+
return self.default is EMPTY
7373

7474
@property
7575
def is_optional(self) -> bool:
7676
return not self.is_required
7777

7878
@property
7979
def has_default(self) -> bool:
80-
return self.default != EMPTY
80+
return self.default is not EMPTY
8181

8282
@property
83-
def dict(self):
83+
def dict(self) -> dict[str, Any]:
8484
return {
8585
"name": self.name,
8686
"kind": self.kind,
@@ -124,7 +124,7 @@ def from_inspect_param(
124124
cls,
125125
param: inspect.Parameter,
126126
description: str | None = None,
127-
):
127+
) -> "Parameter":
128128
return cls(
129129
name=param.name,
130130
type=param.annotation,

objinspect/prettydir.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@ def prettydir(
3939
"__annotations__",
4040
"__module__",
4141
]
42-
METHOD_SKIPS = []
42+
METHOD_SKIPS: list[str] = []
4343

44-
def is_dunder(name: str):
44+
def is_dunder(name: str) -> bool:
4545
return name.startswith("__") and name.endswith("__")
4646

4747
if sep:

objinspect/typing.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def simplified_type_name(name: str) -> str:
5959
return name
6060

6161

62-
def is_generic_alias(t) -> bool:
62+
def is_generic_alias(t: Any) -> bool:
6363
"""
6464
Check if a type is an alias type (list[str], dict[str, int], etc...])
6565
@@ -77,7 +77,7 @@ def is_generic_alias(t) -> bool:
7777
return type(t) in ALIAS_TYPES
7878

7979

80-
def is_union_type(t) -> bool:
80+
def is_union_type(t: Any) -> bool:
8181
"""
8282
Check if a type is a union type (float | int, str | None, etc...)
8383
@@ -95,7 +95,7 @@ def is_union_type(t) -> bool:
9595
return type(t) in UNION_TYPES
9696

9797

98-
def is_iterable_type(t) -> bool:
98+
def is_iterable_type(t: Any) -> bool:
9999
"""
100100
Check if a type is an iterable type (list, tuple, etc...)
101101
@@ -150,7 +150,7 @@ def is_iterable_type(t) -> bool:
150150
return False
151151

152152

153-
def is_mapping_type(t) -> bool:
153+
def is_mapping_type(t: Any) -> bool:
154154
"""
155155
Check if a type is a mapping type (dict, OrderedDict, etc...)
156156
@@ -212,7 +212,7 @@ def is_enum(t: Any) -> bool:
212212
return isinstance(t, EnumMeta)
213213

214214

215-
def get_enum_choices(e) -> tuple[str, ...]:
215+
def get_enum_choices(e: Any) -> tuple[str, ...]:
216216
"""
217217
Get the options of a Python Enum.
218218
@@ -297,7 +297,7 @@ def is_or_contains_literal(t: Any) -> bool:
297297
return False
298298

299299

300-
def get_literal_choices(literal_t) -> tuple[str, ...]:
300+
def get_literal_choices(literal_t: Any) -> tuple[str, ...]:
301301
"""Get the options of a Python Literal."""
302302
if is_direct_literal(literal_t):
303303
return typing.get_args(literal_t)
@@ -307,7 +307,7 @@ def get_literal_choices(literal_t) -> tuple[str, ...]:
307307
raise ValueError(f"{literal_t} is not a literal")
308308

309309

310-
def literal_contains(literal_t, value: Any) -> bool:
310+
def literal_contains(literal_t: Any, value: Any) -> bool:
311311
"""Check if a value is in a Python Literal."""
312312
if not is_direct_literal(literal_t):
313313
raise ValueError(f"{literal_t} is not a literal")
@@ -318,7 +318,7 @@ def literal_contains(literal_t, value: Any) -> bool:
318318
return value in values
319319

320320

321-
def get_choices(t: type) -> tuple | None:
321+
def get_choices(t: Any) -> tuple[Any, ...] | None:
322322
"""
323323
Try to get the choices of a Literal or Enum type.
324324
Will also work with a Union type that contains Literal or Enum types.
@@ -330,7 +330,7 @@ def get_choices(t: type) -> tuple | None:
330330
return get_enum_choices(t)
331331
if is_union_type(t):
332332
args = type_args(t)
333-
choices = []
333+
choices: list[Any] = []
334334
for i in args:
335335
if is_enum(i):
336336
choices.extend(get_enum_choices(i))

0 commit comments

Comments
 (0)