Skip to content

fs

File

File(path: str | PathLike, encoding: str = 'utf-8', *, abs: bool = False)

Bases: PathLike

Initialize a File object.

Parameters:

Name Type Description Default
path PathLike

File path.

required
encoding str

The file's encoding.

'utf-8'
abs bool

Whether to use the absolute path.

False
Source code in stdl/fs.py
def __init__(
    self,
    path: str | PathLike,
    encoding: str = "utf-8",
    *,
    abs: bool = False,
) -> None:
    """Initialize a File object.

    Args:
        path (os.PathLike): File path.
        encoding (str, optional): The file's encoding.
        abs (bool): Whether to use the absolute path.
    """
    self.encoding = encoding
    self.path: str = os.fspath(path)
    if abs:
        self.path = os.path.abspath(self.path)  # type:ignore

dirname property

dirname: str

The file's directory name.

created property

created: float

The time when the file was created as a UNIX timestamp.

modified property

modified: float

The time when the file was last modified as a UNIX timestamp.

accessed property

accessed: float

The time when the file was last accessed as a UNIX timestamp.

basename property

basename: str

The file's base name (without the directory).

ext property

ext: str

The file's extension (without the dot). Returns empty string if the file has no extension.

abspath property

abspath: str

The file's absolute path.

stem property

stem

The file's stem (base name without extension).

size

size(readable: bool = False) -> int | str

The file's size in bytes or a human-readable format if readable is set to True.

Source code in stdl/fs.py
def size(self, readable: bool = False) -> int | str:
    """The file's size in bytes or a human-readable format if readable is set to True."""
    size = os.path.getsize(self.path)
    if readable:
        return bytes_readable(size)
    return size

to_path

to_path() -> Path

Convert to pathlib.Path

Source code in stdl/fs.py
def to_path(self) -> Path:
    """Convert to  pathlib.Path"""
    return Path(self.path)

create

create()

Create an empty file if it doesn't exist.

Source code in stdl/fs.py
def create(self):
    """Create an empty file if it doesn't exist."""
    if self.exists:
        return self
    open(self.path, "a", encoding=self.encoding).close()
    return self

remove

remove()

Remove the file.

Source code in stdl/fs.py
def remove(self):
    """Remove the file."""
    if not self.exists:
        return self
    os.remove(self.path)
    return self

clear

clear()

Clear the contents of a file if it exists

Source code in stdl/fs.py
def clear(self):
    """Clear the contents of a file if it exists"""
    if not self.exists:
        return
    open(self.path, "w", encoding=self.encoding).close()
    return self

read

read() -> str

Read the contents of a file.

Source code in stdl/fs.py
def read(self) -> str:
    """Read the contents of a file."""
    with open(self.path, "r", encoding=self.encoding) as f:
        return f.read()

write

write(data, *, newline: bool = True) -> None

Write data to a file, overwriting any existing data.

Parameters:

Name Type Description Default
data Any

The data to write.

required
newline bool

Whether to add a newline at the end of the data.

True
Source code in stdl/fs.py
def write(self, data, *, newline: bool = True) -> None:
    """
    Write data to a file, overwriting any existing data.

    Args:
        data (Any): The data to write.
        newline (bool, optional): Whether to add a newline at the end of the data.
    """
    self._write(data, "w", newline=newline)

append

append(data, *, newline: bool = True)

Append data to a file.

Parameters:

Name Type Description Default
data Any

The data to append.

required
newline bool

Whether to add a newline at the end of the data.

True
Source code in stdl/fs.py
def append(self, data, *, newline: bool = True):
    """
    Append data to a file.

    Args:
        data (Any): The data to append.
        newline (bool, optional): Whether to add a newline at the end of the data.
    """
    self._write(data, "a", newline=newline)

write_iter

write_iter(data: Iterable, sep='\n')

Write data from an iterable to a file, overwriting any existing data.

Parameters:

Name Type Description Default
data Iterable

The data to write.

required
sep str

The separator to use between items.

'\n'
Source code in stdl/fs.py
def write_iter(self, data: Iterable, sep="\n"):
    """Write data from an iterable to a file, overwriting any existing data.

    Args:
        data (Iterable): The data to write.
        sep (str, optional): The separator to use between items.
    """
    self._write_iter(data, "w", sep=sep)

append_iter

append_iter(data: Iterable, sep='\n')

Append data from an iterable to a file.

Parameters:

Name Type Description Default
data Iterable

The data to append.

required
sep str

The separator to use between items.

'\n'
Source code in stdl/fs.py
def append_iter(self, data: Iterable, sep="\n"):
    """Append data from an iterable to a file.

    Args:
        data (Iterable): The data to append.
        sep (str, optional): The separator to use between items.
    """
    self._write_iter(data, "a", sep=sep)

readlines

readlines() -> list[str]

Equivalent to TextIOWrapper.readlines()

Source code in stdl/fs.py
def readlines(self) -> list[str]:
    """Equivalent to TextIOWrapper.readlines()"""
    with open(self.path, "r", encoding=self.encoding) as f:
        return f.readlines()

splitlines

splitlines() -> list[str]

Equivalent to File.read().splitlines()

