Skip to content

Commit 9d4aa7a

Browse files
committed
Add type hints
1 parent bea6729 commit 9d4aa7a

File tree

3 files changed

+55
-39
lines changed

3 files changed

+55
-39
lines changed

docs/style.css

+3
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@
3737
overflow: visible;
3838
line-height: 1.2;
3939
}
40+
.mkapi-docstring .md-typeset pre>code {
41+
font-size: 0.1rem !important;
42+
}
4043
.mkapi-section-name.bases {
4144
margin-top: .2em;
4245
}

mkdocs.yml

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ site_name: varname
22
theme:
33
favicon: favicon.png
44
logo: favicon.png
5+
palette:
6+
primary: blue
57
name: 'material'
68
# font:
79
# text: 'Ubuntu'

varname.py

+50-39
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,31 @@
33
import dis
44
import sys
55
import warnings
6-
from typing import Union, Tuple
6+
from typing import Union, Tuple, Any, Optional, Type, List, Iterator
7+
from types import FrameType, CodeType
78
from collections import namedtuple as standard_namedtuple
89
from functools import lru_cache
910

1011
import executing
1112

1213
__version__ = "0.4.0"
1314

15+
NodeType = Type[ast.AST]
16+
1417
class VarnameRetrievingError(Exception):
1518
"""When failed to retrieve the varname"""
1619

17-
def varname(caller: int = 1, raise_exc: bool = True) -> str:
20+
def varname(caller: int = 1, raise_exc: bool = True) -> Optional[str]:
1821
"""Get the variable name that assigned by function/class calls
1922
2023
Args:
21-
caller (int): The call stack index, indicating where this function
24+
caller: The call stack index, indicating where this function
2225
is called relative to where the variable is finally retrieved
23-
raise_exc (bool): Whether we should raise an exception if failed
26+
raise_exc: Whether we should raise an exception if failed
2427
to retrieve the name.
2528
2629
Returns:
27-
str|None: The variable name, or `None` when `raise_exc` is `False` and
30+
The variable name, or `None` when `raise_exc` is `False` and
2831
we failed to retrieve the variable name.
2932
3033
Raises:
@@ -33,12 +36,11 @@ def varname(caller: int = 1, raise_exc: bool = True) -> str:
3336
when we are unable to retrieve the variable name and `raise_exc`
3437
is set to `True`.
3538
36-
Warns:
3739
UserWarning: When there are multiple target
3840
in the assign node. (e.g: `a = b = func()`, in such a case,
3941
`b == 'a'`, may not be the case you want)
4042
"""
41-
node = _get_node(caller, raise_exc=raise_exc)
43+
node: Optional[NodeType] = _get_node(caller, raise_exc=raise_exc)
4244
if not node:
4345
if raise_exc:
4446
raise VarnameRetrievingError("Unable to retrieve the ast node.")
@@ -58,10 +60,10 @@ def varname(caller: int = 1, raise_exc: bool = True) -> str:
5860
warnings.warn("Multiple targets in assignment, variable name "
5961
"on the very left will be used.",
6062
UserWarning)
61-
target = node.targets[0]
63+
target: str = node.targets[0]
6264
return _node_name(target)
6365

64-
def will(caller: int = 1, raise_exc: bool = True) -> str:
66+
def will(caller: int = 1, raise_exc: bool = True) -> Optional[str]:
6567
"""Detect the attribute name right immediately after a function call.
6668
6769
Examples:
@@ -91,25 +93,25 @@ def will(caller: int = 1, raise_exc: bool = True) -> str:
9193
>>> awesome.permit().do() == 'I am doing!'
9294
9395
Args:
94-
caller (int): At which stack this function is called.
95-
raise_exc (bool): Raise exception we failed to detect
96+
caller: At which stack this function is called.
97+
raise_exc: Raise exception we failed to detect
9698
9799
Returns:
98-
str: The attribute name right after the function call
99-
None: If there is no attribute attached and `raise_exc` is `False`
100+
The attribute name right after the function call
101+
If there is no attribute attached and `raise_exc` is `False`
100102
101103
Raises:
102104
VarnameRetrievingError: When `raise_exc` is `True` and we failed to
103105
detect the attribute name (including not having one)
104106
"""
105-
node = _get_node(caller, raise_exc=raise_exc)
107+
node: Optional[NodeType] = _get_node(caller, raise_exc=raise_exc)
106108
if not node:
107109
if raise_exc:
108110
raise VarnameRetrievingError("Unable to retrieve the frame.")
109111
return None
110112

