Skip to content

Commit 5fdbe4e

Browse files
committed
Adds handling for the case where stacklevel traversal pops the top of the call stack. Fixes #153
1 parent bfcd7f9 commit 5fdbe4e

File tree

2 files changed

+18
-3
lines changed

2 files changed

+18
-3
lines changed

aerosandbox/optimization/opti.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,8 @@ def variable(
321321

322322
# Track where this variable was declared in code.
323323
filename, lineno, code_context = inspect_tools.get_caller_source_location(
324-
stacklevel=_stacklevel + 1
324+
stacklevel=_stacklevel + 1,
325+
truncate_stacklevel=True,
325326
)
326327
self._variable_declarations[self._variable_index_counter] = (
327328
filename,
@@ -429,7 +430,8 @@ def subject_to(
429430
# Track where this constraint was declared in code.
430431
n_cons = np.length(constraint)
431432
filename, lineno, code_context = inspect_tools.get_caller_source_location(
432-
stacklevel=_stacklevel + 1
433+
stacklevel=_stacklevel + 1,
434+
truncate_stacklevel=True,
433435
)
434436
self._constraint_declarations[self._constraint_index_counter] = (
435437
filename,

aerosandbox/tools/inspect_tools.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
def get_caller_source_location(
99
stacklevel: int = 1,
10+
truncate_stacklevel: bool=False,
1011
) -> (Path, int, str):
1112
"""
1213
Gets the file location where this function itself (`get_caller_source_location()`) is called.
@@ -37,6 +38,9 @@ def get_caller_source_location(
3738
you higher (i.e., more end-user-facing) in the stack. Same behaviour as the `stacklevel` argument in
3839
warnings.warn().
3940
41+
truncate_stacklevel: If True, will truncate the stacklevel to the maximum possible value. This is useful if you
42+
43+
4044
Returns: A tuple of:
4145
(filename, lineno, code_context)
4246
@@ -51,7 +55,16 @@ def get_caller_source_location(
5155
### Go up `stacklevel` frames from the current one to get to the caller frame.
5256
frame = inspect.currentframe()
5357
for _ in range(stacklevel):
54-
frame = frame.f_back
58+
if frame.f_back is None:
59+
if truncate_stacklevel:
60+
break
61+
else:
62+
raise ValueError(
63+
f"Argument `{stacklevel=}` results in popping off the top of the traceback.\n"
64+
f"Use a lower value, or set `truncate_stacklevel=True` to suppress this error."
65+
)
66+
else:
67+
frame = frame.f_back
5568

5669
### Extract the frame info (an `inspect.Traceback` type) from the caller frame
5770
frame_info: inspect.Traceback = inspect.getframeinfo(frame)

0 commit comments

Comments
 (0)