Source code in stdl/fs.py
def splitlines(self) -> list[str]:
    """Equivalent to File.read().splitlines()"""
    return self.read().splitlines()

move_to

move_to(directory: str, *, overwrite=True)

Move the file to a new directory.

Parameters:

Name Type Description Default
directory str

The destination directory.

required
overwrite bool

Whether to overwrite the file if it already exists in the destination directory. Defaults to True.

True
Source code in stdl/fs.py
def move_to(self, directory: str, *, overwrite=True):
    """
    Move the file to a new directory.

    Args:
        directory (str): The destination directory.
        overwrite (bool, optional): Whether to overwrite the file if it already exists in the destination directory. Defaults to True.
    """
    move_path = f"{directory}{SEP}{self.basename}"
    if os.path.exists(move_path) and not overwrite:
        raise FileExistsError(move_path)
    os.rename(self.path, move_path)
    self.path = move_path
    return self

copy_to

copy_to(directory: str, *, mkdir=False, overwrite=True)

Copy the file to a new directory.

Parameters:

Name Type Description Default
directory str

The destination directory.

required
overwrite bool

Whether to overwrite the file if it already exists in the destination directory. Defaults to True.

True
Source code in stdl/fs.py
def copy_to(self, directory: str, *, mkdir=False, overwrite=True):
    """
    Copy the file to a new directory.

    Args:
        directory (str): The destination directory.
        overwrite (bool, optional): Whether to overwrite the file if it already exists in the destination directory. Defaults to True.
    """
    if not os.path.isdir(directory):
        if mkdir:
            os.mkdir(directory)
        else:
            raise FileNotFoundError(f"No such directory: '{directory}'")
    copy_path = f"{directory}{SEP}{self.basename}"
    if os.path.exists(copy_path) and not overwrite:
        raise FileExistsError(copy_path)
    self.path = shutil.copy2(self.path, directory)
    return self

with_dir

with_dir(directory: str)

Change the directory of the file object. This will not move the actual file to that directory. Use File.move_to for that.

Source code in stdl/fs.py
def with_dir(self, directory: str):
    """
    Change the directory of the file object. This will not move the actual file to that directory.
    Use File.move_to for that.
    """
    basename = self.basename
    self.path = f"{directory}{SEP}{basename}"
    return self

with_ext

with_ext(ext: str)

Change the extension of the file and return the new File object

Parameters:

Name Type Description Default
ext str

The new extension of the file.

required

Returns:

Name Type Description
File

The File object with the new extension.

Source code in stdl/fs.py
def with_ext(self, ext: str):
    """Change the extension of the file and return the new File object

    Args:
        ext (str): The new extension of the file.

    Returns:
        File: The File object with the new extension.
    """
    if not ext.startswith("."):
        ext = f".{ext}"
    self.path = f"{self.dirname}{SEP}{self.stem}{ext}"
    return self

with_suffix

with_suffix(suffix: str)

Add a suffix to the file's name and return the new File object.

Source code in stdl/fs.py
def with_suffix(self, suffix: str):
    """Add a suffix to the file's name and return the new File object."""
    ext = self.ext
    if ext:
        ext = f".{ext}"
    filename = f"{self.stem}{suffix}{ext}"
    self.path = f"{self.dirname}{SEP}{filename}"
    return self

with_prefix

with_prefix(prefix: str)

Add a prefix to the file's name and return the new File object.

Source code in stdl/fs.py
def with_prefix(self, prefix: str):
    """Add a prefix to the file's name and return the new File object."""
    ext = self.ext
    if ext:
        ext = f".{ext}"
    filename = f"{prefix}{self.stem}{ext}"
    self.path = f"{self.dirname}{SEP}{filename}"
    return self

rename

rename(name: str)

Rename the file and return the new File object.

Source code in stdl/fs.py
def rename(self, name: str):
    """Rename the file and return the new File object."""
    new_path = f"{self.dirname}{SEP}{name}"
    os.rename(self.path, new_path)
    self.path = new_path
    return self

chmod

chmod(mode: int)

Change the file's permissions.

Source code in stdl/fs.py
def chmod(self, mode: int):
    """Change the file's permissions."""
    os.chmod(self.path, mode)
    return self

chown

chown(user: str, group: str)

Change the file's owner and group.

Source code in stdl/fs.py
def chown(self, user: str, group: str):
    """Change the file's owner and group."""
    shutil.chown(self.path, user, group)
    return self
link(target: str)

Create a hard link to the file.

Source code in stdl/fs.py
def link(self, target: str):
    """Create a hard link to the file."""
    os.link(self.path, target)
    return self
symlink(target: str)

Create a symbolic link to the file.

Source code in stdl/fs.py
def symlink(self, target: str):
    """Create a symbolic link to the file."""
    os.symlink(self.path, target)
    return self

should_exist

should_exist()

Raise FileNotFoundError if the file does not exist.

Source code in stdl/fs.py
def should_exist(self):
    """Raise FileNotFoundError if the file does not exist."""
    if not self.exists:
        raise FileNotFoundError(f"No such file: '{self.path}'")
    return self

should_not_exist

should_not_exist()

Raise FileExistsError if the file exists.

