Search code examples
pythonfile-iopathdirectorypathlib

Open a file from a different parent directory, using the current files name as a variable in the path Python


I have a folder structure like

C:\Users\chale\
├── sql-files
│   ├── source1.sql
│   └── source2.sql
├── python-files
│   ├── source1.py
│   └── source2.py
├── extract-files
│   ├── source1.csv
│   └── source2.csv

I am trying to write a generic way to open the corresponding sql file based on the python file that I am running, and then I perform some pandas data transformations on my sql extracted data and write it to extract-files, again with the same name as the python file running.

I cannot seem to target the correct directory though to open the sql file.

import os
from pathlib import Path

# get the current path of the python file
fullPath = Path(os.path.dirname(__file__))
# create a list of the parts of the current absolute path
fullPathSplit= os.path.dirname(__file__).split('\\')
# get name of the current file, and isolate the name from the file type
fileName = os.path.basename(__file__).split('.')[0]
print(os.path.join(*fullPathSplit[:len(fullPathSplit)-1], 'sql-files', fileName+'.sql'))
# open the corresponding sql file to read
file = open(os.path.join(*fullPathSplit[:len(fullPathSplit)-1], 'sql-files', fileName+'.sql'), 'r')

The output of my print statement above is c:Users\chale\sql-files\source1.sql

but I get an error from the open statement

Traceback (most recent call last):
  File "c:\Users\chale\\python-files\source1.py", line 14, in <module>
    file = open(os.path.join(*destinationTable[:len(destinationTable)-1], 'sql-files', fileName+'.sql'), 'r')
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
FileNotFoundError: [Errno 2] No such file or directory: 'c:Users\\chale\\sql-files\\source1.sql'

The file I am trying to open, opens fine when I hard code the printed value with a slash between c: and Users as a raw string to open

file = open(r'C:\Users\chale\sql-files\source1.sql', 'r')

I have it working using the below code which strips out the c: from the fullPathSplit and then I manually add it in with a slash to join, but I do not understand why it does not join normally.

pathToOpen = os.path.join('C:\\', *fullPathSplit[1:len(fullPathSplit)-1], 'sql-files', fileName+'.sql')
file = open(pathToOpen, 'r')

I don't understand what discussed in the documentation here which I think is the issue. Why do I get a relative path (like c:foo) from my os.path.join? Or maybe my question is, can I configure open to take a relative path like c:foo rather than needing the absolute path? https://docs.python.org/3/library/os.path.html#os.path.join "On Windows, the drive is not reset when a rooted path segment (e.g., r'\foo') is encountered. If a segment is on a different drive or is an absolute path, all previous segments are ignored and the drive is reset. Note that since there is a current directory for each drive, os.path.join("c:", "foo") represents a path relative to the current directory on drive C: (c:foo), not c:\foo."


Solution

  • C:xxx and C:\xxx have two different meanings: "path relative to current directory of drive C:" vs. "absolute path from root of drive C:". That's why you explicitly have to add the backslash.

    Stick to Path methods and things are more simple:

    import os
    from pathlib import Path
    
    script_path = Path(__file__)
    root = script_path.parent.parent
    sql_path = root / 'sql-files' / (script_path.stem + '.sql')
    extract_path = root / 'extract-files' / (script_path.stem + '.csv')
    print(f'{script_path=}')
    print(f'{sql_path=}')
    print(f'{extract_path=}')
    

    Output for source1.py:

    script_path=WindowsPath('C:/Users/chale/python-files/source1.py')
    sql_path=WindowsPath('C:/Users/chale/sql-files/source1.sql')
    extract_path=WindowsPath('C:/Users/chale/extract-files/source1.csv')