Skip to content

Commit a54d3b7

Browse files
committed
Move source check in _bytecode_nameof to nameof. #24
1 parent 24bb42e commit a54d3b7

File tree

2 files changed

+36
-44
lines changed

2 files changed

+36
-44
lines changed

tests/test_varname.py

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616
import varname as varname_module
1717

1818

19-
def nameof(*args, full=False):
19+
def nameof(*args):
2020
"""Test both implementations at the same time"""
21-
result = original_nameof(*args, caller=2, full=full)
21+
result = original_nameof(*args, caller=2)
2222
if len(args) == 1:
2323
assert result == _bytecode_nameof(caller=2)
2424
return result
@@ -600,13 +600,6 @@ class A(list):
600600
assert a == b
601601

602602

603-
def test_no_source_code_nameof():
604-
assert eval('nameof(list)') == eval('original_nameof(list)') == 'list'
605-
606-
with pytest.raises(VarnameRetrievingError):
607-
eval("original_nameof(list, list)")
608-
609-
610603
class Weird:
611604
def __add__(self, other):
612605
_bytecode_nameof(caller=2)
@@ -647,15 +640,10 @@ def test_nameof_full():
647640
# we are not able to retreive full names without source code available
648641
with pytest.raises(
649642
VarnameRetrievingError,
650-
match='Are you trying to call nameof from exec/eval'
643+
match=('Are you trying to call nameof from exec/eval')
651644
):
652-
eval('nameof(a.b, full=False)')
645+
eval('original_nameof(a.b, full=False)')
653646

654-
with pytest.raises(
655-
VarnameRetrievingError,
656-
match='Cannot retrieve full name by nameof'
657-
):
658-
eval('nameof(a.b, full=True)')
659647

660648
def test_nameof_from_stdin():
661649
code = ('from varname import nameof; '

varname.py

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ def inject(obj: object) -> object:
168168

169169
def nameof(var, *more_vars, # pylint: disable=unused-argument
170170
caller: int = 1,
171-
full: bool = False) -> Union[str, Tuple[str]]:
171+
full: Optional[bool] = None) -> Union[str, Tuple[str]]:
172172
"""Get the names of the variables passed in
173173
174174
Examples:
@@ -209,19 +209,36 @@ def nameof(var, *more_vars, # pylint: disable=unused-argument
209209
"""
210210
node = _get_node(caller - 1, raise_exc=True)
211211
if not node:
212-
if full:
212+
# We can't retrieve the node by executing.
213+
# It can be due to running code from python/shell, exec/eval or
214+
# other environments where sourcecode cannot be reached
215+
# make sure we keep it simple (only single variable passed and no
216+
# full passed) to use _bytecode_nameof
217+
if not more_vars and full is None:
218+
return _bytecode_nameof(caller + 1)
219+
220+
# We are anyway raising exceptions, no worries about additional burden
221+
# of frame retrieval again
222+
223+
# may raise exception, just leave it as is
224+
frame = _get_frame(caller)
225+
source = frame.f_code.co_filename
226+
if source == '<stdin>':
227+
raise VarnameRetrievingError(
228+
"Are you trying to call nameof in REPL/python shell? "
229+
"In such a case, nameof can only be called with single "
230+
"argument and no keyword arguments."
231+
)
232+
if source == '<string>':
213233
raise VarnameRetrievingError(
214-
"Cannot retrieve full name by nameof when called "
215-
"in shell/REPL, exec/eval or other situations "
216-
"where sourcecode is unavailable."
234+
"Are you trying to call nameof from exec/eval? "
235+
"In such a case, nameof can only be called with single "
236+
"argument and no keyword arguments."
217237
)
218-
# only works with nameof(a) or nameof(a.b)
219-
# no keyword arguments is supposed to be passed in
220-
# that means we cannot retrieve the full name without
221-
# sourcecode available
222-
if not more_vars:
223-
return _bytecode_nameof(caller + 1)
224-
raise VarnameRetrievingError("Unable to retrieve callee's node.")
238+
raise VarnameRetrievingError(
239+
"Source code unavailable, nameof can only retrieve the name of "
240+
"a single variable, and argument `full` should not be specified."
241+
)
225242

226243
ret: List[str] = []
227244
for arg in node.args:
@@ -370,11 +387,10 @@ def _node_name(node: NodeType) -> str:
370387
def _bytecode_nameof(caller: int = 1) -> str:
371388
"""Bytecode version of nameof as a fallback"""
372389
frame = _get_frame(caller)
373-
source = frame.f_code.co_filename
374-
return _bytecode_nameof_cached(frame.f_code, frame.f_lasti, source)
390+
return _bytecode_nameof_cached(frame.f_code, frame.f_lasti)
375391

376392
@lru_cache()
377-
def _bytecode_nameof_cached(code: CodeType, offset: int, source: str) -> str:
393+
def _bytecode_nameof_cached(code: CodeType, offset: int) -> str:
378394
"""Cached Bytecode version of nameof
379395
380396
We are trying this version only when the sourcecode is unavisible. In most
@@ -390,19 +406,7 @@ def _bytecode_nameof_cached(code: CodeType, offset: int, source: str) -> str:
390406
)
391407

392408
if current_instruction.opname not in ("CALL_FUNCTION", "CALL_METHOD"):
393-
if source == '<stdin>':
394-
raise VarnameRetrievingError(
395-
"Are you trying to call nameof in REPL/python shell? "
396-
"In such a case, nameof can only be called with single "
397-
"argument and no keyword arguments."
398-
)
399-
if source == '<string>':
400-
raise VarnameRetrievingError(
401-
"Are you trying to call nameof from exec/eval? "
402-
"In such a case, nameof can only be called with single "
403-
"argument and no keyword arguments."
404-
)
405-
raise VarnameRetrievingError("Did you call nameof in a weird way? ")
409+
raise VarnameRetrievingError("Did you call nameof in a weird way?")
406410

407411
name_instruction = instructions[
408412
current_instruction_index - 1

0 commit comments

Comments
 (0)