Source code in stdl/fs.py
def should_not_exist(self):
    """Raise FileExistsError if the file exists."""
    if self.exists:
        raise FileExistsError(f"File already exists: '{self.path}'")
    return self

rand classmethod

rand(prefix: str = 'file', ext: str = '')

Create a new random file with a specified prefix and extension.

Parameters:

Name Type Description Default
prefix str

The prefix for the file name.

'file'
ext str

The extension for the file name.

''

Returns:

Name Type Description
File

A new File object with a random name.

Source code in stdl/fs.py
@classmethod
def rand(cls, prefix: str = "file", ext: str = ""):
    """
    Create a new random file with a specified prefix and extension.

    Args:
        prefix (str, optional): The prefix for the file name.
        ext (str, optional): The extension for the file name.

    Returns:
        File: A new File object with a random name.
    """
    return File(rand_filename(prefix, ext))

get_xattr

get_xattr(name: str, group: str = 'user') -> str

Retrieve the value of an extended attribute for the file.

Parameters:

Name Type Description Default
name str

The name of the extended attribute.

required
group str

The group of the extended attribute. Defaults to "user".

'user'

Returns:

Name Type Description
str str

The value of the extended attribute.

Source code in stdl/fs.py
def get_xattr(self, name: str, group: str = "user") -> str:
    """Retrieve the value of an extended attribute for the file.

    Args:
        name (str): The name of the extended attribute.
        group (str, optional): The group of the extended attribute. Defaults to "user".

    Returns:
        str: The value of the extended attribute.
    """
    return os.getxattr(self.path, f"{group}.{name}").decode()

set_xattr

set_xattr(value: str | bytes, name: str, group: str = 'user')

Set an extended attribute for the file.

Parameters:

Name Type Description Default
value str | bytes

The value of the extended attribute.

required
name str

The name of the extended attribute.

required
group str

The group of the extended attribute. Defaults to "user".

'user'
Source code in stdl/fs.py
def set_xattr(self, value: str | bytes, name: str, group: str = "user"):
    """Set an extended attribute for the file.

    Args:
        value (str | bytes): The value of the extended attribute.
        name (str): The name of the extended attribute.
        group (str, optional): The group of the extended attribute. Defaults to "user".
    """
    if isinstance(value, str):
        value = value.encode()
    os.setxattr(self.path, f"{group}.{name}", value)
    return self

remove_xattr

remove_xattr(name: str, group: str = 'user') -> None

Remove an extended attribute from the file.

Parameters:

Name Type Description Default
name str

The name of the extended attribute.

required
group str

The group of the extended attribute. Defaults to "user".

'user'
Source code in stdl/fs.py
def remove_xattr(self, name: str, group: str = "user") -> None:
    """Remove an extended attribute from the file.

    Args:
        name (str): The name of the extended attribute.
        group (str, optional): The group of the extended attribute. Defaults to "user".
    """
    os.removexattr(self.path, f"{group}.{name}")

CompletedCommand

CompletedCommand(args, returncode: int, time_taken: float, stdout: Any | None = None, stderr: Any | None = None)

Bases: CompletedProcess

Source code in stdl/fs.py
def __init__(
    self,
    args,
    returncode: int,
    time_taken: float,
    stdout: T.Any | None = None,
    stderr: T.Any | None = None,
) -> None:
    super().__init__(args, returncode, stdout, stderr)
    self.time_taken = time_taken

stdout_lines property

stdout_lines: list[str]

Returns the stdout as a list of lines.

stderr_lines property

stderr_lines: list[str]

Returns the stderr as a list of lines.

pickle_load

pickle_load(filepath: str | PathLike)

Loads a pickled file.

Source code in stdl/fs.py
def pickle_load(filepath: str | PathLike):
    """Loads a pickled file."""
    with open(filepath, "rb") as f:
        return pickle.load(f)

pickle_dump

pickle_dump(data: Any, filepath: str | PathLike) -> None

Dumps an object to the specified filepath.

Source code in stdl/fs.py
def pickle_dump(data: T.Any, filepath: str | PathLike) -> None:
    """Dumps an object to the specified filepath."""

    with open(filepath, "wb") as f:
        pickle.dump(data, f)

json_load

json_load(path: str | PathLike, encoding='utf-8') -> dict | list[dict]

Load a JSON file from the given path.

Parameters:

Name Type Description Default
path str | PathLike

The path of the JSON file to load.

required
encoding str

The encoding of the file. Defaults to "utf-8".

'utf-8'

Returns:

Type Description
dict | list[dict]

dict | list[dict]: The JSON data loaded from the file.

Source code in stdl/fs.py
def json_load(path: str | PathLike, encoding="utf-8") -> dict | list[dict]:
    """Load a JSON file from the given path.

    Args:
        path (str | PathLike): The path of the JSON file to load.
        encoding (str, optional): The encoding of the file. Defaults to "utf-8".

    Returns:
        dict | list[dict]: The JSON data loaded from the file.
    """
    with open(os.fspath(path), "r", encoding=encoding) as f:
        return json.load(f)

json_append

json_append(data: dict | list[dict], filepath: str | PathLike, encoding: str = 'utf-8', default=str, indent: int = 4)

