17.1. Pathlib About

  • Relative paths are relative to the current working directory

  • Absolute paths start with root directory

  • Python works with both relative and absolute path

17.1.1. Relative Paths

  • Path is relative to currently running script

  • Relative paths works the same on Windows and *nix (Linux, macOS, BSD, etc.)

  • . - Current directory

  • .. - Parent directory

Current directory:

>>> file = 'myfile.csv'
>>> file = 'data/myfile.csv'
>>> file = 'data/csv/myfile.csv'
>>> file = './myfile.csv'
>>> file = './data/myfile.csv'
>>> file = './data/csv/myfile.csv'

Parent directory:

>>> file = '../myfile.csv'
>>> file = '../data/myfile.csv'
>>> file = '../data/csv/myfile.csv'
>>> file = '../../myfile.csv'
>>> file = '../../data/myfile.csv'
>>> file = '../../data/csv/myfile.csv'
>>> file = '../../../myfile.csv'
>>> file = '../../../data/myfile.csv'
>>> file = '../../../data/csv/myfile.csv'

17.1.2. Absolute Paths

  • Absolute path include all entries in the directories hierarchy

  • Absolute path on *nix starts with root / dir

  • Absolute path on Windows starts with drive letter

Linux (and other *nix):

>>> file = '/home/myuser/newfile.csv'

macOS:

>>> file = '/Users/myuser/newfile.csv'

Windows:

>>> file = 'c:/Users/myuser/newfile.csv'

17.1.3. Windows Path Problem

  • Problem with paths on Windows

  • Use backslash (\\) as a path separator

  • Use r-string for paths

Let's say we have a path to a file:

>>> print('C:/Users/myuser/newfile.txt')
C:/Users/myuser/newfile.txt

Paths on Windows do not use slashes (/). You must use backslash (\\) as a path separator. This is where all problems starts. Let's start changing slashes to backslashes from the end (the one before newfile.txt):

>>> print('C:/Users/myuser\newfile.txt')
C:/Users/myuser
ewfile.txt

This is because \n is a newline character. In order this to work we need to escape it.

Now lets convert another slash to backslash, this time the one before directory named myuser:

>>> print('C:/Users\myuser\\newfile.txt')
SyntaxWarning: invalid escape sequence '\m'
C:/Users\myuser\newfile.txt

