Skip to content

Commit ee587c7

Browse files
committed
Fix attribute lookup from bases
Instead of directly looping over the bases, we derive a new class from them which we can then use for correct attribute lookups that implicitly loop over the mro.
1 parent 475c43b commit ee587c7

File tree

2 files changed

+16
-14
lines changed

2 files changed

+16
-14
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
2222
- Restricted the settings module to the {module}:{class} formatting.
2323
- Stopped normalizing lowercase prefixes.
2424

25+
### Fixed
26+
- Fixed Settings subclasses not inheriting the correct Meta sometimes.
27+
2528
## [0.1.3] - Unreleased
2629

2730
### Fixed

class_settings/settings.py

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,16 @@
1616

1717

1818
class SettingsDict(collections.UserDict):
19-
def __init__(self, *, options, bases):
19+
def __init__(self, *, options, bare_cls):
2020
super().__init__()
2121
self.options = options
22-
self.bases = bases
22+
self._bare_cls = bare_cls
2323

2424
def __missing__(self, key):
2525
if self.options.inject_settings and key.isupper():
26-
for base in self.bases:
27-
value = getattr(base, key, missing)
28-
if value is not missing:
29-
return copy.deepcopy(value)
26+
value = getattr(self._bare_cls, key, missing)
27+
if value is not missing:
28+
return copy.deepcopy(value)
3029
raise KeyError(key)
3130

3231
def __setitem__(self, key, value):
@@ -41,7 +40,10 @@ def __setitem__(self, key, value):
4140

4241

4342
class SettingsMeta(type):
44-
def __prepare__(name, bases):
43+
@classmethod
44+
def __prepare__(meta, name, bases):
45+
bare_cls = meta("<Bare>", bases, SettingsDict(options=None, bare_cls=None))
46+
4547
frame = sys._getframe(1)
4648
filename = inspect.getsourcefile(frame)
4749
with tokenize.open(filename) as file:
@@ -69,13 +71,10 @@ def __prepare__(name, bases):
6971
meta = locals["Meta"]
7072
break
7173
else:
72-
for base in bases:
73-
if hasattr(base, "Meta"):
74-
meta = base.Meta
75-
break
76-
else:
77-
meta = None
78-
return SettingsDict(options=Options(meta), bases=bases)
74+
meta = getattr(bare_cls, "Meta", None)
75+
options = Options(meta)
76+
bare_cls._options = options
77+
return SettingsDict(options=options, bare_cls=bare_cls)
7978

8079
def __new__(meta, name, bases, namespace):
8180
if "Meta" in namespace and not isinstance(namespace["Meta"], type):

0 commit comments

Comments
 (0)