Append data to a JSON file. Args: data (dict | list[dict]): The data to be appended filepath (str | PathLike): The path of the JSON file encoding (str, optional): The encoding of the file. Defaults to "utf-8". default : A function that gets called for objects that can’t otherwise be serialized. See json.dump() documentation for more information. indent (int, optional): The number of spaces to use for indentation. Defaults to 4.

Source code in stdl/fs.py
def json_append(
    data: dict | list[dict],
    filepath: str | PathLike,
    encoding: str = "utf-8",
    default=str,
    indent: int = 4,
):
    """Append data to a JSON file.
    Args:
        data (dict | list[dict]): The data to be appended
        filepath (str | PathLike): The path of the JSON file
        encoding (str, optional): The encoding of the file. Defaults to "utf-8".
        default : A function that gets called for objects that can’t otherwise be serialized.
                  See json.dump() documentation for more information.
        indent (int, optional): The number of spaces to use for indentation. Defaults to 4.
    """

    file = File(filepath)
    path = os.fspath(filepath)
    if not file.exists or file.size() == 0:
        json_dump([data], filepath, encoding=encoding, indent=indent, default=default)
        return
    with open(path, "a+", encoding=encoding) as f:
        f.seek(0)
        first_char = f.read(1)
        if first_char == "[":
            f.seek(0, os.SEEK_END)
            f.seek(f.tell() - 2, os.SEEK_SET)
            f.truncate()
            f.write(",\n")
            json.dump(data, f, indent=indent, default=default)
            f.write("]\n")
        elif first_char == "{":
            file_data = first_char + f.read()
            f.seek(0)
            f.truncate()
            f.seek(0)
            f.write("[\n")
            f.write(file_data)
            f.write(",\n")
            json.dump(data, f, indent=indent, default=default)
            f.write("]\n")
        else:
            raise ValueError(f"Cannot parse '{path}' as JSON.")

json_dump

json_dump(data: Any, path: str | PathLike, encoding: str = 'utf-8', default=str, indent=4) -> None

Dumps data to a JSON file.

Parameters:

Name Type Description Default
data Any

data to be dumped

required
path str | PathLike

path to the output file

required
encoding str

encoding of the output file. Default: 'utf-8'

'utf-8'
default

A function that gets called on objects that cannot be serialized. Default: str

str
indent int

number of spaces to use when indenting the output json. Default: 4

4
Source code in stdl/fs.py
def json_dump(
    data: T.Any, path: str | PathLike, encoding: str = "utf-8", default=str, indent=4
) -> None:
    """
    Dumps data to a JSON file.

    Args:
        data: data to be dumped
        path (str | PathLike): path to the output file
        encoding (str): encoding of the output file. Default: 'utf-8'
        default: A function that gets called on objects that cannot be serialized. Default: str
        indent (int): number of spaces to use when indenting the output json. Default: 4
    """
    with open(os.fspath(path), "w", encoding=encoding) as f:
        json.dump(data, f, indent=indent, default=default)

yaml_load

yaml_load(path: str | PathLike, encoding: str = 'utf-8') -> dict | list[dict]

Load a YAML file from the given path.

Parameters:

Name Type Description Default
path str | PathLike

The path of the YAML file to load.

required
encoding str

The encoding of the file. Defaults to "utf-8".

'utf-8'

Returns:

Type Description
dict | list[dict]

dict | list[dict]: The YAML data loaded from the file.

Source code in stdl/fs.py
def yaml_load(path: str | PathLike, encoding: str = "utf-8") -> dict | list[dict]:
    """Load a YAML file from the given path.

    Args:
        path (str | PathLike): The path of the YAML file to load.
        encoding (str, optional): The encoding of the file. Defaults to "utf-8".

    Returns:
        dict | list[dict]: The YAML data loaded from the file.
    """
    with open(path, "r", encoding=encoding) as f:
        return yaml.safe_load(f)

yaml_dump

yaml_dump(data, path: str | PathLike, encoding: str = 'utf-8') -> None

Dumps data to a YAML file Args: data: data to be dumped path (Pathlike): path to the output file encoding (str): encoding of the output file. Default: 'utf-8'

Source code in stdl/fs.py
def yaml_dump(data, path: str | PathLike, encoding: str = "utf-8") -> None:
    """
    Dumps data to a YAML file
    Args:
        data: data to be dumped
        path (Pathlike): path to the output file
        encoding (str): encoding of the output file. Default: 'utf-8'
    """
    with open(path, "w", encoding=encoding) as f:
        yaml.safe_dump(data, f)

get_dir_size

get_dir_size(directory: str | Path, *, readable: bool = False) -> str | int

Moves files to a specified directory

Parameters:

Name Type Description Default
directory (str, Path)

target directory

required
readable bool

Return the size in human-readable format

False
Source code in stdl/fs.py
def get_dir_size(directory: str | Path, *, readable: bool = False) -> str | int:
    """Moves files to a specified directory

    Args:
        directory (str, Path): target directory
        readable (bool, optional): Return the size in human-readable format
    """
    total_size = 0
    for dirpath, _, filenames in os.walk(directory):
        for f in filenames:
            fp = os.path.join(dirpath, f)
            # Skip if it's symbolic link.
            if not os.path.islink(fp):
                total_size += os.path.getsize(fp)
    if readable:
        return bytes_readable(total_size)
    return total_size

