Skip to main content

pftree

https://github.com/FNNDSC/pftree/actions/workflows/ci.yml/badge.svg https://img.shields.io/pypi/v/pftree.svg https://img.shields.io/badge/python-3.11%2B-blue.svg

A dictionary representation of a filesystem tree, with per-directory read / analyze / write processing.

Overview

pftree walks an input directory and records, for every directory that holds files, the names of those files. That mapping is the tree. On top of it the engine runs a three-stage sequence over every directory, read, analyze and write, mirroring the input layout under an output directory. Packages such as pfdo and pfdicom subclass the engine and override the three callbacks; on its own, pftree prints trees as JSON and reports disk usage per directory.

Installation

pip install pftree

Python 3.11 or newer. The only dependency is tqdm.

Command line

pftree --inputDir /data --stats
pftree --inputDir /data --du
pftree --inputDir /data --fileFilter 'glob:*.nii.gz,!tmp' --fileFilterLogic AND --json
pftree --inputDir /data --dirFilter 're:/anat$' --json
pftree --inputDir /data --outputDir /tmp/out --outputLeafDir 'preview-%s' --test 0

pftree --man prints the full manual, pftree --synopsis its first page, pftree --help argparse’s quick reference. --inputDir (required) and --outputDir name the two trees. --maxDepth bounds the walk (-1 for all levels). --relativeDir keys the tree by paths relative to the input directory. --followLinks follows symbolic links. --threads N runs the analyze stage in a pool of N workers. --json prints the whole result. --du prints exactly what du -k prints (cumulative kilobytes per directory, every directory, children before parents, the input directory last, hard links counted once), so pftree --du --inputDir /data | xdu works; --duf is the du -h form and --apparentSize the du --apparent-size count. --stats, --statsReverse and --jsonStats print pftree’s own per-directory report: file count and apparent size of the files each directory holds, after any filters. --test <seconds>[:<type>] runs the built-in callbacks, sleeping per directory and writing a file listing (type 0) or a file count (type 1) into each output directory.

Filters

--fileFilter and --dirFilter each take a comma-separated list of tokens. A token is one of:

nii

substring: the text contains nii

glob:*.nii.gz

shell glob over the whole text

re:^sub-\d+$

regular expression, searched anywhere in the text

!tmp

negation of any of the above forms

--fileFilterLogic and --dirFilterLogic combine a filter’s tokens with OR (any token, the default) or AND (every token).

A file filter tests each file’s name. A directory filter tests each directory’s path relative to --inputDir with / separators, so the input root’s own name never matches, and glob:*/anat or re:/anat$ anchor on a component. The two filters are always ANDed: a file is kept only when its directory passes too, and a directory that keeps no files leaves the tree.

Library

from pathlib import Path
from pftree import DirNode, Pftree, StageResult, TreeOptions

class Counter(Pftree):
    def inputAnalyze_callback(self, node: DirNode, read: StageResult) -> StageResult:
        return StageResult(status=True, files=read.files, payload={"count": len(read.files)})

    def outputSave_callback(self, node: DirNode, analyze: StageResult) -> StageResult:
        node.outputPath.mkdir(parents=True, exist_ok=True)
        (node.outputPath / "count.txt").write_text(f"{analyze.payload['count']}\n")
        return StageResult(status=True, files=["count.txt"])

engine = Counter(TreeOptions(inputDir=Path("/data"), outputDir=Path("/out"), threads=4))
engine.tree_construct(engine.tree_probe())
engine.tree_filter()
result = engine.tree_process(
    inputRead_callback=engine.inputRead_callback,
    inputAnalyze_callback=engine.inputAnalyze_callback,
    outputWrite_callback=engine.outputSave_callback,
)

Every option and result type lives in pftree.models. TreeOptions holds every option; TreeOptions.fromDict(vars(args)) builds it from an argparse Namespace and ignores keys it does not know, so a subclass with a larger argument set passes its namespace straight through. pftree.__main__ exposes parserCore_build() and parserSelf_build() as parent parsers, and the CLI_* and ARGS_SYNOPSIS_* manual texts, for packages that add their own input and output arguments and compose their own --man page.

