Skip to main content

herepath

CI PyPI Python versions License: MIT Docs

A simpler way to find your files. A Python port of the R here package.

📖 Full documentation (English/French): https://pinto-katende-jonathan.github.io/herepath/

herepath builds paths relative to your project's root, no matter what the current working directory is. Stop writing brittle ../../data/x.csv paths or relying on where a script happens to be launched from.

from herepath import here

here("data", "penguins.csv")
# -> /home/me/myproject/data/penguins.csv   (always, from anywhere)

Installation

pip install herepath

One name everywhere: pip install herepath, import herepath, and a herepath command. (An unrelated pyhere package by another author exists on PyPI; herepath is deliberately named to avoid any confusion with it.)

For local development, from the project directory:

pip install -e ".[dev]"

How it works

On the first call to here(), herepath walks up the directory tree from the current working directory until it finds a directory matching one of these criteria (in order):

Category Markers
Explicit .here
Python pyproject.toml, setup.py, setup.cfg, Pipfile, poetry.lock, environment.yml
Editors .vscode/, .idea/, *.Rproj, _quarto.yml
Version control .git, .hg/, .svn/

The closest matching ancestor wins, so a sub-package in a monorepo resolves to its own directory. If nothing matches, the current working directory is used as a fallback. requirements.txt is deliberately not a marker: it is too often duplicated in subdirectories (docs/, tests/), which would anchor the root in the wrong place. Override the criteria with set_criteria() if you need to.

API

here(*args) -> Path

Drop-in replacement for os.path.join, anchored at the project root.

here()                       # the project root
here("data", "raw", "x.csv") # root/data/raw/x.csv
here("data/raw/x.csv")       # same: components may contain "/"

data = here("data")          # absolute
here(data)                   # returned unchanged
here(data, "x.csv")          # absolute anchor kept -> data/x.csv

The result is always an absolute Path, so it stays valid even if the working directory changes later.

i_am(path, *, uuid=None) -> Path

Declare where the current script lives, relative to the project root. This is the recommended and most robust way to fix the root. Put it near the top of a script or notebook:

from herepath import i_am, here
i_am("analysis/report.py")

here("data", "penguins.csv")

It walks up from the working directory until it finds a directory containing path, and pins that as the root. On success it prints a one-line report (here() starts at ...); pass quiet=True to suppress it. If the file can't be found, it raises FileNotFoundError with a descriptive message, which protects you from running a script in the wrong place. Pass uuid="..." to also require a unique marker string within the first 100 lines of the file, for extra safety.

set_here(path=".", verbose=True) -> Path

Create an empty .here marker file to pin a root when no other criterion applies.

reset()

Forget the cached root so it is re-detected on the next call. Handy in long-lived sessions like Jupyter notebooks (after moving files or changing directory) and in tests.

find_root(*criteria, start=".") -> Path

Lower-level escape hatch for custom root markers, in the spirit of R's rprojroot::find_root. Does not cache anything or touch the session root. Build criteria with has_file, has_dir, has_glob; a directory matches if it satisfies any of them:

from herepath import find_root, has_file, has_dir

find_root(has_file("Makefile"), has_dir(".git"))

set_criteria(*criteria) / reset_criteria()

Customise what counts as a project root for the whole session. Useful for organisations with their own markers:

from herepath import set_criteria, has_file, has_dir

set_criteria(has_file("company_project.json"), has_dir("src"))
# ... here() now uses these markers
reset_criteria()  # back to the built-in defaults

using_root(path) context manager

Temporarily pin the root, restoring the previous state on exit. Ideal in tests:

from herepath import using_root, here

with using_root(tmp_path):
    assert here("data") == tmp_path / "data"
# previous root (or auto-detection) restored here

Debugging detection: dr_here(trace=True)

When the wrong root is picked, trace=True prints the full upward search:

Searching from:
  /project/notebooks
Checking:
  /project/notebooks
  /project   <- contains a file `pyproject.toml`
