Repository navigation
pathlib.Path._from_parsed_parts should call cls.__new__(cls) #76846
Description
Activity
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_attrnew_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_attrThe 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.
- addedstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directory
on Jan 25, 2018 Typo in the code of the previous comment:
- __slots__ = ("new_attr",)
+ __slots__ = ("_new_attr",)
- __slots__ = ("new_attr",)
- addedtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
on Jan 26, 2018 This behaviour is because "parent" descriptor ends calling:
@classmethod def _from_parsed_parts(cls, drv, root, parts, init=True): self = object.__new__(cls) self._drv = drv self._root = root self._parts = parts if init: self._init() return self
and this calls object.__new__ and this call raises AttributeError: new_attr. Notice that object.__new__(cls) will not raise as this snippet shows:
>>>: class A:
...: def __new__(*args):
...: raise ZeroDivisionError()
...:>> A()
---------------------------------------------------------------------------ZeroDivisionError Traceback (most recent call last) <python> in <module>() ----> 1 A()
<python> in __new__(*args)
1 class A:
2 def __new__(*args):
----> 3 raise ZeroDivisionError()
4ZeroDivisionError:
>> object.__new__(A)
>> <main.A at 0x7f6239c17860>Sorry, the exception of object.__new__(cls) is AttributeError: _drv
Antoine, is the reason of calling object.new(cls) in
_from_parsed_partsthat the code does not raise on creation?#100481 removes
_from_parsed_parts()and adds a supported route for subclassing, so would resolve this issue I believe.- added a commit that references this issue
on Feb 4, 2023
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
Linked PRs
__new__()and__init__()on pathlib subclasses #102789