6

I want to insert a directory name in the middle of a given file path, like this:

directory_name = 'new_dir'
file_path0 = 'dir1/dir2/dir3/dir4/file.txt'
file_path1 = some_func(file_path0, directory_name, position=2)
print(file_path1)
>>> 'dir1/dir2/new_dir/dir3/dir4/file.txt'

I looked through the os.path and pathlib packages, but it looks like they don't have a function that allows for inserting in the middle of a file path. I tried:

import sys,os
from os.path import join

path_ = file_path0.split(os.sep)
path_.insert(2, 'new_dir')
print(join(path_))

but this results in the error

"expected str, bytes or os.PathLike object, not list"

Does anyone know standard python functions that allow such inserting in the middle of a file path? Alternatively - how can I turn path_ to something that can be processed by os.path. I am new to pathlib, so maybe I missed something out there


Edit: Following the answers to the question I can suggest the following solutions:

1.) As Zach Favakeh suggests and as written in this answer just correct my code above to join(*path_) by using the 'splat' operator * and everything is solved.

2.) As suggested by buran you can use the pathlib package, in very short it results in:

from pathlib import PurePath

path_list = list(PurePath(file_path0).parts)
path_list.insert(2, 'new_dir')
file_path1 = PurePath('').joinpath(*path_list)

print(file_path1)
>>> 'dir1/dir2/new_dir/dir3/dir4/file.txt'
NeStack
  • 1,739
  • 1
  • 20
  • 40
  • I don't think this is directly related to your problem, but FYI: you don't need to import numpy to insert a value into a list. `my_list.insert(index, value)` works fine on its own. – Kevin Aug 19 '19 at 19:16
  • @Kevin Thanks for the comment, it doesn't change the result, but it makes more sense to use your simpler suggestion, so I corrected my code – NeStack Aug 20 '19 at 00:19

6 Answers6

4

Take a look at pathlib.PurePath.parts. It will return separate components of the path and you can insert at desired position and construct the new path

>>> from pathlib import PurePath
>>> file_path0 = 'dir1/dir2/dir3/dir4/file.txt'
>>> p = PurePath(file_path0)
>>> p.parts
('dir1', 'dir2', 'dir3', 'dir4', 'file.txt')
>>> spam = list(p.parts)
>>> spam.insert(2, 'new_dir')
>>> new_path = PurePath('').joinpath(*spam)
>>> new_path
PurePosixPath('dir1/dir2/new_dir/dir3/dir4/file.txt')

This will work with path as a str as well as with pathlib.Path objects

buran
  • 13,682
  • 10
  • 36
  • 61
  • Thanks, it is indeed a possible solution! I made an edit to my question summarizing your code as a TLDR for future readers – NeStack Aug 20 '19 at 18:04
  • 1
    Looks like the cleanest solution to me. Also works great with `spam.insert(-1, 'new_dir')` to insert a folder directly before the last subfolder, as I needed it. – Laurin Herbsthofer Sep 23 '21 at 08:06
2

Since you want to use join on a list to produce the pathname, you should do the following using the "splat" operator: Python os.path.join() on a list

Edit: You could also take your np array and concatenate its elements into a string using np.array2string, using '/' as your separator parameter:https://docs.scipy.org/doc/numpy-1.14.0/reference/generated/numpy.array2string.html

Hope this helps.

Zach Favakeh
  • 227
  • 1
  • 7
  • 1
    The question is about inserting a string in another string (which happens to be a path, not necessarily to an existing file, not necessarily on an accessible disk...). This has nothing to do with navigating existing directories. –  Aug 19 '19 at 19:35
  • Your suggestion of np.array2string works somehow, but it returns strings of the form `['dir1'/'dir2'/'new_dir'/'dir3'/'dir4'/'file.tx']'`, so I need to also get rid of the quotation signs. On the other hand your reference to `os.path.join()` on a list, and using `os.path.join(*file_path_list)`, resolves the error message in my question and solves my problem. If you put this reference to the top of your post I can accept it as the answer. – NeStack Aug 20 '19 at 00:00
1

Solution using regex. The regex will create groups of the following

[^\/]+   - non-'/' characters(i.e. directory names)
\w+\.\w+ - word characters then '.' then word characters (i.e. file name)
import re

directory_name = 'new_dir'
file_path0 = 'dir1/dir2/dir3/dir4/file.txt'
position = 2

regex = re.compile(r'([^\/]+|\w+\.\w+)')
tokens = re.findall(regex, file_path0)
tokens.insert(position, directory_name)
file_path1 = '/'.join(tokens)

Result:

'dir1/dir2/new_dir/dir3/dir4/file.txt'
TomNash
  • 3,147
  • 2
  • 21
  • 57
  • and ... Windows? This _really_ doesn’t look like a job for the regex hammer to me. You can split on **os.path.sep** easily enough. – JL Peyret Aug 20 '19 at 16:56
1

Your solution has only one flaw. After inserting the new directory in the path list path_.insert(2, 'new_dir')you need to call os.path.join(*path_) to get the new modified path. The error that you get is because you are passing a list as parameter to the join function, but you have to unpack it.

JLD
  • 89
  • 5
1

In my case, I knew the portion of path that would precede the insertion point (i.e., "root"). However, the position of the insertion point was not constant due to the possibility of having varying number of path components in the root path. I used Path.relative_to() to break the full path to yield an insertion point for the new_dir.

from pathlib import Path

directory_name = Path('new_dir')
root = Path('dir1/dir2/')
file_path0 = Path('dir1/dir2/dir3/dir4/file.txt')

# non-root component of path
chld = file_path0.relative_to(root)
file_path1 = root / directory_name / chld
print(file_path1)

Result:
'dir1/dir2/new_dir/dir3/dir4/file.txt'

user2514157
  • 545
  • 6
  • 24
0

I made a try with your need:

directory_name = '/new_dir'

file_path0 = 'dir1/dir2/dir3/dir4/file.txt'

before_the_newpath = 'dir1/dir2'

position = file_path0.split(before_the_newpath)

new_directory = before_the_newpath + directory_name + position[1]

Hope it helps.

  • Thanks for the answer, it works. Though it requires that I explicitly specify `before_the_newpath`, so it is not exactly what I want - I want to just give the position where I want to place the new element in the path – NeStack Aug 20 '19 at 00:22