Skip to content

Subclassing of pathlib.Path

In my case, I wanted to enhance the functionality of pathlib.Path to include additional methods for file or directory operations specific to my project.

For example, I wanted to add a method that would allow me to easily zip a directory or a file directly from the Path object:

from pathlib import Path

class EnhancePath(Path):
    def zip(self):
        print('zip file')

EnhancePath.cwd()

This code works normally on python 3.13, but it raises an error on python 3.11 and below (I don't test on 3.12):

AttributeError: type object 'EnhancePath' has no attribute '_flavour'

Solution

Read the source code of pathlib.Path on python 3.11:

python3.11 pathlib
class Path(PurePath):
    def __new__(cls, *args, **kwargs):
        if cls is Path:
            cls = WindowsPath if os.name == 'nt' else PosixPath
        self = cls._from_parts(args)
        if not self._flavour.is_supported:
            raise NotImplementedError("cannot instantiate %r on your system"
                                      % (cls.__name__,))
        return self

class PosixPath(Path, PurePosixPath):
    ...

class PurePosixPath(PurePath):
    _flavour = _posix_flavour

__new__ implements factory function functionality, which means that when you use Path, it will return either a PosixPath or a WindowsPath object depending on the operating system.

When we subclass Path, the __new__ method is inherited, and since cls is not pathlib.Path, In the previous example, cls is __main__.EnhancePath, so it will not change cls to PosixPath or WindowsPath.

So, we need to optimize our code like this:

import sys
from pathlib import Path

class EnhancePath(Path if sys.version_info >= (3, 13) else type(Path())):
    def zip(self):
        print('zip file')

EnhancePath.cwd()

type(Path()) will return PosixPath or WindowsPath depending on the operating system,

Comments