Each callback receives a DirNode (path, relPath, sorted files, outputPath) and returns a StageResult (status, files, payload). Reads and writes run sequentially; analyses run in the thread pool when threads is positive. A directory whose analyze result has status False, or whose analyze callback raises, is dropped from the tree before the write stage; the exception is logged with its traceback. tree_process returns a ProcessResult with the per-directory results and file counts.

Changes in 4.0

  • pfmisc and pudb are no longer dependencies; logging goes through the standard logging module under the pftree logger.

  • --outputLeafDir is applied with ordinary % formatting; the template must contain %s.

  • The callback methods are inputRead_callback, inputAnalyze_callback and outputSave_callback, and they take and return typed objects rather than tuples and dicts.

  • --dirFilter matches the path relative to the input directory, not the absolute path.

  • Filter tokens accept glob:, re: and ! prefixes.

  • Files directly under the input directory are listed under the root key; earlier versions listed the root’s subdirectory names there instead.

  • --relativeDir no longer changes the process’s working directory.

  • The --3D and --syslog options are gone.

  • main(argv) honours argv; --version, --man and --synopsis exit 0.

  • Packaging is pyproject.toml only, published from CI on a v* tag.

Metadata

Release files for pftree 4.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pftree 4.0.0
File Size Uploaded
pftree-4.0.0.tar.gz 40.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pftree 4.0.0
File Interpreter ABI Platform
pftree-4.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 74.6 kB

Release files / pftree-4.0.0.tar.gz

Download URL pftree-4.0.0.tar.gz
Size 40.3 kB
Tags Source
SHA-256 checksum
How to use checksums
ea20e67c723c5a11d7039637fde2f16ff7fd8696c190b3b39ff556ef0a0ba0ac
BLAKE2b-256 checksum
How to use checksums
c8b174bec3c1ca63632b4e55baecbe91b18954909e03cb3d85bef297c3c7a9cb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.

Transparency log

Release files / pftree-4.0.0-py3-none-any.whl

Download URL pftree-4.0.0-py3-none-any.whl
Size 34.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
86dca9373b6085bde6607d05753ab83fbf23680162c79f14505be32f1dc4d9ea
BLAKE2b-256 checksum
How to use checksums
aa0eb961eb2e70bd01840f947b78d21c83a05a02d9c0e450fd6f837515e59124
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.

Transparency log

Release history Release notifications | RSS feed

4.1.1

2 release files

4.1.0

2 release files

This release

4.0.0 This release

2 release files

3.4.2

1 release file

3.4.0

1 release file

3.2.32

1 release file

3.2.30

1 release file

3.2.28

1 release file

3.2.26

1 release file

3.2.24

1 release file

3.2.22

1 release file

3.2.20

1 release file

3.2.18

1 release file

3.2.16

1 release file

3.2.14

1 release file

3.2.12

1 release file

3.2.10

1 release file

3.2.8

1 release file

3.2.6

1 release file

3.2.4

1 release file

3.2.2

1 release file

3.2.0

1 release file

3.0.0

1 release file

2.2.0

1 release file

2.1.2

1 release file

2.1.0

1 release file

2.0.4

1 release file

2.0.2

1 release file

2.0.0

1 release file

1.6.16

1 release file

1.6.14

1 release file

1.6.12

1 release file

1.6.10

1 release file

1.6.8

1 release file

1.6.6

1 release file

1.6.4

1 release file

1.6.2

1 release file

1.6.0

1 release file

1.4.30

1 release file

1.4.28

1 release file

1.4.26

1 release file

1.4.24

1 release file

1.4.22

1 release file

1.4.20

1 release file

1.4.18

1 release file

1.4.16

1 release file

1.4.14

1 release file

1.4.12

1 release file

1.4.10

1 release file

1.4.8

1 release file

1.4.6

1 release file

1.4.4

1 release file

1.4.2

1 release file

1.4.0

1 release file

1.2.2

1 release file

1.2.0

1 release file

1.1.12

1 release file

1.1.10

1 release file

1.1.8

1 release file

1.1.6

1 release file

1.1.4

1 release file

1.1.2

1 release file

1.1.0

1 release file

1.0.4

1 release file

1.0.2

1 release file

1.0.0

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page