Skip to content

Modules

This package provides public modules.

FastConfig dataclass

this class provides the way to build and update instance from toml or json format file.

Source code in fastconfig/config.py
@dataclass
class FastConfig:
    """this class provides the way to build and update instance from `toml` or `json` format file."""

    @classmethod
    def build(
        cls: Type[_Self], path: Union[str, Path], config: Optional[_Self] = None
    ) -> _Self:
        """
        Read file from path and create/update instance.

        Args:
            path: Union[str, Path]
                a file path to read a config
            config: Optional[_Self]
                an instance inheriting from FastConfig (if updating)
        Returns:
            _Self: an instance inheriting from FastConfig
        """
        if config is None:
            return _FastConfigBuilder.build(path, cls)
        else:
            return _FastConfigBuilder.build(path, config)

    def to_dict(self, use_key: bool = False) -> dict[str, Any]:
        """
        Convert from an instance to dict.

        Args:
            use_key: bool
                Whether to convert to dictionary by class instance name
        Returns:
            dict[str, Any]
        """
        if use_key:
            return asdict(self)

        dic: dict[str, Any] = {}
        for key, f in self.__dataclass_fields__.items():
            metadata: dict[str, Any] = (
                dict(f.metadata) if hasattr(f, "metadata") else {}
            )
            separator = metadata["separator"] if "separator" in metadata else "."
            setting_key: list[str] = (
                metadata["key"].split(separator) if "key" in metadata else [key]
            )
            inside: dict[str, Any] = dic
            for nest_field in setting_key[:-1]:
                if nest_field not in dic:
                    inside[nest_field] = {}
                inside = inside[nest_field]
            inside[setting_key[-1]] = getattr(self, key)
        return dic

build(path, config=None) classmethod

Read file from path and create/update instance.

Parameters:

Name Type Description Default
path Union[str, Path]

Union[str, Path] a file path to read a config

required
config Optional[_Self]

Optional[_Self] an instance inheriting from FastConfig (if updating)

None

Returns: _Self: an instance inheriting from FastConfig

Source code in fastconfig/config.py
@classmethod
def build(
    cls: Type[_Self], path: Union[str, Path], config: Optional[_Self] = None
) -> _Self:
    """
    Read file from path and create/update instance.

    Args:
        path: Union[str, Path]
            a file path to read a config
        config: Optional[_Self]
            an instance inheriting from FastConfig (if updating)
    Returns:
        _Self: an instance inheriting from FastConfig
    """
    if config is None:
        return _FastConfigBuilder.build(path, cls)
    else:
        return _FastConfigBuilder.build(path, config)

to_dict(use_key=False)

Convert from an instance to dict.

Parameters:

Name Type Description Default
use_key bool

bool Whether to convert to dictionary by class instance name

False

Returns: dict[str, Any]

Source code in fastconfig/config.py
def to_dict(self, use_key: bool = False) -> dict[str, Any]:
    """
    Convert from an instance to dict.

    Args:
        use_key: bool
            Whether to convert to dictionary by class instance name
    Returns:
        dict[str, Any]
    """
    if use_key:
        return asdict(self)

    dic: dict[str, Any] = {}
    for key, f in self.__dataclass_fields__.items():
        metadata: dict[str, Any] = (
            dict(f.metadata) if hasattr(f, "metadata") else {}
        )
        separator = metadata["separator"] if "separator" in metadata else "."
        setting_key: list[str] = (
            metadata["key"].split(separator) if "key" in metadata else [key]
        )
        inside: dict[str, Any] = dic
        for nest_field in setting_key[:-1]:
            if nest_field not in dic:
                inside[nest_field] = {}
            inside = inside[nest_field]
        inside[setting_key[-1]] = getattr(self, key)
    return dic

FastConfigError

Bases: Exception

super class for all errors returned by FastConfig.

Source code in fastconfig/exception.py
4
5
6
7
class FastConfigError(Exception):
    """super class for all errors returned by FastConfig."""

    ...

InvalidConfigError

Bases: FastConfigError

exception when providing files or classes in unsupported formats.

Source code in fastconfig/exception.py
class InvalidConfigError(FastConfigError):
    """exception when providing files or classes in unsupported formats."""

    ...

MissingRequiredElementError

Bases: FastConfigError

exception when providing field has no default value and the corresponding value could not be read from the file.

Source code in fastconfig/exception.py
class MissingRequiredElementError(FastConfigError):
    """exception when providing `field` has no default value and the corresponding value could not be read from the file."""

    ...

UnexpectedValueError

Bases: FastConfigError

exception whe providing failed type-checking.

Source code in fastconfig/exception.py
class UnexpectedValueError(FastConfigError):
    """exception whe providing failed type-checking."""

    ...

fc_field(key=None, separator='.', default=MISSING, default_factory=MISSING, init=True, repr=True, hash=None, compare=True, metadata=None)

Return dataclass::field.

wrapper of dataclass::field for FastConfig definition. same as field except for passing key and separator.

Parameters:

Name Type Description Default
key Optional[Union[str, int]]

Optional[str | int] the name of the key you want to read, divided by separator when retrieving data

None
separator str

str Separator for splitting key values, default is .

'.'

Returns:

Type Description
_T

_T

Source code in fastconfig/config.py
def fc_field(
    key: Optional[Union[str, int]] = None,
    separator: str = ".",
    default: _T = MISSING,
    default_factory: Type[_T] = MISSING,
    init: bool = True,
    repr: bool = True,
    hash: Optional[bool] = None,
    compare: bool = True,
    metadata: Optional[Mapping[Any, Any]] = None,
) -> _T:
    """
    Return `dataclass::field`.

    wrapper of `dataclass::field` for FastConfig definition.
    same as `field` except for passing `key` and `separator`.

    Args:
        key: Optional[str | int]
            the name of the key you want to read, divided by `separator` when retrieving data
        separator: str
            Separator for splitting key values, default is `.`

    Returns:
        _T
    """
    options: dict[str, Any] = {
        "default": default,
        "default_factory": default_factory,
        "init": init,
        "repr": repr,
        "hash": hash,
        "compare": compare,
        "metadata": metadata if metadata is not None else {},
    }

    if key is not None:
        options["metadata"]["key"] = key
    options["metadata"]["separator"] = separator
    return field(**options)

find_project_root(path=None)

Return if the project root is found, or None if not.

Parameters:

Name Type Description Default
path Optional[Union[str, Path]]

A path string or Path object to start searching, If nothing is passed, start in the current directory

None

Returns:

Type Description
Optional[Path]

Optional[Path]: the project root path, or None if the project root is not found

Source code in fastconfig/searcher.py
def find_project_root(path: Optional[Union[str, Path]] = None) -> Optional[Path]:
    """
    Return if the project root is found, or None if not.

    Args:
        path (Optional[Union[str, Path]]):
            A path string or Path object to start searching, If nothing is passed, start in the current directory

    Returns:
        Optional[Path]: the project root path, or None if the project root is not found
    """
    if path is None:
        path = os.getcwd()
    cnt: int = 0

    candidate: Path = Path(path) if isinstance(path, str) else path
    if is_project_root(candidate):
        return candidate

    while cnt < DEPTH:
        candidate = candidate.parent
        if is_project_root(candidate):
            return candidate

        if candidate.parent == candidate:
            return None

        cnt += 1
    return None

is_project_root(path)

Check the given path is the project root directory or not.

This method determines the project root by whether the version control tool directory exists.

Parameters:

Name Type Description Default
path Union[str, Path]

The path to check whether it is the project root or not

required

Returns:

Name Type Description
bool bool

The result of the project root or not

Source code in fastconfig/searcher.py
def is_project_root(path: Union[str, Path]) -> bool:
    """
    Check the given path is the project root directory or not.

    This method determines the project root by whether the version control tool directory exists.

    Args:
        path (Union[str, Path]):
            The path to check whether it is the project root or not

    Returns:
        bool: The result of the project root or not
    """
    if isinstance(path, str):
        path = Path(path)

    if path.is_file():
        path = path.parent

    for candidate in PROJECT_ROOTS:
        if path.joinpath(candidate).is_dir():
            return True
    return False

search(target, path=None, end_up_the_project_root=True)

Recursively searches for files with the name of the target and returns the result.

Parameters:

Name Type Description Default
target Union[str, Path]

Search target filename, and directory names are ignored.

required
path Optional[Union[str, Path]]

A path string or Path object to start searching, If nothing is passed, start in the current directory.

None
end_up_the_project_root bool

Whether or not to search the directory where the version control tool exists

True

Returns:

Type Description
Optional[Path]

Optional[Path]: a path of the target file, or None if the target file is not found

Source code in fastconfig/searcher.py
def search(
    target: Union[str, Path],
    path: Optional[Union[str, Path]] = None,
    end_up_the_project_root: bool = True,
) -> Optional[Path]:
    """
    Recursively searches for files with the name of the target and returns the result.

    Args:
        target (Union[str, Path]):
            Search target filename, and directory names are ignored.

        path (Optional[Union[str, Path]]):
            A path string or Path object to start searching, If nothing is passed, start in the current directory.

        end_up_the_project_root (bool):
            Whether or not to search the directory where the version control tool exists

    Returns:
        Optional[Path]: a path of the target file, or None if the target file is not found
    """
    if isinstance(target, str):
        target = Path(target)

    target_name: str = target.name
    if path is None:
        path = os.getcwd()

    cnt: int = 0
    candidate: Path = Path(os.path.join(path, target_name))
    if candidate.exists():
        return candidate
    if is_project_root(candidate):
        return None

    while cnt < DEPTH:
        candidate = candidate.parent.parent.joinpath(target_name)
        if candidate.exists():
            return candidate

        if candidate.parent.parent.joinpath(target_name) == candidate or (
            end_up_the_project_root and is_project_root(candidate)
        ):
            return None

        cnt += 1
    return None