10

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") 

Attempts

1

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'.

2

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.

3

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.

Question

How can I easily rename the file's parent folder?

3 Answers 3

9

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) 
Sign up to request clarification or add additional context in comments.

Comments

3

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

Comments

0

EDIT: Found a cleaner solution without str()

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].

Hack like solution

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?

1 Comment

The cleaner solution is definitely writing a function like suggested by hume, then using the function.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.