Hi,
I tried subclassing pathlib.Path and provide it with a new attribute (basically an accessor to an extended attribute). I am rather new to the concept of __slots__ and __new__() but here is how I pictured it should look:
from errno import ENODATA
from os import getxattr, setxattr
from pathlib import Path
class Path_(type(Path())):
__slots__ = ("new_attr",)
def __new__(cls, *args, new_attr=None, **kwargs):
self = super().__new__(cls, *args, **kwargs)
self._new_attr = new_attr
return self
@property
def new_attr(self):
if self._new_attr:
return self._new_attr
try:
new_attr = getxattr(self, "user.new_attr")
except OSError as exc:
if exc.errno != ENODATA:
raise exc
else:
self._new_attr = new_attr
return new_attr
new_attr = b"something_dynamic" # for example uuid4().bytes
setxattr(self, "user.new_attr", new_attr)
self._new_attr = new_attr
return new_attr
The issue I have is that although my class defines its own __new__() method, it is not always called by the methods of pathlib.Path. For example:
>>> Path_("/etc").parent.new_attr
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/path/to/reproducer.py", line 19, in new_attr
if self._new_attr:
AttributeError: _new_attr
The current workaround I use consists in redefining pathlib.Path's _from_parsed_parts() method in my class: instead of creating a new object using:
object.__new__(cls)
my implementation uses:
cls.__new__(cls)
This is the first time I play with the __new__() special method, so it is possible I missed something, if so, sorry for the noise.
|