Type Annotations: utils.fs

- Resolves Issue #688
- Related to PR #628
This commit is contained in:
BJ Dierkes 2024-06-22 02:40:07 -05:00
parent 527cae8c23
commit b49097de47
2 changed files with 37 additions and 15 deletions

View File

@ -21,6 +21,10 @@ Refactoring:
- [Issue #671](https://github.com/datafolklabs/cement/issues/671)
- [PR #681](https://github.com/datafolklabs/cement/pull/681)
- `[dev]` Remove Python 3.5, 3.6, 3.7 Docker Dev Targets
- `[dev]` Added Python 3.13 Dev Target
- `[utils.fs]` Type Annotations: utils.fs
- [Issue #688](https://github.com/datafolklabs/cement/issues/688)
- [PR #628](https://github.com/datafolklabs/cement/pull/628)
Misc:
@ -35,7 +39,9 @@ Deprecations:
Special Recognitions:
Many thanks to `sigma67` for their contributions in modernizing the packaging system. Cement was started in 2009, and has some lingering technical debt that is now being addressed. Their contribution was a major help in moving off of setuptools and on to PDM and `pyproject.toml`, along with initial implementations of Ruff for a new generation of code compliance. I sincerely appreciate your help!
Many thanks to @sigma67 for their contributions in modernizing the packaging system. Cement was started in 2009, and has some lingering technical debt that is now being addressed. Their contribution was a major help in moving off of setuptools and on to PDM and `pyproject.toml`, along with initial implementations of Ruff for a new generation of code compliance. I sincerely appreciate your help!
Many thanks to @rednar for their contributions toward adding type annotations in [PR 628](https://github.com/datafolklabs/cement/pull/628). This PR was too large to merge directly, but it serving as a guide to finally begin work toward adding type annotations to Cement. This was a massive effort, and is very helpful to have this work available to guide the effort even if it will not be merged directly.
## 3.0.10 - Feb 28, 2024

View File

@ -1,9 +1,16 @@
"""Common File System Utilities."""
# derks@2024-06-22: remove after 3.9 is EOL?
from __future__ import annotations
import os
import tempfile
import shutil
from datetime import datetime
# from typing import Any, Optional, TYPE_CHECKING
from typing import Any, Optional
from typing_extensions import Self
from types import TracebackType
class Tmp(object):
@ -11,7 +18,7 @@ class Tmp(object):
"""
Provides creation and cleanup of a separate temporary directory, and file.
Keyword Arguments:
Keyword Args:
cleanup (bool): Whether or not to delete the temporary directory and
file on exit (when used with the ``with`` operator).
suffix (str): The suffix that the directory and file will end with.
@ -37,7 +44,10 @@ class Tmp(object):
"""
def __init__(self, **kwargs):
dir: str
file: str
def __init__(self, **kwargs: str) -> None:
self.cleanup = kwargs.get('cleanup', True)
suffix = kwargs.get('suffix', '')
prefix = kwargs.get('prefix', 'tmp')
@ -50,7 +60,7 @@ class Tmp(object):
prefix=prefix,
dir=dir)
def remove(self):
def remove(self) -> None:
"""
Remove the temporary directory (and file) if it exists, and
``self.cleanup`` is ``True``.
@ -61,20 +71,24 @@ class Tmp(object):
if os.path.exists(self.file):
os.remove(self.file)
def __enter__(self):
def __enter__(self) -> Self:
return self
def __exit__(self, exc_type, exc_value, exc_traceback):
def __exit__(self,
__exc_type: type[BaseException] | None,
__exc_value: BaseException | None,
__exc_traceback: TracebackType | None) -> None:
self.remove()
def abspath(path, strip_trailing_slash=True):
def abspath(path: str, strip_trailing_slash: bool = True) -> str:
"""
Return an absolute path, while also expanding the ``~`` user directory
shortcut.
Args:
path (str): The original path to expand.
Returns:
str: The fully expanded, absolute path to the given ``path``
@ -92,7 +106,7 @@ def abspath(path, strip_trailing_slash=True):
return os.path.abspath(os.path.expanduser(path))
def join(*args, **kwargs):
def join(*args: str, **kwargs: Any) -> str:
"""
Return a complete, joined path, by first calling ``abspath()`` on the first
item to ensure the final path is complete.
@ -117,12 +131,12 @@ def join(*args, **kwargs):
return os.path.join(first_path, *paths, **kwargs)
def join_exists(*paths):
def join_exists(*paths: str) -> tuple[str, bool]:
"""
Wrapper around ``os.path.join()``, ``os.path.abspath()``, and
``os.path.exists()``.
Arguments:
Args:
paths (list): List of paths to join, and then return ``True`` if that
path exists, or ``False`` if it does not.
@ -134,11 +148,11 @@ def join_exists(*paths):
return (path, os.path.exists(path))
def ensure_dir_exists(path):
def ensure_dir_exists(path: str) -> None:
"""
Ensure the directory ``path`` exists, and if not create it.
Arguments:
Args:
path (str): The filesystem path of a directory.
Raises:
@ -156,12 +170,12 @@ def ensure_dir_exists(path):
os.makedirs(path)
def ensure_parent_dir_exists(path):
def ensure_parent_dir_exists(path: str) -> None:
"""
Ensure the parent directory of ``path`` (file, or directory) exists, and if
not create it.
Arguments:
Args:
path (str): The filesystem path of a file or directory.
Returns: None
@ -171,7 +185,7 @@ def ensure_parent_dir_exists(path):
return ensure_dir_exists(parent_dir)
def backup(path, suffix='.bak', **kwargs):
def backup(path: str, suffix: str = '.bak', **kwargs: Any) -> Optional[str]:
"""
Rename a file or directory safely without overwriting an existing
backup of the same name.
@ -179,6 +193,8 @@ def backup(path, suffix='.bak', **kwargs):
Args:
path (str): The path to the file or directory to make a backup of.
suffix (str): The suffix to rename files with.
Keyword Args:
timestamp(bool): whether to add a timestamp to the backup suffix
timestamp_format(str): Date-Time format in python datetime.datetime
notation. default '%Y-%m-%d-%H:%M:%S'