This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: pathlib: Path and PurePath cannot be subclassed
Type: enhancement Stage: resolved
Components: Library (Lib) Versions: Python 3.7
process
Status: closed Resolution: duplicate
Dependencies: Superseder: Direct sub-classing of pathlib.Path
View: 24132
Assigned To: Nosy List: pitrou, sbstp, serhiy.storchaka, steven.daprano
Priority: normal Keywords:

Created on 2017-07-18 06:40 by sbstp, last changed 2022-04-11 14:58 by admin. This issue is now closed.

Messages (3)
msg298577 - (view) Author: Simon Bernier St-Pierre (sbstp) * Date: 2017-07-18 06:40
Because of the special way Path and PurePath are instantiated, they can't be inherited like a normal class. Here's an example of the issue:

>>> import pathlib
>>> class MyPath(pathlib.Path):
...   pass
... 
>>> p = MyPath('/home')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.5/pathlib.py", line 969, in __new__
    self = cls._from_parts(args, init=False)
  File "/usr/lib/python3.5/pathlib.py", line 651, in _from_parts
    drv, root, parts = self._parse_args(args)
  File "/usr/lib/python3.5/pathlib.py", line 644, in _parse_args
    return cls._flavour.parse_parts(parts)
AttributeError: type object 'MyPath' has no attribute '_flavour'

A solution is to get the concrete type of Path via type(Path()) and inherit the class it yields, but it isn't pretty or intuitive. Perhaps a declaration that directs to the proper class could be added to the module.

PlatformPath = WindowsPath if os.name == 'nt' else PosixPath
PurePlatformPath = ...
msg298584 - (view) Author: Steven D'Aprano (steven.daprano) * (Python committer) Date: 2017-07-18 12:34
Python 3.4, 3.5 and 3.6 are in feature-freeze, so this enhancement can only apply to 3.7.

You say that pathlib.Path "can't be subclassed", but then immediately show an example of subclassing it:

>>> class MyPath(pathlib.Path):
...   pass
... 

Which works fine. If you run:

issubclass(MyClass, pathlib.Path)

it returns True. Unfortunately, it looks like your subclass broke one of the class invariants, but you don't find out until you try to instantiate it:

>>> p = MyPath('/home')
Traceback (most recent call last):
  ...
AttributeError: type object 'MyPath' has no attribute '_flavour'


_flavour is a private attribute, and is not documented, so I don't think subclassing is supported. If that is the case:

- the documentation should say that subclassing is not supported;
- or the Path class should actively prohibit subclassing (will 
  probably require a metaclass);
- or both.

If subclassing is supported, then I think there ought to be a better way than this:


py> class MyPath(pathlib.Path):
...     _flavour = pathlib.Path('.')._flavour
...
py> MyPath('.')
MyPath('.')
msg298585 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2017-07-18 12:42
This is a duplicate of issue24132.
History
Date User Action Args
2022-04-11 14:58:49adminsetgithub: 75140
2017-07-18 12:42:29serhiy.storchakasetstatus: open -> closed

superseder: Direct sub-classing of pathlib.Path

nosy: + serhiy.storchaka
messages: + msg298585
resolution: duplicate
stage: resolved
2017-07-18 12:34:34steven.dapranosetnosy: + pitrou, steven.daprano

messages: + msg298584
versions: - Python 3.4, Python 3.5, Python 3.6
2017-07-18 06:40:11sbstpcreate