Skip to content

Commit c44ec87

Browse files
committed
Modify MustUse to iterate the stack frame and collate options from all frames.
Options in closer frames take precedence
1 parent 5689b6b commit c44ec87

File tree

2 files changed

+29
-5
lines changed

2 files changed

+29
-5
lines changed

amaranth/_unused.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import sys
22
import warnings
3+
import logging
34

45
from ._utils import get_linter_option
56

@@ -18,7 +19,9 @@ class MustUse:
1819
def __new__(cls, *args, src_loc_at=0, **kwargs):
1920
frame = sys._getframe(1 + src_loc_at)
2021
self = super().__new__(cls)
21-
self._MustUse__used = False
22+
23+
self._MustUse__used = False
24+
self._MustUse__frame = frame
2225
self._MustUse__context = dict(
2326
filename=frame.f_code.co_filename,
2427
lineno=frame.f_lineno,
@@ -31,7 +34,7 @@ def __del__(self):
3134
if getattr(self._MustUse__warning, "_MustUse__silence", False):
3235
return
3336
if hasattr(self, "_MustUse__used") and not self._MustUse__used:
34-
if get_linter_option(self._MustUse__context["filename"],
37+
if get_linter_option(self._MustUse__frame,
3538
self._MustUse__warning.__qualname__, bool, True):
3639
warnings.warn_explicit(
3740
f"{self!r} created but never used", self._MustUse__warning,

amaranth/_utils.py

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,18 +74,39 @@ def decorator_like(*args, **kwargs):
7474
return f(*args, **kwargs)
7575
return decorator_like
7676

77+
_LINT_PATTERN = re.compile(r"^#\s*amaranth:\s*((?:\w+=\w+\s*)(?:,\s*\w+=\w+\s*)*)\n$")
78+
7779

7880
def get_linter_options(filename):
7981
first_line = linecache.getline(filename, 1)
8082
if first_line:
81-
match = re.match(r"^#\s*amaranth:\s*((?:\w+=\w+\s*)(?:,\s*\w+=\w+\s*)*)\n$", first_line)
83+
match = _LINT_PATTERN.match(first_line)
8284
if match:
8385
return dict(map(lambda s: s.strip().split("=", 2), match.group(1).split(",")))
8486
return dict()
8587

8688

87-
def get_linter_option(filename, name, type, default):
88-
options = get_linter_options(filename)
89+
def get_linter_option(frame, name, type, default):
90+
"""
91+
Get given linter option for a given stack frame. This iterates down the frames, collating options of the form:
92+
```
93+
# amaranth: {name} = value
94+
```
95+
The earliest option value in the stack takes precedence
96+
97+
Returns:
98+
option value: bool | int
99+
"""
100+
101+
options = {}
102+
while frame:
103+
f_opts = get_linter_options(frame.f_code.co_filename)
104+
options = f_opts | options
105+
if frame.f_back is None:
106+
break
107+
else:
108+
frame = frame.f_back
109+
89110
if name not in options:
90111
return default
91112

0 commit comments

Comments
 (0)