diff --git a/playground/__init__.py b/playground/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/playground/cwd_test.py b/playground/cwd_test.py new file mode 100644 index 0000000..e69de29 diff --git a/playground/sub_ground/__init__.py b/playground/sub_ground/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/playground/sub_ground/cwd_indirect_test.py b/playground/sub_ground/cwd_indirect_test.py new file mode 100644 index 0000000..e69de29 diff --git a/utils_v2/goog/models/data/auth_tokens.py b/utils_v2/goog/models/data/auth_tokens.py index 5006049..d6c4cd2 100644 --- a/utils_v2/goog/models/data/auth_tokens.py +++ b/utils_v2/goog/models/data/auth_tokens.py @@ -204,6 +204,21 @@ class GoogleAuthTokens(BaseModel): force_refresh = force_refresh ) + def has_scopes(self, scopes: List[str]) -> bool: + + """ + Check if all the specified scopes were granted. + :param scopes: The list of scopes to check. These are the permissions you need. + :return: True if all specified scoped are present, else False. + """ + + # Start by assuming success: + has_scopes = True + + # Now loop through the needed scopes and check: + for scope in scopes: + if scope not in self.scopes + # ***************************************************************************************************************** # ***** **** diff --git a/utils_v2/system/files.py b/utils_v2/system/files.py index 1dd719c..b833640 100644 --- a/utils_v2/system/files.py +++ b/utils_v2/system/files.py @@ -6,11 +6,11 @@ DATE: - Friday, 26th April, 2024 + Friday, 26th Apr., 2024 OBJECTIVE: - To provide an easy way to work with files and directories in an synchronous way. + To provide an easy way to work with files and directories. REFERENCES: @@ -37,9 +37,13 @@ sys.path.append("..") # Other system-level dependencies: import os import sys +import inspect import pathlib import platform +# For working with datatypes: +from typing import List, Literal + # ***************************************************************************************************************** # ***** **** @@ -70,41 +74,89 @@ import platform def get_cwd(): - if platform.system().lower().find("windows") > -1: return os.getcwd() - else: return os.path.split(os.path.realpath(__file__))[0] + """ + Returns the full path of the file from which the current execution flow started. No matter where this function is + called from, the path returned will be of the file where the execution flow started. + :return: The full file path of the script where the execution flow began. + """ + + return os.getcwd() # --------------------------------------------------------------------------------------------------------------------- -def get_parent_directory(path): +def get_file_directory(include_filename: bool = False): - return pathlib.Path(path).parent.absolute() + """ + Returns the absolute path of the file that called this function, regardless of where this file is placed, and + regardless of which other file called this function. + :param include_filename: Whether you want the file's name in the response or not. + :return: The full path of the file from which this function was called. + """ + + # Get the current stack frame (the one just before this function) + caller_frame = inspect.stack()[1] # [1] gets the caller's frame + file_name = caller_frame.filename # Get the filename (relative path) + + # Get the absolute path of the file + full_path = os.path.abspath(file_name) + if not include_filename: full_path = os.path.split(full_path)[0] + + # Done here: + return full_path # --------------------------------------------------------------------------------------------------------------------- -def make_directory(path): +def get_parent_directory(path: str, depth: int = 1) -> str: + + """ + Takes a path and gives you its parent path 'n' no. of directories up. + :param path: The path whose parent is needed. + :param depth: How many dirs you want to come up. + :return: The parent path 'n' levels up. + """ + + for _ in range(depth): path = os.path.split(path)[0] + return path or "/" + + # if depth <= 0: return path + # else: return get_parent_directory(pathlib.Path(path).parent.absolute(), depth - 1) + + +# --------------------------------------------------------------------------------------------------------------------- + + +def make_directory(path: str) -> bool: + + """ + Creates a directory if you have sufficient permissions. + :param path: The path you want to create. + :return: True if successful, else False. + """ if not os.path.exists(path): - try: - os.makedirs(path) + try: os.makedirs(path) except Exception as excp: print("FILE UTILS EXCEPTION (make dir):", excp) return False - if os.path.exists(path): - return True - - else: - return False + if os.path.exists(path):return True + else: return False # --------------------------------------------------------------------------------------------------------------------- -def get_directory_for_file_path(file_path): +def get_directory_for_file_path(file_path: str) -> str: + + """ + Given a file's path, this function gives you that file's parent directory's path. + :param file_path: The file's full path whose parent is needed. + :return: The file's parent directory's path if the file exists, else None. + """ if os.path.exists(file_path): path_components = os.path.split(file_path) @@ -116,7 +168,22 @@ def get_directory_for_file_path(file_path): # --------------------------------------------------------------------------------------------------------------------- -def write_file(file_path, file_data, mode = "w"): +def write_file( + file_path: str, + file_data: str | bytes, + mode: Literal["w", "wb", "a", "ab"] = "w", + raise_exception: bool = False +) -> bool: + + """ + Writes/overwrites a file with the data provided. + :param file_path: The file to which you want to add data. + :param file_data: The data you want to add to the end of the file. + :param mode: The mode with which data will be written. + :param raise_exception: If set to True, exceptions will be propagated; if set to False, exceptions will be + suppressed. + :return: True if successful, else False. + """ try: @@ -133,31 +200,80 @@ def write_file(file_path, file_data, mode = "w"): # --------------------------------------------------------------------------------------------------------------------- -def append_file(file_path, file_data): +def append_file( + file_path: str, + file_data: str, + mode: Literal["a", "ab"] = "a", + raise_exception: bool = False +) -> bool: - return write_file(file_path, file_data, mode = "a") + """ + Adds data to the end of a file. + :param file_path: The file to which you want to add data. + :param file_data: The data you want to add to the end of the file. + :param mode: The mode with which data will be written. + :param raise_exception: If set to True, exceptions will be propagated; if set to False, exceptions will be + suppressed. + :return: True if successful, else False. + """ + + try: return write_file(file_path, file_data, mode = mode) + except Exception as excp: + if raise_exception: raise + return False # --------------------------------------------------------------------------------------------------------------------- -def read_file(file_path, mode = "r", encoding = "utf8"): +def read_file( + file_path: str, + mode: Literal["r", "rb"] = "r", + encoding = "utf8", + raise_exception: bool = False +) -> str | bytes | None: + + """ + Reads the contents of one file. + :param file_path: The path of the file whose contents must be read. + :param mode: The mode of reading the file. + :param encoding: The encoding of the file. + :param raise_exception: If set to True, exceptions will be propagated; if set to False, exceptions will be + suppressed. + :return: The contents of the file or None. + """ try: + file = open(file_path, mode, encoding = encoding) file_contents = file.read() file.close() return file_contents except Exception as excp: - print("FILE UTILS EXCEPTION (read file):", excp) + if raise_exception: raise return None # --------------------------------------------------------------------------------------------------------------------- -def rename_file(current, new): +def rename_file( + current: str, + new: str, + raise_exception: bool = False +) -> bool: + + """ + Renames one file. USE CAREFULLY. + WARNING: rename_directory("old_file", "/path/to/new_location/new_file") will move 'old_file' to + '/path/to/new_location/' and rename it to 'new_file'. + :param current: The current name/path. + :param new: The new name/path. + :param raise_exception: If set to True, exceptions will be propagated; if set to False, exceptions will be + suppressed. + :return: True if renamed, else False. + """ try: if os.path.isfile(current): @@ -166,14 +282,29 @@ def rename_file(current, new): return False except Exception as excp: - print("FILE UTILS EXCEPTION (rename file):", excp) + if raise_exception: raise return False # --------------------------------------------------------------------------------------------------------------------- -def rename_directory(current, new): +def rename_directory( + current: str, + new: str, + raise_exception: bool = False +) -> bool: + + """ + Renames the directory. USE CAREFULLY. + WARNING: rename_directory("old_directory", "/path/to/new_location/new_directory") will move 'old_directory' to + '/path/to/new_location/' and rename it to 'new_directory'. + :param current: The current name/path. + :param new: The new name/path. + :param raise_exception: If set to True, exceptions will be propagated; if set to False, exceptions will be + suppressed. + :return: True if renamed, else False. + """ try: if os.path.isdir(current): @@ -182,14 +313,25 @@ def rename_directory(current, new): return False except Exception as excp: - print("FILE UTILS EXCEPTION (rename dir):", excp) + if raise_exception: raise return False # --------------------------------------------------------------------------------------------------------------------- -def delete_file(file_path): +def delete_file( + file_path: str, + raise_exception: bool = False +) -> bool: + + """ + Deletes one file. USE CAREFULLY. + :param file_path: The path of the file that you want to delete. + :param raise_exception: If set to True, exceptions will be propagated; if set to False, exceptions will be + suppressed. + :return: True if deleted, else False. + """ try: if os.path.isfile(file_path): @@ -198,14 +340,25 @@ def delete_file(file_path): return False except Exception as excp: - print("FILE UTILS EXCEPTION (delete file):", excp) + if raise_exception: raise return False # --------------------------------------------------------------------------------------------------------------------- -def delete_directory(directory_path): +def delete_directory( + directory_path: str, + raise_exception: bool = False +) -> bool: + + """ + Deletes a whole directory with all its contents. USE CAREFULLY. + :param directory_path: The path that you want to delete. + :param raise_exception: If set to True, exceptions will be propagated; if set to False, exceptions will be + suppressed. + :return: True if deleted, else False. + """ try: if os.path.exists(directory_path): @@ -219,14 +372,27 @@ def delete_directory(directory_path): return False except Exception as excp: - print("FILE UTILS EXCEPTION (delete dir):", excp) + if raise_exception: raise return False # --------------------------------------------------------------------------------------------------------------------- -def move_file(file_path, new_dir): +def move_file( + file_path: str, + new_dir: str, + raise_exception: bool = False +) -> bool: + + """ + To move a file from one place to another. + :param file_path: The path of the current file. + :param new_dir: The destination directory. + :param raise_exception: If set to True, exceptions will be propagated; if set to False, exceptions will be + suppressed. + :return: True if moved, else False. + """ try: destination = os.path.join(new_dir, os.path.split(file_path)[-1]) @@ -234,16 +400,30 @@ def move_file(file_path, new_dir): return True except Exception as excp: - print("FILE UTILS EXCEPTION (move file):", excp) + if raise_exception: raise return False # --------------------------------------------------------------------------------------------------------------------- -def copy_file(file_path, new_dir): +def copy_file( + file_path: str, + new_dir: str, + raise_exception: bool = False +) -> bool: + + """ + To copy a file from one place to another. + :param file_path: The path of the current file. + :param new_dir: The destination directory. + :param raise_exception: If set to True, exceptions will be propagated; if set to False, exceptions will be + suppressed. + :return: True if copied, else False. + """ try: + destination = os.path.join(new_dir, os.path.split(file_path)[-1]) handle_src = open(file_path, mode = "r") handle_dst = open(destination, mode = "w") @@ -255,14 +435,27 @@ def copy_file(file_path, new_dir): return True except Exception as excp: - print("FILE UTILS EXCEPTION (copy file):", excp) + if raise_exception: raise return False # --------------------------------------------------------------------------------------------------------------------- -def list_files(directory_path, full_path = False): +def list_files( + directory_path: str, + full_path = False, + raise_exception: bool = False +) -> List[str]: + + """ + Lists all the files in a path. + :param directory_path: The path inside which you want to list all the files. + :param full_path: Whether, or not, you would like to receive the list of full paths, or just the names of the files. + :param raise_exception: If set to True, exceptions will be propagated; if set to False, exceptions will be + suppressed. + :return: The list of files inside the given path. + """ try: path = pathlib.Path(directory_path) @@ -271,20 +464,31 @@ def list_files(directory_path, full_path = False): return files except Exception as excp: - print("FILE UTILS EXCEPTION (list files):", excp) - return False + if raise_exception: raise + return [] # --------------------------------------------------------------------------------------------------------------------- def list_dirs( - directory_path, + directory_path: str, full_path = False, - raise_exception = False -): + raise_exception: bool = False +) -> List[str]: + + """ + Lists all the subdirectories in a path. + :param directory_path: The path inside which you want to list all the directories. + :param full_path: Whether, or not, you would like to receive the list of full paths, or just the names of the + directories. + :param raise_exception: If set to True, exceptions will be propagated; if set to False, exceptions will be + suppressed. + :return: The list of subdirectories inside the given path. + """ try: + path = pathlib.Path(directory_path) files = [entry.name for entry in path.iterdir() if entry.is_dir()] if full_path: files = [os.path.join(directory_path, file) for file in files] @@ -292,7 +496,6 @@ def list_dirs( except Exception as excp: if raise_exception: raise - print("FILE UTILS EXCEPTION (list dirs):", excp) return []