Abstract class from a concrete class in Python

93 views Asked by At

With the release of Python 3.12, pathlib.Path can now be subclassed. I want to create a subclass CustomPath(Path) for non-os environments (ftp, sftp, s3 storage, etc.), meaning I have to re-implemented (almost) all methods.

I want to make sure that CustomPathis only using methods which are defined in the subclass, to prevent accidentally using methods from the parent Path class. In order to do this, I want to use only the interface (abstract class) of Path. (Since Path may be updated to include new methods beyond my control.)

What is the most pythonic way of doing this? (It might be the case that it is not appropriate to subclass at all.)


Here's an example of expected behavior:

class S3Path(pathlib.Path):
    @classmethod
    def from_connection(cls, ...):
        ...  # custom implementation

    def read_text(self, encoding=None, errors=None):
        ...  # custom implementation


s3path = S3Path.from_connection(...)

text = s3path.read_text()
s3path.write_text(text)  # should raise NotImplementedError
2

There are 2 answers

1
barneygale On BEST ANSWER

I am the current pathlib maintainer. I'm looking to add pathlib ABCs in future, and in fact they already exist (privately) in CPython. For the time being you may wish to use the "pathlib-abc" PyPI package, which is a straight copy-paste of the private functionality.

0
Andrii On

I can see two options:

OPTION 1: override parent methods you want to 'hide' by providing an empty body like here:

class MyPath(pathlib.Path):
    def is_dir(self):
        pass

OPTION 2: Since you don't want to use any methods of the base class I suggest using plain class instead of inheritance. It'll prevent you from using parent class methods accidentally. Just implement the methods you need according to the pathlib.Path specification and your requirements.

Here's an example of how you can implement this:

import pathlib

class MyPath:
    def __init__(self, path):
        self._path = path

    def exists(self):
        return r'custom implementation of 'exists''

    ######## any other methods

# Example usage:
my_path = MyPath('/path/to/file')
print(my_path.exists())