Skip to content

Commit d3c231b

Browse files
committed
Remove .marker example and add .here example
1 parent 8d22b80 commit d3c231b

7 files changed

+90
-87
lines changed

README.md

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44

55
Simple and short code examples to find the root directory of your project in different ways. This can be useful in projects where you are reading or writing data to directories inside your project directory. All examples return a [`pathlib.Path`](https://docs.python.org/3/library/pathlib.html) object.
66

7-
All code in this repository is licensed under the [MIT No Attribution (MIT-0) License](./LICENSE) and can be used without attribution.
7+
To use, just copy and paste one of the examples into your project. Make any adjustments as needed or desired. These examples are all fairly straightforward and generally have no external dependencies. All code in this repository is licensed under the [MIT No Attribution (MIT-0) License](./LICENSE) and can be used without attribution.
88

9-
If for some reason you prefer a take on a dependency instead of copy-pasting a small amount of code, see these packages: [pyprojroot](https://github.com/chendaniely/pyprojroot), [rootpath](https://github.com/grimen/python-rootpath)
9+
If for some reason you prefer to take on a dependency or to have a function resolve a bunch of criteria automagically, see these packages as alternatives: [pyprojroot](https://github.com/chendaniely/pyprojroot), [rootpath](https://github.com/grimen/python-rootpath)
1010

1111
## Cookbook
1212

@@ -20,6 +20,8 @@ Table of contents:
2020

2121
### Find pyproject.toml file
2222

23+
[`pyproject.toml`](https://packaging.python.org/en/latest/guides/writing-pyproject-toml/) is a modern standard configuration file for packaging metadata and tools configuration. It's typically in the project root directory of Python projects.
24+
2325
```python
2426
from pathlib import Path
2527

@@ -37,6 +39,8 @@ def proj_root_from_pyproject_toml() -> Path:
3739

3840
### Find pyproject.toml file matching project name
3941

42+
If you're in a monorepo with multiple Python packages, you may want to find the specific intended `pyproject.toml` file by matching on its contents.
43+
4044
```python
4145
from pathlib import Path
4246
import tomllib
@@ -78,6 +82,8 @@ def proj_root_from_pyproject_toml() -> Path:
7882
7983
### Find .git directory
8084
85+
If using Git as your version control system, there will be a `.git` directory in your project root.
86+
8187
```python
8288
from pathlib import Path
8389
@@ -93,41 +99,42 @@ def proj_root_from_git() -> Path:
9399
```
94100
95101

96-
### Find a specific file containing a specific value
102+
### Find a .here file
103+
104+
Popularized by R's [here](https://here.r-lib.org/) package, some project root detection tools support finding a file named `.here`.
97105

98106
```python
99107
from pathlib import Path
100108

101109

102-
def proj_root_from_marker_file() -> Path:
103-
"""Find the nearest parent directory containing a file '.marker' whose contents are
104-
'value'."""
105-
marker_file_name = ".marker"
106-
marker_contents = "value"
110+
def proj_root_from_here_file() -> Path:
111+
"""Find the nearest parent directory containing a file '.here'."""
107112
current_dir = Path.cwd()
108113
while current_dir.parent != current_dir:
109-
if (current_dir / marker_file_name).exists():
110-
if (current_dir / marker_file_name).read_text().strip() == marker_contents:
111-
return current_dir
114+
if (current_dir / ".here").exists():
115+
return current_dir
112116
current_dir = current_dir.parent
113-
raise RuntimeError(
114-
f"{marker_file_name} containing '{marker_contents}' "
115-
"not found in any parent directories."
116-
)
117+
raise RuntimeError("'.here' file not found in any parent directories.")
117118
```
118119

119120

120121
### Read from environment variable
121122

123+
Environment variables are a good way specify configuration values that vary between running environments.
124+
122125
```python
123126
import os
124127
from pathlib import Path
125128

126129

127130
def proj_root_from_env_var() -> Path:
128-
"""Get the project root directory from an environment variable."""
131+
"""Get the project root directory from an environment variable. It must be an
132+
absolute path."""
129133
proj_root = os.environ.get("PROJ_ROOT")
130134
if not proj_root:
131135
raise RuntimeError("PROJ_ROOT environment variable is not set.")
132-
return Path(proj_root)
136+
path = Path(proj_root)
137+
if not path.is_absolute():
138+
raise RuntimeError("PROJ_ROOT must be an absolute path.")
139+
return path
133140
```

src/_README.md.template

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44

55
Simple and short code examples to find the root directory of your project in different ways. This can be useful in projects where you are reading or writing data to directories inside your project directory. All examples return a [`pathlib.Path`](https://docs.python.org/3/library/pathlib.html) object.
66

7-
All code in this repository is licensed under the [MIT No Attribution (MIT-0) License](./LICENSE) and can be used without attribution.
7+
To use, just copy and paste one of the examples into your project. Make any adjustments as needed or desired. These examples are all fairly straightforward and generally have no external dependencies. All code in this repository is licensed under the [MIT No Attribution (MIT-0) License](./LICENSE) and can be used without attribution.
88

9-
If for some reason you prefer a take on a dependency instead of copy-pasting a small amount of code, see these packages: [pyprojroot](https://github.com/chendaniely/pyprojroot), [rootpath](https://github.com/grimen/python-rootpath)
9+
If for some reason you prefer to take on a dependency or to have a function resolve a bunch of criteria automagically, see these packages as alternatives: [pyprojroot](https://github.com/chendaniely/pyprojroot), [rootpath](https://github.com/grimen/python-rootpath)
1010

1111
## Cookbook
1212

@@ -20,10 +20,14 @@ Table of contents:
2020

2121
### Find pyproject.toml file
2222

23+
[`pyproject.toml`](https://packaging.python.org/en/latest/guides/writing-pyproject-toml/) is a modern standard configuration file for packaging metadata and tools configuration. It's typically in the project root directory of Python projects.
24+
2325
{find_pyproject_toml}
2426

2527
### Find pyproject.toml file matching project name
2628

29+
If you're in a monorepo with multiple Python packages, you may want to find the specific intended `pyproject.toml` file by matching on its contents.
30+
2731
{find_pyproject_toml_project_name}
2832

2933
> [!TIP]
@@ -44,12 +48,18 @@ Table of contents:
4448

4549
### Find .git directory
4650

51+
If using Git as your version control system, there will be a `.git` directory in your project root.
52+
4753
{find_git}
4854

49-
### Find a specific file containing a specific value
55+
### Find a .here file
5056

51-
{find_marker_file}
57+
Popularized by R's [here](https://here.r-lib.org/) package, some project root detection tools support finding a file named `.here`.
58+
59+
{find_here_file}
5260

5361
### Read from environment variable
5462

63+
Environment variables are a good way specify configuration values that vary between running environments.
64+
5565
{read_from_env_var}

src/examples/find_here_file.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from pathlib import Path
2+
3+
4+
def proj_root_from_here_file() -> Path:
5+
"""Find the nearest parent directory containing a file '.here'."""
6+
current_dir = Path.cwd()
7+
while current_dir.parent != current_dir:
8+
if (current_dir / ".here").exists():
9+
return current_dir
10+
current_dir = current_dir.parent
11+
raise RuntimeError("'.here' file not found in any parent directories.")

src/examples/find_marker_file.py

Lines changed: 0 additions & 18 deletions
This file was deleted.

src/examples/read_from_env_var.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,12 @@
33

44

55
def proj_root_from_env_var() -> Path:
6-
"""Get the project root directory from an environment variable."""
6+
"""Get the project root directory from an environment variable. It must be an
7+
absolute path."""
78
proj_root = os.environ.get("PROJ_ROOT")
89
if not proj_root:
910
raise RuntimeError("PROJ_ROOT environment variable is not set.")
10-
return Path(proj_root)
11+
path = Path(proj_root)
12+
if not path.is_absolute():
13+
raise RuntimeError("PROJ_ROOT must be an absolute path.")
14+
return path

src/tests/test_find_here_file.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import pytest
2+
3+
from examples.find_here_file import proj_root_from_here_file
4+
5+
6+
def test_find_here_current_wd(tmp_path, monkeypatch):
7+
here_path = tmp_path / ".here"
8+
here_path.touch()
9+
10+
monkeypatch.chdir(tmp_path)
11+
12+
assert proj_root_from_here_file() == tmp_path
13+
14+
15+
def test_find_here_in_parents(tmp_path, monkeypatch):
16+
here_path = tmp_path / ".here"
17+
here_path.touch()
18+
19+
subdir = tmp_path / "subdir"
20+
subdir.mkdir()
21+
monkeypatch.chdir(tmp_path / "subdir")
22+
assert proj_root_from_here_file() == tmp_path
23+
24+
subsubdir = subdir / "subsubdir"
25+
subsubdir.mkdir()
26+
monkeypatch.chdir(subsubdir)
27+
assert proj_root_from_here_file() == tmp_path
28+
29+
30+
def test_find_here_not_found(tmp_path, monkeypatch):
31+
subdir = tmp_path / "subdir"
32+
subdir.mkdir()
33+
monkeypatch.chdir(subdir)
34+
with pytest.raises(RuntimeError):
35+
proj_root_from_here_file()

src/tests/test_find_marker_file.py

Lines changed: 0 additions & 46 deletions
This file was deleted.

0 commit comments

Comments
 (0)