111113
# try to get not inst.attr from inst.attr()
112-
node = node.parent
114+
node: NodeType = node.parent
113115

114116
# see test_will_fail
115117
if not isinstance(node, ast.Attribute):
@@ -122,7 +124,7 @@ def will(caller: int = 1, raise_exc: bool = True) -> str:
122124
# ast.Attribute
123125
return node.attr
124126

125-
def inject(obj: any) -> any:
127+
def inject(obj: object) -> object:
126128
"""Inject attribute `__varname__` to an object
127129
128130
Examples:
@@ -150,9 +152,9 @@ def inject(obj: any) -> any:
150152
be set as an attribute
151153
152154
Returns:
153-
obj: The object with __varname__ injected
155+
The object with __varname__ injected
154156
"""
155-
vname = varname()
157+
vname: Optional[str] = varname()
156158
try:
157159
setattr(obj, '__varname__', vname)
158160
except AttributeError:
@@ -178,15 +180,15 @@ def nameof(*args, caller: int = 1) -> Union[str, Tuple[str]]:
178180
*args: A couple of variables passed in
179181
180182
Returns:
181-
tuple|str: The names of variables passed in
183+
The names of variables passed in
182184
"""
183-
node = _get_node(caller - 1, raise_exc=True)
185+
node: Optional[NodeType] = _get_node(caller - 1, raise_exc=True)
184186
if not node:
185187
if len(args) == 1:
186188
return _bytecode_nameof(caller + 1)
187189
raise VarnameRetrievingError("Unable to retrieve callee's node.")
188190

189-
ret = []
191+
ret: List[str] = []
190192
for arg in node.args:
191193
ret.append(_node_name(arg))
192194

@@ -196,7 +198,7 @@ def nameof(*args, caller: int = 1) -> Union[str, Tuple[str]]:
196198

197199
return ret[0] if len(args) == 1 else tuple(ret)
198200

199-
def namedtuple(*args, **kwargs):
201+
def namedtuple(*args, **kwargs) -> type:
200202
"""A shortcut for namedtuple
201203
202204
You don't need to specify the typename, which will be fetched from
@@ -214,6 +216,9 @@ def namedtuple(*args, **kwargs):
214216
*args: arguments for `collections.namedtuple` except `typename`
215217
**kwargs: keyword arguments for `collections.namedtuple`
216218
except `typename`
219+
220+
Returns:
221+
The namedtuple you desired.
217222
"""
218223
typename: str = varname(raise_exc=True)
219224
return standard_namedtuple(typename, *args, **kwargs)
@@ -232,16 +237,17 @@ class Wrapper:
232237
>>> # bar.value is val
233238
234239
Args:
235-
240+
value: The value to be wrapped
241+
raise_exc: Whether to raise exception when varname is failed to retrieve
236242
237243
Attributes:
238-
name (str): The variable name to which the instance is assigned
239-
value (any): The value this wrapper wraps
244+
name: The variable name to which the instance is assigned
245+
value: The value this wrapper wraps
240246
"""
241247

242-
def __init__(self, value: any, raise_exc: bool = True):
248+
def __init__(self, value: Any, raise_exc: bool = True):
243249
self.name: str = varname(raise_exc=raise_exc)
244-
self.value: any = value
250+
self.value: Any = value
245251