move_files

move_files(files: list[str | PathLike], directory: str | PathLike, *, mkdir: bool = False) -> None

Moves files to a specified directory

Parameters:

Name Type Description Default
files list[str | PathLike]

List of files to be moved

required
directory str | PathLike

target directory

required
mkdir bool

whether to create the directory if it doesn't exist. Default: False

False

Raises:

Type Description
FileNotFoundError

if the target directory does not exist and mkdir is False.

Source code in stdl/fs.py
def move_files(
    files: list[str | PathLike], directory: str | PathLike, *, mkdir: bool = False
) -> None:
    """Moves files to a specified directory

    Args:
        files (list[str | PathLike]): List of files to be moved
        directory (str | PathLike): target directory
        mkdir (bool): whether to create the directory if it doesn't exist. Default: False

    Raises:
        FileNotFoundError : if the target directory does not exist and mkdir is False.
    """
    directory = os.fspath(directory)
    if exists(directory):
        if mkdir:
            os.makedirs(directory, exist_ok=True)
        else:
            raise FileNotFoundError(f"{directory} is not a directory")
    for file in files:
        os.rename(os.fspath(file), f"{directory}{SEP}{os.path.basename(file)}")

rand_filename

rand_filename(prefix: str = 'file', ext: str = '', include_datetime: bool = False) -> str

Generates a random filename with the given prefix and extension. Optionally includes current date and time in the filename.

Parameters:

Name Type Description Default
prefix str

Filename prefix.

'file'
ext str

Filename extension.

''
include_datetime bool

Whether to include date and time.

False

Returns:

Name Type Description
str str

The generated random filename.

Source code in stdl/fs.py
def rand_filename(prefix: str = "file", ext: str = "", include_datetime: bool = False) -> str:
    """
    Generates a random filename with the given prefix and extension.
    Optionally includes current date and time in the filename.

    Args:
        prefix (str, optional): Filename prefix.
        ext (str, optional): Filename extension.
        include_datetime (bool, optional): Whether to include date and time.

    Returns:
        str: The generated random filename.
    """
    if ext and not ext.startswith("."):
        ext = f".{ext}"
    num = str(random.randrange(1000000000, 9999999999)).zfill(10)
    if include_datetime:
        creation_time = datetime.now().strftime("%Y-%m-%d.%H-%M-%S-%f")[:-3]
        filename = f"{prefix}.{num}.{creation_time}{ext}"
    else:
        filename = f"{prefix}.{num}{ext}"
    return filename

bytes_readable

bytes_readable(size_bytes: int) -> str

Convert bytes to a human-readable string. Args: size_bytes (int): The number of bytes Returns: str : The number of bytes in a human-readable format

Source code in stdl/fs.py
def bytes_readable(size_bytes: int) -> str:
    """Convert bytes to a human-readable string.
    Args:
        size_bytes (int): The number of bytes
    Returns:
        str : The number of bytes in a human-readable format
    """
    if size_bytes < 0:
        raise ValueError(size_bytes)
    if size_bytes == 0:
        return "0B"
    i = int(math.floor(math.log(size_bytes, 1024)))
    p = math.pow(1024, i)
    s = round(size_bytes / p, 2)
    size_name = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB")
    return f"{s} {size_name[i]}"

readable_size_to_bytes

readable_size_to_bytes(size: str, kb_size: Literal[1000, 1024] = 1024) -> int

Convert human-readable string to bytes. Args: size (str): The number of bytes in human-readable format kb_size (int, optional): The byte size of a kilobyte (1000 or 1024). Defaults to 1024. Returns: int: The number of bytes

Source code in stdl/fs.py
def readable_size_to_bytes(size: str, kb_size: T.Literal[1000, 1024] = 1024) -> int:
    """Convert human-readable string to bytes.
    Args:
        size (str): The number of bytes in human-readable format
        kb_size (int, optional): The byte size of a kilobyte (1000 or 1024). Defaults to 1024.
    Returns:
        int: The number of bytes
    """
    if kb_size not in (1000, 1024):
        raise ValueError(f"Invalid kb_size: {kb_size}. Must be 1000 or 1024.")

    size = size.upper().replace(" ", "")
    if size.isdigit():
        return int(size)

    match = re.match(r"^(\d+(\.\d+)?)(B|KB|MB|GB|TB)$", size)
    if not match:
        raise ValueError(f"Invalid size format: {size}")

    number, unit = float(match.group(1)), match.group(3)

    units = {"B": 1, "KB": kb_size, "MB": kb_size**2, "GB": kb_size**3, "TB": kb_size**4}

    if unit not in units:
        raise ValueError(f"Invalid unit: {unit}")

    return int(number * units[unit])

windows_has_drive

windows_has_drive(letter: str) -> bool

Check if a drive letter exists on Windows. Will always return False if the platform is not Windows. Args: letter (str): The letter of the drive. Returns: bool: Whether the drive exists.

