findpaths.py
Overview
The [findpaths.py](/projects/286/67504) module provides utility functions for locating and parsing pytest configuration files within a filesystem hierarchy. It primarily deals with discovering configuration files such as `pytest.ini`, `setup.cfg`, `tox.ini`, and `pyproject.toml`, parsing their contents into a standardized dictionary format, and determining the root directory for pytest runs based on command-line arguments and filesystem layout.
Key functionalities include:
Parsing various configuration file formats (
.ini,.cfg,.toml) into a unified dictionary representing pytest settings.Searching directories and arguments for valid pytest configuration files.
Computing common ancestor directories for sets of paths.
Handling pytest-specific command line options like
--inifileand--rootdir.Validating directory paths and configuration file presence.
Converting configuration data into a compatible format expected by pytest systems.
This module is a foundational piece to support pytest's ability to configure itself flexibly depending on project layout and user invocation.
Detailed Explanation of Functions and Methods
_parse_ini_config(path: Path) -> iniconfig.IniConfig
Parses a generic `.ini` configuration file using the legacy [IniConfig](/projects/286/67332) parser from the `iniconfig` library.
Parameters:
path(Path): The path to the.inifile to parse.
Returns:
iniconfig.IniConfig: Parsed configuration object.
Raises:
UsageError: If the.inifile cannot be parsed due to syntax errors.
Usage example:
config = _parse_ini_config(Path("pytest.ini"))
load_config_dict_from_file(filepath: Path) -> ConfigDict | None
Loads pytest configuration from a given file path if it contains valid pytest settings.
Parameters:
filepath(Path): Path to the configuration file.
Returns:
ConfigDict(alias fordict[str, Union[str, list[str]]]): Dictionary of pytest configuration options if found.Noneif no valid pytest configuration is found in the file.
Supported file types and parsing logic:
.ini: Reads[pytest]section..cfg: Reads[tool:pytest]section only; raises error if[pytest]section is present..toml: Reads[tool.pytest.ini_options]table and converts all scalar values to strings for compatibility.
Raises:
UsageError: For parsing errors or unsupported configuration formats.Calls
_pytest.outcomes.failif an unsupported[pytest]section is found insetup.cfg.
Usage example:
config_dict = load_config_dict_from_file(Path("setup.cfg")) if config_dict is not None: print("Loaded pytest config:", config_dict)
locate_config(invocation_dir: Path, args: Iterable[Path]) -> tuple[Path | None, Path | None, ConfigDict]
Searches for a valid pytest configuration file based on a list of argument paths and returns its root directory, config file path, and configuration dictionary.
Parameters:
invocation_dir(Path): Directory where pytest was invoked.args(Iterable[Path]): List of file or directory paths to consider for locating config.
Returns:
Tuple containing:
rootdir(Path | None): The directory root of the pytest project.inifile(Path | None): The path to the found configuration file.cfgdict(ConfigDict): The parsed configuration dictionary (empty if no config found).
Description:
Iterates through provided paths and their parent directories.
Looks for config files named:
pytest.ini,.pytest.ini,pyproject.toml,tox.ini,setup.cfg.Prefers the first valid pytest config found.
If a
pyproject.tomlis found but no pytest config inside, returns it with empty config dict.
Usage example:
rootdir, inifile, config = locate_config(Path.cwd(), [Path("tests")]) if rootdir: print(f"Config found in {inifile} with rootdir {rootdir}")
get_common_ancestor(invocation_dir: Path, paths: Iterable[Path]) -> Path
Determines the common ancestor directory of a set of filesystem paths.
Parameters:
invocation_dir(Path): Directory where pytest was invoked.paths(Iterable[Path]): Paths to compute the common ancestor for.
Returns:
Path: The common ancestor directory path.
Details:
If no paths exist, returns
invocation_dir.If the common ancestor is a file, returns its parent directory.
Uses
commonpathutility to find shared parent directories.
Usage example:
ancestor = get_common_ancestor(Path.cwd(), [Path("tests/test_one.py"), Path("tests/test_two.py")]) print(f"Common ancestor: {ancestor}")
get_dirs_from_args(args: Iterable[str]) -> list[Path]
Extracts directories from command-line arguments, handling both file paths and node IDs (pytest test specifiers).
Parameters:
args(Iterable[str]): List of command line arguments.
Returns:
list[Path]: List of directories corresponding to the args.
Details:
Filters out options (arguments starting with
-).For node IDs (like
test_module.py::TestClass), extracts the file part.Converts file paths to directories (parent if file).
Usage example:
dirs = get_dirs_from_args(["tests/test_module.py::TestClass", "-v"]) print(dirs) # [Path("tests")]
determine_setup(*, inifile: str | None, args: Sequence[str], rootdir_cmd_arg: str | None, invocation_dir: Path) -> tuple[Path, Path | None, ConfigDict]
Determines the pytest root directory, configuration file path, and configuration dictionary based on command-line arguments and invocation context.
Parameters:
inifile(str | None): The--inifilecommand line argument if provided.args(Sequence[str]): Remaining command line arguments.rootdir_cmd_arg(str | None): The--rootdircommand line argument if provided.invocation_dir(Path): Directory where pytest was invoked.
Returns:
Tuple containing:
rootdir(Path): The root directory for pytest.inifile(Path | None): Path to the configuration file, if any.inicfg(ConfigDict): Parsed configuration dictionary.
Logic Summary:
If
--inifileis given, load config from there and set rootdir as its parent (unless overridden).Otherwise, find common ancestor from args and locate config file starting there.
If no config found, try heuristics like locating
setup.pyto determine rootdir.If
--rootdiris given, validate and override rootdir.Raise
UsageErrorif--rootdirpoints to a non-directory.
Usage example:
rootdir, inifile, config = determine_setup( inifile=None, args=["tests"], rootdir_cmd_arg=None, invocation_dir=Path.cwd(), ) print(f"Rootdir: {rootdir}, Inifile: {inifile}, Config: {config}")
is_fs_root(p: Path) -> bool
Checks if the given path points to the root of the filesystem.
Parameters:
p(Path): Path to check.
Returns:
bool:Trueif path is root filesystem (e.g.,/on Unix,C:\on Windows), elseFalse.
Usage example:
print(is_fs_root(Path("/"))) # True on Unix print(is_fs_root(Path("C:\\"))) # True on Windows print(is_fs_root(Path("/home/user"))) # False
Important Implementation Details and Algorithms
Parsing Strategy:
The module supports multiple configuration file formats for pytest, using specific sections based on file type:.inifiles use[pytest]section..cfgfiles use[tool:pytest]and prohibit[pytest]..tomlfiles use[tool.pytest.ini_options].
This reflects pytest's evolving configuration strategy accommodating legacy and modern config styles.
Configuration Value Normalization:
For TOML files, all scalar values are converted to strings to maintain compatibility with the rest of pytest's config system, which expects strings or lists of strings.Filesystem Traversal:
Thelocate_configfunction traverses upwards from given paths to find configuration files, enabling pytest to detect project roots reliably.Common Ancestor Determination:
The functionget_common_ancestorintelligently finds the nearest shared directory among a set of paths, considering edge cases like files and filesystem roots.Error Handling:
The module raisesUsageErrorfor invalid configurations and uses pytest'sfailfunction to enforce deprecated config styles, ensuring users receive prompt feedback on misconfigurations.
Interaction with Other System Components
Configuration System:
This module feeds parsed configuration dictionaries into pytest's core configuration system, enabling command line and file-based settings to be merged.Command-Line Interface:
Functions likedetermine_setupdirectly process CLI options (--inifile,--rootdir, positional args) to decide pytest's execution context.Path Utilities:
Utilizes_pytest.pathlibutilities such asabsolutepath,commonpath, andsafe_existsto handle path normalization and safe existence checks.Error and Outcome Handling:
Imports and usesUsageError(custom exception) and_pytest.outcomes.failto manage error reporting and graceful exits.Third-Party Libraries:
Usesiniconfigfor.inifile parsing andtomli/tomllibfor.tomlparsing depending on Python version.
Visual Diagram of Main Functions and Relationships
flowchart TD
A[determine_setup] --> B[get_dirs_from_args]
A --> C[get_common_ancestor]
A --> D[locate_config]
D --> E[load_config_dict_from_file]
E --> F[_parse_ini_config]
E --> G[toml parsing logic]
C --> H[commonpath utility]
B --> I[safe_exists]
A -.-> J[is_fs_root]
E -.-> K[fail on deprecated config]
style A fill:#f9f,stroke:#333,stroke-width:2px
style D fill:#bbf,stroke:#333,stroke-width:1px
style E fill:#bbf,stroke:#333,stroke-width:1px
style C fill:#bbf,stroke:#333,stroke-width:1px
style B fill:#bbf,stroke:#333,stroke-width:1px
Summary
[findpaths.py](/projects/286/67504) is a utility module crucial for pytest's configuration discovery and setup. It encapsulates the logic for searching, parsing, and validating pytest configuration files across multiple formats and locations. By integrating with pytest's CLI parsing and filesystem utilities, it determines the project root and configuration context, enabling pytest to run tests consistently in diverse project layouts.
This module ensures backward compatibility and enforces configuration correctness, facilitating a smooth user experience when configuring pytest runs.