-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make Range
instances somewhat immutable
#142
Conversation
🔍 Existing Issues For ReviewYour pull request is modifying functions with the following pre-existing issues: 📄 File: xocto/ranges.py
Did you find this useful? React with a 👍 or 👎 |
c473001
to
a6cf892
Compare
Prior to this change, `Range` instances (because it declares `__slots__`) did not have instance dict but classes derived from `Range` did have instance dicts - a confusing mix of paradigms. This change adds `__slots__ = ()` to classes that have `Range` as a base class, and adds two tests to ensure that instances do not have a `__dict__` attribute. It also adds an initialiser to `HalfFiniteRange` to set `boundary` using the slot, rather than trying to use an instance dict.
a6cf892
to
bd702d0
Compare
_is_left_exclusive: bool | ||
_is_left_inclusive: bool | ||
_is_right_exclusive: bool | ||
_is_right_inclusive: bool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These types were previously implicitly declared when __init__
set attributes.
start: T | ||
boundaries = RangeBoundaries.INCLUSIVE_EXCLUSIVE |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Setting the default value using a class attribute does not play with __slots__
. I have moved this default to __init__
.
xocto/ranges.py
Outdated
else: | ||
raise AttributeError( | ||
f"'{type(self).__name__}' object has no attribute '{name}'" | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These exception messages consistent with those raised by collections.namedtuple
.
xocto/ranges.py
Outdated
raise AttributeError( | ||
f"'{type(self).__name__}' object has no attribute '{name}'" | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps explicit is better than implicit, but I wonder if we could delegate this branch to super()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is a good point. Change to use super
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good change, thanks for making it. As this is a potentially breaking change we'll need to at least bump the minor version when releasing.
Prior to this change, attributes of `Range` instances can be set, bypassing validation and violating class invariants. This change adds `Range.__setattr__`, which raises `AttributeError`, and alters `__init__` to use the same `object.__setattr__` trick as `attrs` to set attributes during initialisation.
bd702d0
to
d093dec
Compare
This PR addresses two problems with
Range
.Attributes of
Range
instances can be set, bypassing validation and violating class invariants:Additional attributes can be set on instances of classes derived from
Range
Range
uses__slots__
, which prevents creation of instance dictionaries. Classes derived fromRange
do not have__slots__ = ()
, which means that instance dictionaries are created:Fix these problems:
__slots__ = ()
to classes that haveRange
as a base class (preventing creation of instance dicts),Range.__setattr__
to raiseAttributeError
, andRange.__init__
to use the sameobject.__setattr__
trick asattrs
to set attributes during initialisation.