10.3. File Path Errors

10.3.1. Recap

  • Raw Strings

  • Always use raw-strings (r"...") for paths

  • Raw String turns-off escape characters

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

Problem is with \Users. After escape sequence \U... Python expects hexadecimal Unicode codepoint, i.e. '\U0001F680' which is a rocket 🚀 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 s isn't one of them.

10.3.2. Setup

>>> from pathlib import Path
>>> Path('/tmp/myfile.txt').unlink(missing_ok=True)

10.3.3. Escaping Characters in Path

  • "\ " (backslash space) - escapes space

  • Note that in Python escapes in paths are not required

>>> FILE = '/tmp/my file.txt'
>>> FILE = r'/tmp/my file.txt'
>>> FILE = r'C:\Users\Admin\myfile.txt'
>>>
>>>
>>> repr(FILE)
"'C:\\\\Users\\\\Admin\\\\myfile.txt'"
>>>
>>> str(FILE)
'C:\\Users\\Admin\\myfile.txt'
>>>
>>> print(repr(FILE))
'C:\\Users\\Admin\\myfile.txt'
>>>
>>> print(FILE)
C:\Users\Admin\myfile.txt

10.3.4. FileNotFoundError

>>> open('/tmp/myfile.txt')
Traceback (most recent call last):
FileNotFoundError: [Errno 2] No such file or directory: '/tmp/myfile.txt'
>>> try:
...     file = open('/tmp/myfile.txt')
... except FileNotFoundError:
...     print('Sorry, file not found')
Sorry, file not found

10.3.5. PermissionError

>>> open('/etc/sudoers')  
Traceback (most recent call last):
PermissionError: [Errno 13] Permission denied: '/etc/sudoers'
>>> 
... try:
...     file = open('/etc/sudoers')
... except PermissionError:
...     print('Sorry, permission denied')
Sorry, permission denied

10.3.6. IsADirectoryError

>>> open('/tmp')
Traceback (most recent call last):
IsADirectoryError: [Errno 21] Is a directory: '/tmp'
>>> try:
...     file = open('/tmp')
... except IsADirectoryError:
...     print('Sorry, path leads to directory')
Sorry, path leads to directory

10.3.7. Use Case - 0x01

>>> try:
...     file = open('/tmp/myfile.txt')
... except FileNotFoundError:
...     print('Sorry, file not found')
... except PermissionError:
...     print('Sorry, permission denied')
... except IsADirectoryError:
...     print('Sorry, path leads to directory')
Sorry, file not found

10.3.8. Assignments

Code 10.5. Solution
"""
* Assignment: File Path Exception
* Type: class assignment
* Complexity: easy
* Lines of code: 6 lines
* Time: 3 min

English:
    1. Modify `result` function
    2. If `filename` exists, print 'Ok'
    3. If `filename` does not exist, print 'File not found'
    4. Run doctests - all must succeed

Polish:
    1. Zmodyfikuj funkcję `result`
    2. Jeżeli `filename` istnieje, wypisz 'Ok'
    3. Jeżeli `filename` nie istnieje, wypisz 'File not found'
    4. Uruchom doctesty - wszystkie muszą się powieść

Hints:
    * `try`
    * `except`
    * `else`
    * `open()`

Tests:
    >>> import sys; sys.tracebacklimit = 0
    >>> from inspect import isfunction

    >>> assert result is not Ellipsis, \
    'Assign your result to variable `result`'

    >>> assert isfunction(result), \
    'Variable `result` has invalid type, should be function'

    >>> result(__file__)
    Ok
    >>> result('_notexisting.txt')
    File not found
"""


def result(filename):
    ...


Code 10.6. Solution
"""
* Assignment: File Path Abspath
* Type: class assignment
* Complexity: easy
* Lines of code: 3 lines
* Time: 5 min

English:
    1. Define `path` with converted `filename` to absolute path
    2. To `result` assgin string:
        a. `file` if path is a file
        b. `directory` if path is a directory
        c. `missing` if path does not exist
    3. Run doctests - all must succeed

Polish:
    1. Zdefiniuj `path` z przekonwertowym `filename` do ścieżki bezwzględnej
    2. Do `result` przypisz ciąg znaków:
        a. `file` jeżeli ścieżka jest plikiem
        b. `directory` jeżeli ścieżka jest katalogiem
        c. `missing` jeżeli ścieżka nie istnieje
    3. Uruchom doctesty - wszystkie muszą się powieść

Hints:
    * `from pathlib import Path`
    * `Path.cwd()`
    * `Path()`
    * `Path.is_dir()`
    * `Path.is_file()`
    * `Path.exists()`

Tests:
    >>> import sys; sys.tracebacklimit = 0

    >>> assert isinstance(result, str), \
    'Result must be a str with: `file`, `directory` or `missing`'

    >>> assert isinstance(abspath, Path), \
    'Use Path class from pathlib library to create a filepath'

    >>> current_directory = Path.cwd()
    >>> assert str(current_directory) in str(abspath), \
    'File Path must be absolute, check if you have current directory in path'

    >>> result
    'missing'
"""

from pathlib import Path


FILENAME = 'myfile.txt'

# Absolute path to FILENAME
# type: Path
abspath = ...

# File, directory or missing
# type: str
result = ...