I'm attempting to create a subclass of pathlib.Path
that will do some manipulation to the passed string path value before passing it along to the base class.
class MyPath(Path):
def __init__(self, str_path):
str_path = str_path.upper() # just representative, not what I'm actually doing
super().__init__(str_path)
However, when I try to use this:
foo = MyPath("/path/to/my/file.txt")
bar = foo / "bar"
I get the following error: TypeError: unsupported operand type(s) for /: 'MyPath' and 'str'
I am using Python 3.12 which I understand to have better support for subclassing Path
MyPath("foo") / "bar'
goes through several steps:
MyPath("foo").__truediv__("bar")
, whichMyPath("foo").with_segments("bar")
, whichMyPath(MyPath("foo"), "bar")
, whichTypeError
because you overrode MyPath.__init__
to only accept a single additional positional argument, whichMyPath.__truediv__
to catch a TypeError
and subsequently return NotImplemented
Your __init__
method must be careful to accept multiple path components, not just a single string, and it must not assume that each argument is an actual string, but rather objects that implement the os.PathLike
interface. (In particular, don't assume that a path component has an upper
method. Call os.fspath
on the component first to retrieve a str
representation that does have an upper
method.)
Something like
import os
class MyPath(Path):
def __init__(self, *paths):
super().__init__(*(os.fspath(x).upper() for x in paths))
and thus
% py312/bin/python -i tmp.py
>>> bar
MyPath('/PATH/TO/MY/FILE.TXT/BAR')
Alternately, as others have alluded to, you can override with_segments
to, for example, combine the segments yourself and pass the single result to MyPath
, but I see no reason to restrict MyPath.__init__
's signature as you currently do.