Skip to main content

herepath

CI PyPI Python versions License: MIT Docs DOI

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.4.tar.gz (23.1 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.4-py3-none-any.whl (14.5 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: herepath-0.1.4.tar.gz
  • Upload date:
  • Size: 23.1 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.4.tar.gz
Algorithm Hash digest
SHA256 f3d90c5fdff56663013b90092151a7582d27bfa188bd9bab093ff7ae8cd31095
MD5 7fb832d48acdc1218894992c8749c9e4
BLAKE2b-256 6683d5dc8148919585bde1f5ba9a46fd86940554a5b8ecc66de12a213253a68a

See more details on using hashes here.

Provenance

The following attestation bundles were made for herepath-0.1.4.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.4-py3-none-any.whl.

File metadata

  • Download URL: herepath-0.1.4-py3-none-any.whl
  • Upload date:
  • Size: 14.5 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.4-py3-none-any.whl
Algorithm Hash digest
SHA256 d0a723c904025cb83d207a8678d3a86e8680ac0022f9a417e8ba512051b0f31a
MD5 2d504af760a5bcb3f7377bc8103128df
BLAKE2b-256 fcb44779a7a533cb1e20e493ed0735515889d198dd6c5a291270ba2a75a2375d

See more details on using hashes here.

Provenance

The following attestation bundles were made for herepath-0.1.4-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