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; pftree.manual renders such a package’s own --man page (Manual, manual_print) with the same colouring as pftree’s.

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.1.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.1.0
File Size Uploaded
pftree-4.1.0.tar.gz 41.3 kB Details

Built distribution (wheel)

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

Total release size: 77.1 kB

Release files / pftree-4.1.0.tar.gz

Download URL pftree-4.1.0.tar.gz
Size 41.3 kB
Tags Source
SHA-256 checksum
How to use checksums
a981360c392f92f5a0be7f888a4bcdd07dd145b90bba26c4312b8ad0ea096578
BLAKE2b-256 checksum
How to use checksums
99981d749bbfe16cc662dd0bd9c4dc976dba1dd53afcfdfd99d574de765c69b1
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.1.0-py3-none-any.whl

Download URL pftree-4.1.0-py3-none-any.whl
Size 35.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c48dc87b476f30d5b89386cfb9b991f1bbda24341f4d8270e098b74feb3098e3
BLAKE2b-256 checksum
How to use checksums
e3050dbf7bbfe186820a879ac5986fab998c9811d474980e8e52d843904d5486
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

This release

4.1.0 This release

2 release files

4.0.0

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