246252
def __str__(self) -> str:
247253
return repr(self.value)
@@ -250,14 +256,14 @@ def __repr__(self) -> str:
250256
return (f"<{self.__class__.__name__} "
251257
f"(name={self.name!r}, value={self.value!r})>")
252258

253-
def _get_frame(caller):
259+
def _get_frame(caller: int) -> FrameType:
254260
"""Get the frame at `caller` depth"""
255261
try:
256262
return sys._getframe(caller + 1)
257263
except Exception as exc:
258264
raise VarnameRetrievingError from exc
259265

260-
def _get_node(caller: int, raise_exc: bool = True):
266+
def _get_node(caller: int, raise_exc: bool = True) -> Optional[NodeType]:
261267
"""Try to get node from the executing object.
262268
263269
This can fail when a frame is failed to retrieve.
@@ -267,11 +273,11 @@ def _get_node(caller: int, raise_exc: bool = True):
267273
When the node can not be retrieved, try to return the first statement.
268274
"""
269275
try:
270-
frame = _get_frame(caller + 2)
276+
frame: FrameType = _get_frame(caller + 2)
271277
except VarnameRetrievingError:
272278
return None
273279

274-
exet = executing.Source.executing(frame)
280+
exet: executing.Executing = executing.Source.executing(frame)
275281

276282
if exet.node:
277283
return exet.node
@@ -285,7 +291,7 @@ def _get_node(caller: int, raise_exc: bool = True):
285291

286292
return None
287293

288-
def _lookfor_parent_assign(node):
294+
def _lookfor_parent_assign(node: NodeType) -> Optional[ast.Assign]:
289295
"""Look for an ast.Assign node in the parents"""
290296
while hasattr(node, 'parent'):
291297
node = node.parent
@@ -294,8 +300,11 @@ def _lookfor_parent_assign(node):
294300
return node
295301
return None
296302

297-
def _node_name(node):
298-
"""Get the node node name"""
303+
def _node_name(node: NodeType) -> str:
304+
"""Get the node node name.
305+
306+
Raises VarnameRetrievingError when failed
307+
"""
299308
if isinstance(node, ast.Name):
300309
return node.id
301310
if isinstance(node, ast.Attribute):
@@ -306,15 +315,15 @@ def _node_name(node):
306315
f"not {ast.dump(node)}"
307316
)
308317

309-
def _bytecode_nameof(caller=1):
318+
def _bytecode_nameof(caller: int = 1) -> str:
310319
"""Bytecode version of nameof as a fallback"""
311-
frame = _get_frame(caller)
320+
frame: FrameType = _get_frame(caller)
312321
return _bytecode_nameof_cached(frame.f_code, frame.f_lasti)
313322

314323
@lru_cache()
315-
def _bytecode_nameof_cached(code, offset):
324+
def _bytecode_nameof_cached(code: CodeType, offset: int) -> str:
316325
"""Cached Bytecode version of nameof"""
317-
instructions = list(dis.get_instructions(code))
326+
instructions: Iterator[dis.Instruction] = list(dis.get_instructions(code))
318327
(current_instruction_index, current_instruction), = (
319328
(index, instruction)
320329
for index, instruction in enumerate(instructions)
@@ -324,7 +333,9 @@ def _bytecode_nameof_cached(code, offset):
324333
if current_instruction.opname not in ("CALL_FUNCTION", "CALL_METHOD"):
325334
raise VarnameRetrievingError("Did you call nameof in a weird way?")
326335

327-
name_instruction = instructions[current_instruction_index - 1]
336+
name_instruction: dis.Instruction = instructions[
337+
current_instruction_index - 1
338+
]
328339
if not name_instruction.opname.startswith("LOAD_"):
329340
raise VarnameRetrievingError("Argument must be a variable or attribute")
330341

0 commit comments

Comments
 (0)