Since Python 3.12 all non-existing escape characters (in this case \m will need to be escaped or put inside of a row strings. This is only a warning (SyntaxWarning: invalid escape sequence '\m', so we can ignore it, but this behavior will be default sometime in the future, so it is better to avoid it now.

The last slash (the one before Users):

>>> print('C:\Users\\myuser\\newfile.txt')
Traceback (most recent call last):
SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 2-3: truncated \UXXXXXXXX escape

This time the problem is more serious. Problem is with \Users. After escape sequence \U Python expects hexadecimal Unicode codepoint, i.e. \U0001F600 which is a smiley 😀 emoticon emoticon. In this example, Python finds letter s, which is invalid hexadecimal character and therefore raises an SyntaxError telling user that there is an error with decoding bytes. The only valid hexadecimal numbers are 0123456789abcdefABCDEF and letter s isn't one of them.

There is two ways how you can avoid this problem. Using escape before every slash:

>>> print('C:\\Users\\myuser\\newfile.txt')
C:\Users\myuser\newfile.txt

Or use r-string:

>>> print(r'C:\Users\myuser\newfile.txt')
C:\Users\myuser\newfile.txt

Both will generate the same output, so you can choose either one. In my opinion r-strings are less error prone and I use them each time when I have to deal with paths.

17.1.4. Convention

  • Never hardcode paths, use constant as a file name or file path

  • Convention (singular form): FILE, FILENAME, FILEPATH, PATH

  • Convention (plural form): FILES, FILENAMES, FILEPATHS, PATHS

  • Note, that PATH is usually used for other purposes (sys.path or os.getenv('PATH'))

>>> FILE = 'myfile.txt'
>>> FILES = [
...     'myfile1.txt',
...     'myfile2.txt',
...     'myfile3.txt',
... ]

17.1.5. Current Working Directory

  • Get current working directory with Path.cwd()

>>> from pathlib import Path
>>>
>>> result = Path.cwd()
>>> print(result)
/home/myuser/myproject

17.1.6. Running File

  • Get path of the running script

>>> from pathlib import Path
>>>
>>> result = Path(__file__)
>>> print(result)
/home/myuser/myproject/myfile.py

17.1.7. Running Directory

  • Get directory of the running script

  • Base directory

>>> from pathlib import Path
>>>
>>> result = Path(__file__).parent
>>> print(result)
/home/myuser/myproject

17.1.8. Recap

  • Relative paths are relative to the current working directory

  • Absolute paths start with root directory

  • Python works with both relative and absolute path

  • Path separator / (slash) is used on *nix operating systems: Linux, macOS, BSD and other POSIX compliant OSes (excluding older versions of Windows)

  • Path separator \ (backslash) is used on Windows

  • In newer Windows versions both \ and / works the same

  • . - Current directory

  • .. - Parent directory

  • Absolute path on *nix starts with root / dir

  • Absolute path on Windows starts with drive letter

  • Never hardcode paths, use constant as a file name or file path

  • On Windows use r-string for paths

17.1.9. Assignments

# %% About
# - Name: Pathlib About File
# - Difficulty: easy
# - Lines: 1
# - Minutes: 1

# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% English
# 1. Create Path object for file `FILE`
# 2. Define variable `result: Path` with the solution
# 3. Use `pathlib` built-in module
# 4. Run doctests - all must succeed

# %% Polish
# 1. Utwórz obiekt Path dla pliku `FILE`
# 2. Zdefiniuj zmienną `result: Path` z rozwiązaniem
# 3. Use `pathlib` built-in module
# 4. Uruchom doctesty - wszystkie muszą się powieść

# %% Expected

# %% Hints
# - `pathlib.Path()`

# %% Doctests
"""
>>> import sys; sys.tracebacklimit = 0

>>> assert sys.version_info >= (3, 10), \
'Python has an is invalid version; expected: `3.10` or newer.'

>>> assert 'result' in globals(), \
'Variable `result` is not defined; assign result of your program to it.'

>>> assert result is not Ellipsis, \
'Variable `result` has an invalid value; assign result of your program to it.'

>>> assert isinstance(result, Path), \
'Variable `result` has invalid type; expected: `Path`.'
"""

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -f -v myfile.py`

# %% Imports
from pathlib import Path

# %% Types
result: Path

# %% Data
FILE = '_temporary.txt'

# %% Result
result = ...

# %% About
# - Name: Pathlib About Directory
# - Difficulty: easy
# - Lines: 1
# - Minutes: 1

# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% English
# 1. Create Path object for directory `DIRECTORY`
# 2. Define variable `result: Path` with the solution
# 3. Use `pathlib` built-in module
# 4. Run doctests - all must succeed

# %% Polish
# 1. Utwórz obiekt Path dla katalogu `DIRECTORY`
# 2. Zdefiniuj zmienną `result: Path` z rozwiązaniem
# 3. Use `pathlib` built-in module
# 4. Uruchom doctesty - wszystkie muszą się powieść

# %% Expected

# %% Hints
# - `pathlib.Path()`

# %% Doctests
"""
>>> import sys; sys.tracebacklimit = 0

>>> assert sys.version_info >= (3, 10), \
'Python has an is invalid version; expected: `3.10` or newer.'

>>> assert 'result' in globals(), \
'Variable `result` is not defined; assign result of your program to it.'

>>> assert result is not Ellipsis, \
'Variable `result` has an invalid value; assign result of your program to it.'

>>> assert isinstance(result, Path), \
'Variable `result` has invalid type; expected: `Path`.'
"""

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -f -v myfile.py`

# %% Imports
from pathlib import Path

# %% Types
result: Path

# %% Data
DIRECTORY = '.'

# %% Result
result = ...

# %% About
# - Name: Pathlib About CWD
# - Difficulty: easy
# - Lines: 1
# - Minutes: 1

# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% English
# 1. Create Path object for current working directory
# 2. Define variable `result: Path` with the solution
# 3. Use `pathlib` built-in module
# 4. Run doctests - all must succeed

# %% Polish
# 1. Utwórz obiekt Path dla bieżącego katalogu roboczego
# 2. Zdefiniuj zmienną `result: Path` z rozwiązaniem
# 3. Use `pathlib` built-in module
# 4. Uruchom doctesty - wszystkie muszą się powieść

# %% Expected

# %% Hints
# - `pathlib.Path()`
# - `Path.cwd()`

# %% Doctests
"""
>>> import sys; sys.tracebacklimit = 0

>>> assert sys.version_info >= (3, 10), \
'Python has an is invalid version; expected: `3.10` or newer.'

>>> cwd = Path.cwd()

>>> assert 'result' in globals(), \
'Variable `result` is not defined; assign result of your program to it.'

>>> assert result is not Ellipsis, \
'Variable `result` has an invalid value; assign result of your program to it.'

>>> assert isinstance(result, Path), \
'Variable `result` has invalid type; expected: `Path`.'

>>> assert result == cwd, \
'Variable `result` has invalid value; expected current working directory path.'
"""

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -f -v myfile.py`

# %% Imports
from pathlib import Path

# %% Types
result: Path

# %% Data

# %% Result
result = ...

# %% About
# - Name: Pathlib About CurrentFile
# - Difficulty: easy
# - Lines: 1
# - Minutes: 1

# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% English
# 1. Create Path object for file with the running script
# 2. Define variable `result: Path` with the solution
# 3. Use `pathlib` built-in module
# 4. Run doctests - all must succeed

# %% Polish
# 1. Utwórz obiekt Path dla pliku z uruchamianym skryptem
# 2. Zdefiniuj zmienną `result: Path` z rozwiązaniem
# 3. Use `pathlib` built-in module
# 4. Uruchom doctesty - wszystkie muszą się powieść

# %% Expected

# %% Hints
# - `pathlib.Path()`

# %% Doctests
"""
>>> import sys; sys.tracebacklimit = 0

>>> assert sys.version_info >= (3, 10), \
'Python has an is invalid version; expected: `3.10` or newer.'

>>> assert 'result' in globals(), \
'Variable `result` is not defined; assign result of your program to it.'

>>> assert result is not Ellipsis, \
'Variable `result` has an invalid value; assign result of your program to it.'

>>> assert isinstance(result, Path), \
'Variable `result` has invalid type; expected: `Path`.'
"""

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -f -v myfile.py`

# %% Imports
from pathlib import Path

# %% Types
result: Path

# %% Data

# %% Result
result = ...

# %% About
# - Name: Pathlib About CurrentDirectory
# - Difficulty: easy
# - Lines: 1
# - Minutes: 1

# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% English
# 1. Create Path object for directory with the running script
# 2. Define variable `result: Path` with the solution
# 3. Use `pathlib` built-in module
# 4. Run doctests - all must succeed

# %% Polish
# 1. Utwórz obiekt Path dla katalogu z uruchamianym skryptem
# 2. Zdefiniuj zmienną `result: Path` z rozwiązaniem
# 3. Use `pathlib` built-in module
# 4. Uruchom doctesty - wszystkie muszą się powieść

# %% Expected

# %% Hints
# - `pathlib.Path()`

# %% Doctests
"""
>>> import sys; sys.tracebacklimit = 0

>>> assert sys.version_info >= (3, 10), \
'Python has an is invalid version; expected: `3.10` or newer.'

>>> assert 'result' in globals(), \
'Variable `result` is not defined; assign result of your program to it.'

>>> assert result is not Ellipsis, \
'Variable `result` has an invalid value; assign result of your program to it.'

>>> assert isinstance(result, Path), \
'Variable `result` has invalid type; expected: `Path`.'
"""

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -f -v myfile.py`

# %% Imports
from pathlib import Path

# %% Types
result: Path

# %% Data

# %% Result
result = ...