`pathlib.PurePath`: Setters for properties

Currently, if you want to modify a pathlib object’s property, you need to do the following:

obj = base / 'foo' / 'bar.txt'
obj = obj.with_stem(obj.stem + '_release')
# results in {base}/foo/bar_release.txt

However, it seems native to write the following:

obj = base / 'foo' / 'bar.txt'
obj.stem += '_release'
# results in {base}/foo/bar_release.txt

This is quite useful when changing only part of a filename, like name, stem, or suffix, especially when you do so inside a single-line conditional block.

file_to_copy = base / 'foo' / 'bar.zip'
if (platform == 'linux')
    file_to_copy.suffix = '.tar.gz'
if ('x86' in arch):
    file_to_copy.stem += '-x86'
if (use_backup):
    file_to_copy.name += '.bak'
# e.t.c.
1 Like

Making paths mutable would break their hashability, preventing from using them as dict keys, etc. (It would also make them deviate from strings.)

8 Likes

Thought about this too. There’s a dilemma between nice syntax sugar & immutability. A possible solution can be derived class with mutable fields.

Like:

file_to_copy = (base / 'foo' / 'bar.zip').mutable
if (platform == 'linux')
    file_to_copy.suffix = '.tar.gz'
if ('x86' in arch):
    file_to_copy.stem += '-x86'
if (use_backup):
    file_to_copy.name += '.bak'
1 Like

An alternative would be extending the set of methods that it supports. E.g., instead of having to do

somepath = somepath.with_stem(path.stem + "stem_suffix")

we could do

somepath = path.stem_add("stem_suffix")
# this would return a new Path/PurePath/etc. object

This preserves immutability and nicely mirrors str’s behaviour with its methods.

A better name than stem_add can probably be thought of, but the idea is there.

I don’t understand what this ptoposal has to do with immutability? You can do inplace operations with both strings and tuples and it works fine because a new object is created in the process. I assume the same would apply here

The proposed API allows path.stem = "foo" and such. There is no dunder that path can implement for this to assign a new object to path. It could implement __setattr__ in a special way that would modify it differently than “set the stem attribute”, but it cannot give a new object.

3 Likes

Yes, you can, but the immutability applies to the entire object, not to one single attribute. In order to get “mutability by creating a new object” to work, you would need something like this:

path = Path(...)
original = path
path.stem += "_release"
assert path is not original

This is perfectly possible with strings, since you go some_string += some_value and it reassigns some_string, but to do this on the entire object would be quite weird. You’d need to come up with some sort of API that allows it, and that’s basically going to come right back around to the with_stem() method.

1 Like

Ok, I gotcha!

The immutability of Path makes it easy, clear, and safe.

1 Like

An alternative would be adding methods that change the different parts of it. E.g., stem_add for appending to the stem.

1 Like