pooch: a download manager with a cache for data files
A friend to fetch your data files
At a glance
- What is it?
- pooch is a small pure Python library that fetches data files over HTTP, FTP, DOI and data repositories, stores them in a local cache folder, and verifies each one against a known hash so that a rerun does not download again. The judgement is that the interesting part is the split between retrieve for a one-off file and create for a versioned registry, and that the test suite deliberately runs against the installed package rather than the source tree.
- Who is it for?
- pooch fits a scientific package that ships or fetches sample data and wants the download to happen automatically, on the first run, with a checksum to prove the file is the one you meant, because the library does that in a few lines and pulls in three dependencies. It is the wrong choice for a large data workflow, where a dedicated tool with parallel transfers, resumable downloads and scheduling belongs, since pooch is deliberately a single file at a time helper.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 44 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A cache folder and a promise not to download twice
Pooch is a Python library that manages data by downloading files from a server, only when needed, and storing them locally in a data cache, which is a folder on your computer. The repository description puts it more plainly, a friend to fetch your data files.
The readme frames it with two questions that read like an FAQ. Do you just want to download a file without messing with requests and urllib? Are you trying to add sample datasets to your Python package? Both answers are yes, and the library is small enough that the answer is in the first page of the documentation.
The design constraints are listed as four bullets and they matter. It is pure Python with minimal dependencies. It downloads over HTTP and FTP and from data repositories such as Zenodo and figshare. It has built-in post-processors that unzip and decompress the data after the download. And it is designed to be extended, so you can write your own downloaders and post-processors.
That last point is the one that makes it a library rather than a script. The built-in set covers the common cases, and the extension points mean the uncommon cases are still possible without forking.
The project is part of the Fatiando a Terra family of open source packages, the documentation lives at fatiando.org/pooch with a separate development version, and the last push to the repository was on 2026-09-09.
retrieve is the one-liner and the hash is the contract
The example in the readme is aimed at a scientist who wants one data file, and it shows the whole API in a few lines.
fname_bathymetry = pooch.retrieve(
url="https://github.com/fatiando-data/caribbean-bathymetry/releases/download/v1/caribbean-bathymetry.csv.xz",
known_hash="md5:a7332aa6e69c77d49d7fb54b764caa82",
)The comments explain the behaviour. Running this again will not cause a download, and Pooch will check the hash of the downloaded file against the given value to make sure it is the right file, not corrupted or outdated.
So the hash is doing two jobs at once. It is the identity of the file, so the cache knows whether what it has is what you asked for, and it is the corruption check, so a truncated download is caught rather than read as data.
The second example shows the DOI form, and it is the feature that matters for the scientific audience. Pooch can download based on a DOI from certain providers:
fname_gravity = pooch.retrieve(
url="doi:10.5281/zenodo.5882430/southern-africa-gravity.csv.xz",
known_hash="md5:1dee324a14e647855366d6eb01a1ef35",
)The readme puts the benefit plainly for a researcher. You can host your data on a repository and download it using the DOI, you can have the data downloaded automatically by code instead of telling colleagues to do it themselves, and you can make sure that everyone running the code has the same version of the data files.
create is the versioned registry a package author wants
The second example in the readme is for package developers who ship sample data, and it uses a different entry point, pooch.create, which returns what the comments call a new friend to manage your sample data storage.
The parameters are where the design shows.
GOODBOY = pooch.create(
path=pooch.os_cache("mypackage"),
base_url="https://github.com/myproject/mypackage/raw/{version}/data/",
version=version,
version_dev="main",
env="MYPACKAGE_DATA_DIR",
)The path is the folder where the data will be stored, and the suggestion is to use the default cache folder for your operating system, which is what os_cache gives you. The base URL is the remote data store, and the comment notes that .format will be called on the string to insert the version.
The version argument is the important one. Pooches are versioned so that you can use multiple versions of a package simultaneously, and the version is appended to the path, using a PEP 440 compliant version number. The version_dev argument handles development versions, because a version with a +XX.XXXXX suffix is treated as a development version and the version string is replaced with the development one, in this case main.
The env argument is an environment variable that overwrites the path, so a user can point the cache somewhere else, which matters on a shared machine or a read-only container. And the registry is a dictionary with all the files managed by this pooch, where the keys are the file names relative to the base URL and the values are their SHA256 hashes.
SciPy and scikit-image run on it
The list of projects using Pooch is the strongest argument for the library, and it is long enough to include the tools most scientific Python users already have installed.
SciPy is at the top of the list, followed by scikit-image and xarray, then Ensaio, which is from the same Fatiando a Terra family, and GemPy, MetPy, napari, Satpy, yt and PyVista. Further down sit icepack, histolab, seaborn-image, Open AR-Sandbox, climlab, mne-python, GemGIS, SHTOOLS, MOABB, GeoViews, ScopeSim, Brainrender, pyxem, cellfinder, PVGeo, geosnap, BioCypher, cf-xarray, Scirpy, rembg, DASCore, scikit-mobility, Py-ART, HyperSpy, RosettaSciIO, eXSpy, SPLASH, xclim, CLISOPS and scXpand.
Two observations. The list spans geoscience, neuroscience, astronomy, chemistry and image processing, so the library is not tied to one field's file formats or repository habits. And the readme asks users to send a pull request adding their project to the list, which means the list is maintained as evidence rather than as a marketing page.
The project also has a paper, with a DOI badge pointing at a Journal of Open Source Software entry, and a citation page in the documentation, which is the norm for a package that is used in published work.
The release history is unhurried: version 1.8.1 on 2024-02-20, 1.8.2 on 2024-06-06, and 1.9.0 on 2026-01-30.
Three dependencies, and extras for the awkward cases
The dependency list is short enough to state exactly.
The runtime requirements are platformdirs at 2.5.0 or newer, packaging at 20.0 or newer, and requests at 2.19.0 or newer. Platformdirs is what finds the cache folder on each operating system, packaging handles version parsing, and requests does the HTTP work. The FTP support, mentioned in the feature list, is not a separate dependency, which tells you it is implemented on top of what is already there.
The optional dependencies are where the real requirements live. The progress extra pulls in tqdm for download progress bars, capped below version 5. The sftp extra pulls in paramiko, which is the natural way to add SFTP to a downloader. The xxhash extra pulls in xxhash, which is the faster hash for the integrity check, and it is offered as an option rather than a requirement. The test extra pulls in pytest-httpserver and pytest-localftpserver, which are local servers used to test the HTTP and FTP downloaders without touching the network.
That last one is a small design statement. A download library that tests itself against local servers is a library that can be tested in a sandbox, in continuous integration without network access, and against a server that behaves in a specific way.
The manifest also marks the package as typed, with a typing classifier, and the supported Python versions run from 3.9 to 3.14 with a floor of 3.9, and the development status is production or stable.
The test suite runs against the installed package
The Makefile contains one decision that reveals how the maintainers think about their own package.
The test target creates a temporary directory, changes into it, and runs pytest there, with the comment that this is to make sure the tests are run on the installed version. It then copies the coverage data back and removes the directory. The pytest invocation includes coverage reporting with the missing lines shown, the doctest modules flag, and the verbose flag.
Running your own test suite from a different directory, against the package as installed rather than against the source tree, catches a class of bug that is otherwise invisible: the case where the package works from a checkout because an untracked file is present, and fails for every user who installs it.
The rest of the tooling is modern and layered. The format target runs ruff with the import sorting rules in fix mode, then ruff format, then burocrata, which is the Fatiando project's own tool for enforcing its comment and documentation conventions. The check target runs three things, a format check, a style check with ruff, and a type check with mypy over the package and the documentation.
The repository root shows the same care. There is a .coveragerc for the coverage configuration, a .codecov.yml for the coverage reporting, a .flake8 for the older lint configuration, an environment.yml for the conda environment, a CITATION.cff for citation metadata, a paper directory, an AUTHORS.md, and a Makefile with a generated help target that lists every command with a one-line description.
Editorial conclusion
pooch fits a scientific package that ships or fetches sample data and wants the download to happen automatically, on the first run, with a checksum to prove the file is the one you meant, because the library does that in a few lines and pulls in three dependencies. It is the wrong choice for a large data workflow, where a dedicated tool with parallel transfers, resumable downloads and scheduling belongs, since pooch is deliberately a single file at a time helper. It is also the wrong choice if you want to host your data somewhere exotic, since the downloaders and post-processors are designed to be extended rather than to be exhaustive. Before you adopt it, read the create parameters rather than only retrieve, because the version and version_dev arguments are what stop a user running your code from silently getting a different dataset than the one you tested.
Frequently asked questions
What is pooch?
It is a small pure Python library that manages data by downloading files from a server, only when needed, and storing them in a local cache folder. It supports HTTP, FTP, DOIs and data repositories such as Zenodo and figshare, and its post-processors can unzip and decompress what it downloads.
How does pooch know a file is correct?
You pass a known_hash to retrieve, and Pooch checks the hash of the downloaded file against that value to make sure it is the right file and not corrupted or outdated. A second run finds the file in the cache and does not download it again.
What is the difference between retrieve and create in pooch?
retrieve fetches a single file and returns its path. create builds a versioned registry for a package's sample data, taking a cache path, a base URL with a version placeholder, the version and a development version string, an environment variable that overrides the path, and a dictionary of file names and their SHA256 hashes.
What does pooch depend on?
Three runtime dependencies, platformdirs, packaging and requests, with optional extras for a tqdm progress bar, SFTP through paramiko, faster hashing through xxhash, and local HTTP and FTP servers for the test suite.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/fatiando-pooch)Was this useful?