Matched:
  /project

Forcing the root with HEREPATH_ROOT

Set the HEREPATH_ROOT environment variable to an existing directory to override auto-detection entirely. This is the recommended escape hatch for Docker, CI, and deployment, where the heuristics may not apply:

HEREPATH_ROOT=/app python analysis/report.py

If it points to a path that isn't a directory, here() raises ValueError so misconfiguration fails loudly. An explicit i_am() call still takes precedence.

dr_here(show_reason=True)

Print a situation report explaining where the root is and why, which is useful when here() gives unexpected results.

here() starts at /home/me/myproject
- This directory contains a file `pyproject.toml`
- Initial working directory: /home/me/myproject/analysis
- Current working directory: /home/me/myproject/analysis

When not to use herepath

herepath is for scripts, notebooks and analyses: code run from within a project tree. It is not meant for use inside an installed library, because once a package is installed the source layout no longer exists. To access data bundled with an installed package, use importlib.resources instead.

Differences from the R package

  • Returns pathlib.Path objects instead of strings.
  • The default root criteria are Python-flavoured (e.g. pyproject.toml) rather than R-flavoured (e.g. DESCRIPTION), while keeping the universal markers (.here, .git, editors).
  • The root is resolved lazily on first use (Python has no package-load hook tied to a session the way R does).

Command line

Installing the package also provides a herepath command, handy in shell scripts and Makefiles:

herepath                      # print the project root
herepath data penguins.csv    # print root/data/penguins.csv
herepath --report             # situation report (why this root?)
herepath --version

# e.g. anchor a command at the project root from any subdirectory:
cat "$(herepath data/penguins.csv)"

Development

pip install -e ".[dev]"
pre-commit install   # optional: run linters on commit

pytest               # tests
pytest --cov         # tests + coverage
ruff check .         # lint
ruff format .        # format
mypy                 # type-check

See CONTRIBUTING.md for the full guide. The project is tested on CPython 3.8 to 3.13 across Linux, macOS and Windows.

Authors and acknowledgements

Main developer and creator: Jonathan Katende Pinto.

Main contributors:

  • MWANZA LUBUKAYI Henock
  • MUTONJI BUKAMA Arsène
  • KHANG MATE ZULBAL Emmanuel
  • MUKWIYO MUKALO Patrick

Inspired by the R here package by Kirill Müller and Jennifer Bryan.

License

MIT, © Jonathan Katende Pinto.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

herepath-0.1.2.tar.gz (22.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

herepath-0.1.2-py3-none-any.whl (14.4 kB view details)

Uploaded Python 3

File details

Details for the file herepath-0.1.2.tar.gz.

File metadata

  • Download URL: herepath-0.1.2.tar.gz
  • Upload date:
  • Size: 22.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for herepath-0.1.2.tar.gz
Algorithm Hash digest
SHA256 b0df65f472f85ae2f2d4a44b17ecdbc257142b352d83407da403f10380f7101b
MD5 60c2dddd4d2dca640fb55d5e141afaec
BLAKE2b-256 467b283a94b110857161d4532c4eb62101007ffbccda5ab06985ec3f831e509a

See more details on using hashes here.

Provenance

The following attestation bundles were made for herepath-0.1.2.tar.gz:

Publisher: publish.yml on Pinto-Katende-Jonathan/herepath

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file herepath-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: herepath-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 14.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for herepath-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 f9b83cbf8f02c331ce27762ad5335a24ff96d12217c10b880cb85b8abcb6c61a
MD5 44242233b65a31407000c71d84e0b539
BLAKE2b-256 62732dac3ae2c83c2f1543b910fc004b57f099ccb81614671c34169280a249ee

See more details on using hashes here.

Provenance

The following attestation bundles were made for herepath-0.1.2-py3-none-any.whl:

Publisher: publish.yml on Pinto-Katende-Jonathan/herepath

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page