A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from http://stackoverflow.com/questions/29850801/simple-subclassing-pathlib-path-does-not-work/29854141 below:

oop - Subclass `pathlib.Path` fails

I would like to enhance the class pathlib.Path but the simple example above dose not work.

from pathlib import Path

class PPath(Path):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

test = PPath("dir", "test.txt")

Here is the error message I have.

Traceback (most recent call last):
  File "/Users/projetmbc/test.py", line 14, in <module>
    test = PPath("dir", "test.txt")
  File "/anaconda/lib/python3.4/pathlib.py", line 907, in __new__
    self = cls._from_parts(args, init=False)
  File "/anaconda/lib/python3.4/pathlib.py", line 589, in _from_parts
    drv, root, parts = self._parse_args(args)
  File "/anaconda/lib/python3.4/pathlib.py", line 582, in _parse_args
    return cls._flavour.parse_parts(parts)
AttributeError: type object 'PPath' has no attribute '_flavour'

What I am doing wrong ?

asked Apr 24, 2015 at 14:57

projetmbcprojetmbc

1,49411 gold badge1313 silver badges2828 bronze badges

2

You can subclass the concrete implementation, so this works:

class Path(type(pathlib.Path())):

Here's what I did with this:

import pathlib

class Path(type(pathlib.Path())):
    def open(self, mode='r', buffering=-1, encoding=None, errors=None, newline=None):
        if encoding is None and 'b' not in mode:
            encoding = 'utf-8'
        return super().open(mode, buffering, encoding, errors, newline)

Path('/tmp/a.txt').write_text("я")

answered Dec 6, 2015 at 11:11

Oleh PrypinOleh Prypin

34.3k1111 gold badges9494 silver badges100100 bronze badges

4

Combining some of the previous answers you could also just write:

class MyPath(pathlib.Path):
    _flavour = type(pathlib.Path())._flavour
UPDATE for Python 3.12

In Python 3.12 the pathlib.Path class now supports subclassing (see What’s New In Python 3.12). Therefore, you can simply access the _flavour attribute from your subclass without any workaround.

answered Mar 13, 2021 at 12:11

Night TrainNight Train

2,59633 gold badges2222 silver badges4040 bronze badges

3

Here is the definition of the Path class. It does something rather clever. Rather than directly returning an instance of Path from its __new__(), it returns an instance of a subclass, but only if it's been invoked directly as Path() (and not as a subclass).

Otherwise, it expects to have been invoked via either WindowsPath() or PosixPath(), which both provide a _flavour class attribute via multiple inheritance. You must also provide this attribute when subclassing. You'll probably need to instantiate and/or subclass the _Flavour class to do this. This is not a supported part of the API, so your code might break in a future version of Python.

TL;DR: This idea is fraught with peril, and I fear that my answers to your questions will be interpreted as approval rather than reluctant assistance.

answered Apr 24, 2015 at 15:09

KevinKevin

30.3k1111 gold badges6666 silver badges8888 bronze badges

4

You may be able to simplify your life depending on why you want to extend Path (or PosixPath, or WindowsPath). In my case, I wanted to implement a File class that had all the methods of Path, and a few others. However, I didn't actually care if isinstance(File(), Path).

Delegation works beautifully:

class File:

    def __init__(self, path):
        self.path = pathlib.Path(path)
        ...

    def __getattr__(self, attr):
        return getattr(self.path, attr)

    def foobar(self):
        ...

Now, if file = File('/a/b/c'), I can use the entire Path interface on file, and also do file.foobar().

answered Mar 1, 2020 at 4:37

4

I have been struggling with this too.

Here is what i did, studying from the pathlib module. Seems to me that is the cleaner way to do it, but if the pathlib module changes its implementation, it probably won't hold.

from pathlib import Path
import os
import pathlib

