-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from kyoto7250/add_methods_for_find_project_root
Add methods for find project root
- Loading branch information
Showing
8 changed files
with
665 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
name: lint_and_test | ||
on: [pull_request] | ||
|
||
jobs: | ||
ci: | ||
runs-on: ubuntu-latest | ||
strategy: | ||
fail-fast: false | ||
matrix: | ||
python-version: ["3.8", "3.9", "3.10", "3.11"] | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- name: Set up Python ${{ matrix.python-version }} | ||
uses: actions/setup-python@v4 | ||
with: | ||
python-version: ${{ matrix.python-version }} | ||
- name: Run image | ||
uses: abatilo/actions-poetry@v2 | ||
with: | ||
poetry-version: "1.4.2" | ||
- name: poetry install | ||
run: poetry install | ||
- name: black | ||
run: poetry run black --check --verbose fastconfig/ tests/ | ||
- name: ruff | ||
run: poetry run ruff check --exit-non-zero-on-fix fastconfig/ tests/ | ||
- name: isort | ||
run: poetry run isort --check-only fastconfig/ tests/ | ||
- name: pytest | ||
run: poetry run pytest |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
style: | ||
poetry run black fastconfig/ tests/ | ||
poetry run isort fastconfig/ tests/ | ||
poetry run ruff fastconfig/ tests/ | ||
|
||
test: | ||
poetry run pytest --cov=fastconfig --cov-report=html |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,42 @@ | ||
# fastconfig | ||
A lightweight way to find the project root and load config | ||
|
||
|
||
## Abstract | ||
|
||
This library provides two functionalities: | ||
(The config function is under development) | ||
|
||
* A function to search for files while traversing up to the project root. | ||
- `fastconfig.find_project_root` | ||
- `fastconfig.is_project_root` | ||
- `fastconfig.search` | ||
* A function to directly build a class from a configuration file. | ||
|
||
|
||
## Install | ||
|
||
```bash | ||
pip install fastconfig | ||
``` | ||
|
||
## Usage | ||
|
||
|
||
```python | ||
import fastconfig | ||
import pathlib | ||
from typing import Optional | ||
|
||
path: Optional[pathlib.Path] = fastconfig.search("pyproject.toml") | ||
if path is not None: | ||
# TODO: read config | ||
pass | ||
``` | ||
|
||
## Motivation | ||
|
||
In many projects, it is common to write configuration files, read them in code, and build Config classes. I created this library to enable these functions to be implemented by simply defining a class and specifying a file name (such as pyproject.toml). | ||
|
||
## Contribution | ||
If you have suggestions for features or improvements to the code, please feel free to create an issue or pull request. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import os | ||
from pathlib import Path | ||
from typing import List, Optional, Union | ||
|
||
__version__ = "0.1.0" | ||
PROJECT_ROOTS: List[str] = [".hg", ".git"] | ||
DEPTH: int = 10 | ||
|
||
|
||
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 | ||
|
||
|
||
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 | ||
|
||
|
||
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 |
Oops, something went wrong.