Source code in stdl/fs.py
def windows_has_drive(letter: str) -> bool:
    """
    Check if a drive letter exists on Windows.
    Will always return False if the platform is not Windows.
    Args:
        letter (str): The letter of the drive.
    Returns:
        bool: Whether the drive exists.
    """
    if sys.platform != "win32":
        return False
    return os.path.exists(f"{letter}:{SEP}")

is_wsl

is_wsl() -> bool

Check if the current platform is Windows Subsystem for Linux (WSL).

Source code in stdl/fs.py
def is_wsl() -> bool:
    """
    Check if the current platform is Windows Subsystem for Linux (WSL).
    """
    return sys.platform == "linux" and "microsoft" in platform.platform()

mkdir

mkdir(path: str | Path, mode: int = 511, exist_ok: bool = True) -> None

Creates a directory.

Parameters:

Name Type Description Default
path str | Path

The path of the directory to create.

required
exist_ok bool

Whether to raise an exception if the directory already exists. Defaults to True.

True
Source code in stdl/fs.py
def mkdir(path: str | Path, mode: int = 511, exist_ok: bool = True) -> None:
    """
    Creates a directory.

    Args:
        path (str | Path): The path of the directory to create.
        exist_ok (bool, optional): Whether to raise an exception if the directory already exists. Defaults to True.
    """
    os.makedirs(os.fspath(path), exist_ok=exist_ok, mode=mode)

mkdirs

mkdirs(dest: str | Path, names: list[str]) -> None

Creates directories inside a destination directory.

Parameters:

Name Type Description Default
dest str | Path

The destination directory.

required
names list[str]

A list of directory names to be created in the destination directory.

required
Source code in stdl/fs.py
def mkdirs(dest: str | Path, names: list[str]) -> None:
    """
    Creates directories inside a destination directory.

    Args:
        dest (str | Path): The destination directory.
        names (list[str]): A list of directory names to be created in the destination directory.
    """
    if not exists(dest):
        mkdir(dest)
    for i in names:
        if not exists(i):
            path = f"{dest}{SEP}{i}"
            mkdir(path)

yield_files_in

yield_files_in(directory: str | Path, ext: str | tuple | None = None, *, recursive: bool = True, abs: bool = True) -> Generator[str, None, None]

Yields the paths of files in a directory.

This function searches for files in a directory and yields their paths. If the ext parameter is provided, only files with that extension are yielded. The ext parameter is case-insensitive. If the recursive parameter is set to True, the function will search for files in subdirectories recursively.

Parameters:

Name Type Description Default
directory str | Path

The directory to search.

required
ext str | tuple[str, ...]

If provided, only yield files with provided extensions.

None
recursive bool

Whether to search recursively.

True
abs bool

Whether to convert paths to absolute paths.

True

Yields:

Type Description
str

Generator[str, None, None]: The absolute paths of the files in the directory, matching the provided extension.

Source code in stdl/fs.py
def yield_files_in(
    directory: str | Path,
    ext: str | tuple | None = None,
    *,
    recursive: bool = True,
    abs: bool = True,
) -> T.Generator[str, None, None]:
    """
    Yields the paths of files in a directory.

    This function searches for files in a directory and yields their paths.
    If the `ext` parameter is provided, only files with that extension are yielded. The `ext` parameter is case-insensitive.
    If the `recursive` parameter is set to `True`, the function will search for files in subdirectories recursively.

    Args:
        directory (str | Path): The directory to search.
        ext (str | tuple[str, ...], optional): If provided, only yield files with provided extensions.
        recursive (bool, optional): Whether to search recursively.
        abs (bool, optional): Whether to convert paths to absolute paths.

    Yields:
        Generator[str, None, None]: The absolute paths of the files in the directory, matching the provided extension.
    """
    if not recursive:
        for entry in os.scandir(directory):
            if not entry.is_file():
                continue
            path = entry.path
            if abs:
                path = os.path.abspath(entry.path)
            if ext is None:
                yield path
            else:
                if path.lower().endswith(ext):
                    yield path
        return

    queue = Queue()
    queue.put(directory)

    if ext is None:
        while not queue.empty():
            next_dir = queue.get()
            for entry in os.scandir(next_dir):
                if entry.is_dir():
                    queue.put(entry.path)
                elif entry.is_file():
                    yield os.path.abspath(entry.path) if abs else entry.path
        return

    while not queue.empty():
        next_dir = queue.get()
        for entry in os.scandir(next_dir):
            if entry.is_dir():
                queue.put(entry.path)
            elif entry.is_file():
                if entry.path.lower().endswith(ext):
                    yield os.path.abspath(entry.path) if abs else entry.path

get_files_in

get_files_in(directory: str | Path, ext: str | tuple | None = None, *, recursive: bool = True, abs: bool = True) -> list[str]

Returns the paths of files in a directory.

This function searches for files in a directory and yields their paths. If the ext parameter is provided, only files with that extension are returned. The ext parameter is case-insensitive. If the recursive parameter is set to True, the function will search for files in subdirectories recursively.

Parameters:

Name Type Description Default
directory str | Path

The directory to search.

required
ext str | tuple[str, ...]

