Powershell has the Split-Path
cmdlet which allows you to extract the Parent and Leaf of a file. In PS version 6, you can extract the extension, with the -Extension
switch. Why this wasn't a feature of PS version 4 and greater I don't know, so I decided to write my own version in Python.
PathUtilities:
# PathUtilities.py
def parse_file_path(file_path : str):
"""
The function a user must call if they want to parse a file path.
It accepts, validates, and returns a tuple containing
the elements (parent, leaf, and extension)
of the path.
The path doesn't haven't exist.
Args:
file_path : str - A string representing a file path.
Returns:
A tuple containing all the parsed elements.
"""
_determine_if_the_drive_letter_is_valid(file_path=file_path)
_determine_if_second_element_is_valid(file_path=file_path)
_determine_if_the_string_contains_forbidden_characters(string_to_validate = file_path[2:])
return _construct_path_tuple(file_path=file_path)
def _determine_if_the_drive_letter_is_valid(file_path : str):
"""
Determines if the drive letter is a letter.
Raises a TypeError if the first letter is invalid.
Args:
file_path - see parse_file_path function.
Returns:
None
"""
drive_letter = file_path[:1]
if not drive_letter.isalpha():
raise TypeError("Drive Letter is invalid.")
def _determine_if_second_element_is_valid(file_path : str):
"""
Determine if the second element in the path is a :
Raises a ValueError if the second element is invalid.
Args:
file_path - see parse_file_path function.
Returns:
None
"""
valid_element = ":"
second_element = file_path[1]
if second_element != valid_element:
raise ValueError("Invalid characters in path.")
def _determine_if_the_string_contains_forbidden_characters(*additional_characters, string_to_validate : str):
"""
Determine if the string contains forbidden elements.
Raises a ValueError if any forbidden character is found.
Args:
string_to_validate : str - The string we're going to test.
*additional_characters - To make the function reusable we accept additional elements to be tested
in addition to the list of forbidden characters.
"""
# Contains all the forbidden characters in Windows paths.
# Note the 4 slashes, because paths use \\ to seperate folders and drives, we have to validate
# if the user entered additional slashes, two slashes is fine, but more are forbidden.
# Example: C:\\Users\\Sveta\\\\\emp_list.txt - invalid.
forbidden_characters = ["<", ">", ":", "/", '"', "|", "?", "*"," ", "\\\\"]
for forbidden_character in forbidden_characters:
if forbidden_character in string_to_validate:
raise ValueError("Invalid characters in path.")
if additional_characters:
for character in additional_characters:
if character in string_to_validate:
raise ValueError("Invalid characters in path.")
def _parse_extension(string_to_parse : str):
"""
Split the file path on the period, validate, and return the extension with the period.
Raises a ValueError if the extension contains forbidden characters.
Args:
file_path - see parse_file_path function
Returns:
the extension of the file or None, if no file extension is present.
"""
# file and folder names are allowed to have periods, so we split on that,
# but we're only interested in the last element, the extension.
split_extension = string_to_parse.split(".")[-1]
# if the string doesn't have a file extension, we return None.
if len(split_extension) == len(string_to_parse):
return None
_determine_if_the_string_contains_forbidden_characters("\\", string_to_validate = split_extension)
return ".{0}".format(split_extension)
def _parse_leaf(file_path : str):
"""
Split the file path using \\ and returns the last element.
Args:
file_path - see parse_file_path function.
Returns:
the last element of the file path, in this case the filename with extension.
"""
delimiter = "\\"
return file_path.split(delimiter)[-1]
def _parse_parent(file_path : str, leaf: str):
"""
Take the leaf, and use it as a delimiter to extract the parent directory, without the trailing slash.
Args:
file_path - see parse_file_path function.
leaf : str - the leaf of our file path.
Returns:
The first element in our list, our parent directory.
"""
delimiter = "\\{0}".format(leaf)
return file_path.split(delimiter)[0]
def _construct_path_tuple(file_path : str):
"""
Constructs a tuple representing the elements of the file path.
Args:
file_path - see parse_file_path function.
Returns:
A tuple that contains the file elements.
"""
leaf = _parse_leaf(file_path = file_path)
extension = _parse_extension(string_to_parse = leaf)
parent = _parse_parent(file_path = file_path, leaf=leaf)
return (parent, leaf, extension)
Main:
import pathutilities
def main():
try:
path = pathutilities.parse_file_path("C:\\Users\\Sveta\\Employee\\emp_list.txt")
except (TypeError, ValueError) as error:
print(error)
else:
parent, leaf, extension = path
print(parent, leaf, extension)
# Output:
# C:\Users\Sveta\Employee emp_list.txt .txt
if __name__ == '__main__':
main()
os.path
module? \$\endgroup\$pathlib
can result in a cleaner interface. \$\endgroup\$_parse_extension
is invalid Python code. When trying to source the file, Python yields aSyntaxError
in line 155. \$\endgroup\$