Reputation: 6282
The new Path package from the pathlib library, which has been added from Python 3.4, seems a powerful replacement of approaches such as os.path.join()
, but I've some trouble working with it.
I have a path that can be anything from
folder_foo/file.csv
to
long/path/to/folder_foo/file.csv
I read the .csv
file in folder_foo
with pandas, modify it and want to save it to
folder_bar/file.csv
or
long/path/to/folder_bar/file.csv
Essentially I want to rename folder_foo
to folder_bar
in the Path object.
EDIT: example path code
csv_path = Path("long/path/to/folder_foo/file.csv")
csv_path.parents[0] = csv_path.parents[0] + "_clean")
Which leads to the error TypeError: unsupported operand type(s) for +: 'PosixPath' and 'str'
, which means you cannot use +
to combine a PosixPath
with a str
as described in TypeError: unsupported operand type(s) for +: 'PosixPath' and 'str'.
To solve this I tried the following:
csv_path.parents[0] = Path(str(csv_path.parents[0]) + "_clean")
Which however results in the error : TypeError: '_PathParents' object does not support item assignment
.
Since PosixPath
is not a list, this error is understandable.
Maybe .parts
is a better approach, but
csv_path.parts[-2] = csv_path.parts[-2][:-3] + "bar"
results in: TypeError: 'tuple' object does not support item assignment
.
How can I easily rename the file's parent folder?
Upvotes: 10
Views: 13481
Reputation: 2553
You could also write a little function to replace the part of the path you want to change. Here's a runnable example:
from pathlib import Path
path1 = Path("a/b/c.txt")
path2 = Path("b/c.txt")
def rename_dir(path, src, dst):
# convert to list so that we can change elements
parts = list(path.parts)
# replace part that matches src with dst
parts[parts.index(src)] = dst
return Path(*parts)
rename_dir(path1, 'b', 'q')
#> PosixPath('a/q/c.txt')
rename_dir(path2, 'b', 'q')
#> PosixPath('q/c.txt')
Created at 2021-03-06 10:44:00 PST by reprexlite v0.4.2
Upvotes: 3
Reputation: 131
Would rather split this up for readability:
bar_folder = csv_path.parent.parent / 'folder_bar'
csv_path2 = bar_folder / csv_path.name
Having the destination folder as a variable also enables you to create the folder using for example:
bar_folder.mkdir(exist_ok=True)
Upvotes: 9
Reputation: 6282
csv_path2 = csv_path.parents[1] / (csv_path.parts[-2][:-3] + "bar") / csv_path.parts[-1]
# result
PosixPath('long/path/to/folder_bar/file.csv')
Path.parents
gets the whole path to the folder minus the file. Path.parents[1]
goes 2 levels up (long/path/to/
), which is still a Path object. Then we get the last folder name with csv_path.parts[-2]
, which is a string. We apply [:-3]
to get all string characters except "foo"
. This means we have "folder_"
. Then with + "bar"
we get "folder_bar"
, which is added to our Path
object. Finally we re-add the file name to our Path
object with / csv_path.parts[-1]
.
csv_path = Path(str(csv_path.parents[0])[:-3] + 'bar/' + csv_path.parts[-1])
It seems to me a bit unintuitive, however. There should be a more clean solution?
Upvotes: 0