If provided, only yield files with provided extensions. Defaults to None.

None
recursive bool

Whether to search recursively. Defaults to True.

True
abs bool

Whether to convert paths to absolute paths.

True

Returns:

Type Description
list[str]

list[str]: The absolute path of the files in the directory, matching the provided extension.

Source code in stdl/fs.py
def get_files_in(
    directory: str | Path,
    ext: str | tuple | None = None,
    *,
    recursive: bool = True,
    abs: bool = True,
) -> list[str]:
    """
    Returns the paths of files in a directory.

    This function searches for files in a directory and yields their paths.
    If the `ext` parameter is provided, only files with that extension are returned. The `ext` parameter is case-insensitive.
    If the `recursive` parameter is set to `True`, the function will search for files in subdirectories recursively.

    Args:
        directory (str | Path): The directory to search.
        ext (str | tuple[str, ...], optional): If provided, only yield files with provided extensions. Defaults to None.
        recursive (bool, optional): Whether to search recursively. Defaults to True.
        abs (bool, optional): Whether to convert paths to absolute paths.

    Returns:
        list[str]: The absolute path of the files in the directory, matching the provided extension.
    """

    return list(yield_files_in(directory, ext, recursive=recursive, abs=abs))

yield_dirs_in

yield_dirs_in(directory: str | Path, *, recursive: bool = True, abs: bool = True) -> Generator[str, None, None]

Yields paths to all directories in the specified directory. Yielded paths are converted to absolute paths.

Parameters:

Name Type Description Default
directory str | Path

The directory to search.

required
recursive bool

Whether to search recursively.

True
abs bool

Whether to convert paths to absolute paths.

True

Yields:

Type Description
str

Generator[str, None, None]: The paths of the directories that are found during travelsal.

Source code in stdl/fs.py
def yield_dirs_in(
    directory: str | Path, *, recursive: bool = True, abs: bool = True
) -> T.Generator[str, None, None]:
    """
    Yields paths to all directories in the specified directory.
    Yielded paths are converted to absolute paths.

    Args:
        directory (str | Path): The directory to search.
        recursive (bool, optional): Whether to search recursively.
        abs (bool, optional): Whether to convert paths to absolute paths.


    Yields:
        Generator[str, None, None]: The paths of the directories that are found during travelsal.
    """
    queue = Queue()
    queue.put(directory)
    while not queue.empty():
        next_dir = queue.get()
        for entry in os.scandir(next_dir):
            if entry.is_dir():
                if recursive:
                    queue.put(entry.path)
                yield os.path.abspath(entry.path) if abs else entry.path

get_dirs_in

get_dirs_in(directory: str | Path, *, recursive: bool = True, abs: bool = True) -> list[str]

Returns all directories in the specified directory. Returned paths are converted to absolute paths.

Parameters:

Name Type Description Default
directory str | Path

The directory to search.

required
recursive bool

Whether to search recursively.

True
abs bool

Whether to convert paths to absolute paths.

True

Returns:

Type Description
list[str]

list[str]: The paths of the directories that are found during travelsal.

Source code in stdl/fs.py
def get_dirs_in(directory: str | Path, *, recursive: bool = True, abs: bool = True) -> list[str]:
    """
    Returns all directories in the specified directory.
    Returned paths are converted to absolute paths.

    Args:
        directory (str | Path): The directory to search.
        recursive (bool, optional): Whether to search recursively.
        abs (bool, optional): Whether to convert paths to absolute paths.

    Returns:
        list[str]: The paths of the directories that are found during travelsal.
    """
    return list(yield_dirs_in(directory, recursive=recursive, abs=abs))

ensure_paths_exist

ensure_paths_exist(*args: str | PathLike | Iterable[str | PathLike]) -> None

Ensures that the specified paths exist.

Parameters:

Name Type Description Default
*args

one or more strings representing the paths to check. Can also include an Iterable of paths.

()

Raises:

Type Description
FileNotFoundError

if one of the provided paths does not exist.

Source code in stdl/fs.py
def ensure_paths_exist(*args: str | PathLike | Iterable[str | PathLike]) -> None:
    """
    Ensures that the specified paths exist.

    Args:
        *args : one or more strings representing the paths to check. Can also include an Iterable of paths.

    Raises:
        FileNotFoundError : if one of the provided paths does not exist.
    """

    def check_path(path: str | PathLike):
        if not os.path.exists(os.fspath(path)):
            raise FileNotFoundError(f"Path does not exist: '{path}'")

    for path in args:
        if isinstance(path, (str, bytes, PathLike)):
            check_path(path)
        elif isinstance(path, Iterable):
            for i in path:
                check_path(i)

ensure_paths_dont_exist

ensure_paths_dont_exist(*args: str | PathLike | Iterable[str | PathLike]) -> None

Ensures that the specified paths don't exist.

Parameters:

Name Type Description Default
*args

one or more strings representing the paths to check. Can also include an Iterable of paths.

()

Raises:

Type Description
FileNotFoundError

if one of the provided paths exists.