class PPath(Path):

    _flavour = pathlib._windows_flavour if os.name == 'nt' else pathlib._posix_flavour

    def __new__(cls, *args):
        return super(PPath, cls).__new__(cls, *args)

    def __init__(self, *args):
        super().__init__() #Path.__init__ does not take any arg (all is done in new)
        self._some_instance_ppath_value = self.exists() #Path method

    def some_ppath_method(self, *args):
        pass

test = PPath("dir", "test.txt")

answered Nov 9, 2018 at 18:07

A. MarchandA. Marchand

33933 silver badges44 bronze badges

Note

I have opened a bug track here after a little discussion on the Python dev. list.

A temporary solution

Sorry for this double answer but here is a way to achieve what I want. Thanks to Kevin that points me to the source of pathlib and the fact we have here constructors.

import pathlib
import os

def _extramethod(cls, n):
    print("=== "*n)

class PathPlus(pathlib.Path):
    def __new__(cls, *args):
        if cls is PathPlus:
            cls = pathlib.WindowsPath if os.name == 'nt' else pathlib.PosixPath

        setattr(cls, "extramethod", _extramethod)

        return cls._from_parts(args)

test = PathPlus("C:", "Users", "projetmbc", "onefile.ext")

print("File ?", test.is_file())
print("Dir  ?", test.is_dir())
print("New name:", test.with_name("new.name"))
print("Drive ?", test.drive)

test.extramethod(4)

This prints the following lines.

File ? False
Dir  ? False
New name: C:/Users/projetmbc/new.name
Drive ? 
=== === === === 
Anthon

77.9k3434 gold badges206206 silver badges287287 bronze badges

answered Apr 26, 2015 at 16:11

projetmbcprojetmbc

1,49411 gold badge1313 silver badges2828 bronze badges

2

With the latest Python version, _flavour, _posix_flavour are deprecated and we can pass flavour keyword in our class.

import os
from pathlib import Path


class PPath(Path):
    def __init__(self, *args) -> None:
        # Determine the flavor based on the operating system
        flavour = 'posix' if os.name == 'posix' else 'windows'

        # Pass the flavor to the superclass constructor
        super().__init__(*args, flavour=flavour)
Barmar

787k5757 gold badges552552 silver badges663663 bronze badges

answered Aug 20, 2024 at 2:41

Chillar AnandChillar Anand

29.8k1010 gold badges124124 silver badges144144 bronze badges

2

It's work too.

from pathlib import Path

class SystemConfigPath(type(Path())):
    def __new__(cls, **kwargs):
        path = cls._std_etc()
        return super().__new__(cls, path, **kwargs)

    @staticmethod
    def _std_etc():
        return '/etc'

name = SystemConfigPath()
name = name / 'apt'
print(name)

Printed:

/etc/apt

@staticmethod can be replaced by @classmethod

answered Aug 6, 2018 at 2:51

In order to inherit from pathlib.Path, you need to specify which OS, or "flavour" you're representing. All you need to do is specify that you are using either Windows or Unix (seems to be Unix based on your traceback) by inheriting from pathlib.PosixPath or pathlib.WindowsPath.

import pathlib

class PPath(pathlib.PosixPath):
    pass

test = PPath("dir", "test.txt")
print(test)

Which outputs:

dir\test.txt

Using type(pathlib.Path()) as proposed in this answer does the exact same thing as directly inheriting from pathlib.PosixPath or pathlib.WindowsPath since instantiating pathlib.Path "creates either a PosixPath or a WindowsPath" (pathlib documentation).

If you know your application will not be cross-platform, it is simpler to directly inherit from the flavor Path that represents your OS.

answered Sep 30, 2021 at 16:45

Chris CollettChris Collett

1,2981313 silver badges1818 bronze badges

Here is a simple way to do things regarding to the observation made by Kevin.

class PPath():
    def __init__(self, *args, **kwargs):
        self.path = Path(*args, **kwargs)

Then I will need to use a trick so as to automatically bind all the Path's methods to my PPpath class. I think that will be funny to do.

answered Apr 24, 2015 at 17:44

projetmbcprojetmbc

1,49411 gold badge1313 silver badges2828 bronze badges

5

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4