Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a6fa924

Browse files
committed
Allow setting new private attributes
1 parent dfa05fe commit a6fa924

File tree

2 files changed

+33
-19
lines changed

2 files changed

+33
-19
lines changed

pyvista/core/utilities/misc.py

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -310,23 +310,25 @@ def _no_new_attributes(self, this_class: type) -> None:
310310

311311
def __setattr__(self, key: str, value: Any) -> None:
312312
"""Prevent adding new attributes to classes using "normal" methods."""
313-
# Check if this class froze itself. Any frozen state already set by parent classes, e.g.
314-
# by calling super().__init__(), will be ignored. This allows subclasses to set attributes
315-
# during init without being affect by a parent class init.
316-
frozen = self.__dict__.get('__frozen', False)
317-
frozen_by = self.__dict__.get('__frozen_by_class', None)
318-
if (
319-
frozen
320-
and frozen_by is type(self)
321-
and not (key in type(self).__dict__ or hasattr(self, key))
322-
):
323-
from pyvista import PyVistaAttributeError # noqa: PLC0415
324-
325-
msg = (
326-
f'Attribute {key!r} does not exist and cannot be added to class '
327-
f'{self.__class__.__name__!r}\nUse `pv.set_new_attribute` to set new attributes.'
328-
)
329-
raise PyVistaAttributeError(msg)
313+
if not key.startswith('_'):
314+
# Check if this class froze itself. Any frozen state already set by parent classes,
315+
# e.g. by calling super().__init__(), will be ignored. This allows subclasses to set
316+
# attributes during init without being affect by a parent class init.
317+
frozen = self.__dict__.get('__frozen', False)
318+
frozen_by = self.__dict__.get('__frozen_by_class', None)
319+
if (
320+
frozen
321+
and frozen_by is type(self)
322+
and not (key in type(self).__dict__ or hasattr(self, key))
323+
):
324+
from pyvista import PyVistaAttributeError # noqa: PLC0415
325+
326+
msg = (
327+
f'Attribute {key!r} does not exist and cannot be added to class '
328+
f'{self.__class__.__name__!r}\nUse `pv.set_new_attribute` to set new '
329+
f'attributes or consider setting a private variable (with `_` prefix) instead.'
330+
)
331+
raise PyVistaAttributeError(msg)
330332
object.__setattr__(self, key, value)
331333

332334

tests/core/test_utilities.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1329,9 +1329,10 @@ def test_no_new_attr_mixin(no_new_attributes_mixin_subclass):
13291329

13301330
match = (
13311331
"Attribute 'ham' does not exist and cannot be added to class 'A'\n"
1332-
'Use `pv.set_new_attribute` to set new attributes.'
1332+
'Use `pv.set_new_attribute` to set new attributes or consider setting a private variable '
1333+
'(with `_` prefix) instead.'
13331334
)
1334-
with pytest.raises(pv.PyVistaAttributeError, match=match):
1335+
with pytest.raises(pv.PyVistaAttributeError, match=re.escape(match)):
13351336
setattr(a, ham, eggs)
13361337

13371338
match = "Attribute 'ham' does not exist and cannot be added to class 'B'"
@@ -2348,6 +2349,17 @@ def test_vtk_snake_case():
23482349
_ = pv.PolyData().information
23492350

23502351

2352+
def test_allow_new_attributes():
2353+
match = (
2354+
"Attribute 'foo' does not exist and cannot be added to class 'PolyData'\n"
2355+
'Use `pv.set_new_attribute` to set new attributes or consider setting a private '
2356+
'variable (with `_` prefix) instead.'
2357+
)
2358+
_ = pv.PolyData()._foo = 42
2359+
with pytest.raises(pv.PyVistaAttributeError, match=re.escape(match)):
2360+
_ = pv.PolyData().foo = 42
2361+
2362+
23512363
T = TypeVar('T')
23522364

23532365

0 commit comments

Comments
 (0)