Source code in stdl/fs.py
def ensure_paths_dont_exist(*args: str | PathLike | Iterable[str | PathLike]) -> None:
    """
    Ensures that the specified paths don't exist.

    Args:
        *args : one or more strings representing the paths to check. Can also include an Iterable of paths.

    Raises:
        FileNotFoundError : if one of the provided paths exists.
    """

    def check_path(path: str | PathLike):
        if os.path.exists(os.fspath(path)):
            raise FileExistsError(f"Path already exists: '{path}'")

    for path in args:
        if isinstance(path, (str, bytes, PathLike)):
            check_path(path)
        elif isinstance(path, Iterable):
            for i in path:
                check_path(i)

exec_cmd

exec_cmd(cmd: list[str] | str, timeout: float = None, shell: bool = False, capture_output: bool = True, check: bool = False, cwd: str = None, stdin: IO = None, stdout: IO = None, stderr: IO = None, input: str | bytes = None, env: dict = None, text: bool = True, *args, **kwargs) -> CompletedCommand

Wrapper for subprocess.run with nicer default arguments.

Parameters:

Name Type Description Default
cmd str | list[str]

command to run. A list of strings or a single string.

required
timeout float

the time after which the command is killed.

None
shell bool

whether or not to run the command in a shell.

False
capture_output bool

whether or not to capture the output to stdout and stderr.

True
check bool

whether or not to raise an exception on a non-zero exit code.

False
cwd str

current working directory to run the command in.

None
stdin IO

file object to read stdin from.

None
stdout IO

file object to write stdout to.

None
stderr IO

file object to write stderr to.

None
input str | bytes

input to send to the command.

None
env dict

environment variables to pass to the new process.

None
text bool

whether or not to return output as text or bytes.

True
*args

additional arguments to pass to subprocess.run.

()
**kwargs

additional keyword arguments to pass to subprocess.run.

{}

Returns:

Type Description
CompletedCommand

subprocess.CompletedProcess : the completed process.

Source code in stdl/fs.py
def exec_cmd(
    cmd: list[str] | str,
    timeout: float = None,  # type:ignore
    shell: bool = False,
    capture_output: bool = True,
    check: bool = False,
    cwd: str = None,  # type:ignore
    stdin: T.IO = None,  # type:ignore
    stdout: T.IO = None,  # type:ignore
    stderr: T.IO = None,  # type:ignore
    input: str | bytes = None,  # type:ignore
    env: dict = None,  # type:ignore
    text: bool = True,
    *args,
    **kwargs,
) -> CompletedCommand:
    """
    Wrapper for subprocess.run with nicer default arguments.

    Args:
        cmd (str | list[str]): command to run. A list of strings or a single string.
        timeout (float, optional): the time after which the command is killed.
        shell (bool, optional): whether or not to run the command in a shell.
        capture_output (bool, optional): whether or not to capture the output to stdout and stderr.
        check (bool, optional): whether or not to raise an exception on a non-zero exit code.
        cwd (str, optional): current working directory to run the command in.
        stdin (IO, optional): file object to read stdin from.
        stdout (IO, optional): file object to write stdout to.
        stderr (IO, optional): file object to write stderr to.
        input (str | bytes): input to send to the command.
        env (dict, optional): environment variables to pass to the new process.
        text (bool): whether or not to return output as text or bytes.
        *args : additional arguments to pass to subprocess.run.
        **kwargs : additional keyword arguments to pass to subprocess.run.

    Returns:
        subprocess.CompletedProcess : the completed process.
    """
    if isinstance(cmd, str):
        cmd = shlex.split(cmd)

    start_time = time.time()

    result = subprocess.run(
        cmd,
        timeout=timeout,
        shell=shell,
        check=check,
        stdin=stdin,
        stdout=stdout,
        stderr=stderr,
        capture_output=capture_output,
        text=text,
        input=input,
        env=env,
        cwd=cwd,
        *args,
        **kwargs,
    )

    return CompletedCommand(
        result.args,
        result.returncode,
        time.time() - start_time,
        result.stdout,
        result.stderr,
    )

read_piped

read_piped() -> str

Reads piped input from stdin.

Source code in stdl/fs.py
def read_piped() -> str:
    """
    Reads piped input from stdin.
    """
    if sys.stdin.isatty():
        return ""
    return sys.stdin.read().strip()

start_file

start_file(path: str | PathLike) -> None

Open the file with your OS's default application.

This function determines the current operating system and uses the appropriate command to open the specified file with the default application. It supports Windows, macOS, and Linux, including Windows Subsystem for Linux (WSL).

Source code in stdl/fs.py
def start_file(path: str | PathLike) -> None:
    """
    Open the file with your OS's default application.

    This function determines the current operating system and uses the appropriate command
    to open the specified file with the default application. It supports Windows, macOS,
    and Linux, including Windows Subsystem for Linux (WSL).
    """
    path = os.fspath(path)
    if is_wsl():
        exec_cmd(f"cmd.exe /C start '{path}'", check=True)
    elif sys.platform == "win32":
        os.startfile(path)
    elif sys.platform == "darwin":
        exec_cmd(f"open {path}", check=True)
    elif sys.platform == "linux":
        exec_cmd(f"xdg-open '{path}'", check=True)
    else:
        raise NotImplementedError(f"Unsupported platform: {sys.platform}")