The pyinstaller specs gather plugin modules two different ways. The .py
files are shipped verbatim by collect_data_files(include_py_files=True),
while collect_submodules() supplies the hiddenimports that pyinstaller
actually analyses for dependencies. The first walks the filesystem, the
second walks pkgutil, and pkgutil skips a directory with no __init__.py.
volatility3/framework/plugins/renderers has been such a directory since
the arrow and parquet renderers moved into it, so parquet_renderer.py was
copied into the binary but never analysed, and the pyarrow it imports was
left out. The frozen build still advertised the arrow and parquet
renderers, because the framework finds them at runtime with os.walk, and
then died with an unhandled RuntimeError when either was selected.
Adding the __init__.py makes pkgutil descend into the directory, which is
all collect_submodules needs, and matches every other plugin subpackage.
Both specs use the same collect_submodules line, so neither needs editing.
populate_config prefixed "file://" onto the result of pathname2url, which
already returns a leading "///" on Windows. Three slashes plus two gives
file://///C:/..., an empty authority that urlopen reads as a UNC path, so
every URIRequirement failed there before the file was ever opened. That
covers --single-location, --yara-file, --yara-compiled-file, --strings-file,
--isf and volshell's --script.
pathlib's as_uri produces the same string as the current code on POSIX for
every supported Python version, and the correct one on Windows, including
for UNC paths. It also sidesteps the Python 3.14 rewrite of pathname2url,
which gives POSIX the same leading "///" that Windows always returned.
The two other places in the codebase that build file URLs,
URIRequirement.location_from_file and volshell's run_script, were already
correct; this was the only one assembling the scheme by hand.
Per review feedback, the small next_id() closure that combined a
'nonlocal node_counter' assignment with an f-string formatter is more
naturally expressed as itertools.count. The counter generator yields
the integer sequence starting at 1 and the call site formats it as
'n<index>' on the spot, so the behaviour is unchanged: per-render,
strictly-increasing, plugin-agnostic Mermaid node identifiers.
Bring the new MermaidRenderer in line with the repository's ruff
formatting rules (introduced in the develop merge that this branch
just absorbed): double-quoted strings, trailing comma after the last
mapping entry, four-space hanging indent for the visitor signature,
and an additional blank line between top-level classes.
Address review feedback that the renderer was tightly coupled to plugins
exposing PID/PPID columns: the previous implementation looked up "PID"
and "PPID" by name to build parent->child edges and raised a generic
exception otherwise, which prevented any non-pstree tree plugin from
being rendered as Mermaid.
The relationship is already encoded in the TreeGrid -- every TreeNode
carries its path_depth -- so the new render() walks the rows in
traversal order and tracks ancestry with a parent stack:
* descending one or more levels pushes the previously-emitted node
once per level (so a level skip still produces sane pops);
* ascending pops the corresponding number of levels;
* the stack top is always the parent of the next emitted node, or
empty for a root-level node.
Each node is given a stable per-render identifier (n1, n2, ...) instead
of being keyed by a column value such as PID, since PIDs are not unique
across a TreeGrid and may contain characters that are unsafe in Mermaid
node IDs.
A small label-escaping helper replaces the previous ad-hoc string
replacement of parentheses, and embedded newlines in cell renderings
are folded to <br> so each row stays a single Mermaid node.
The unused tree_indent_column placeholder (flagged by code scanning)
is dropped as part of the rewrite.
The debug log emitted when writing out --save-config previously logged the
literal string "{args.save_config}" instead of the resolved filename, in both
vol.py and volshell. Add the f-string prefix so the actual destination path
appears in the log.
Add a warning directive to the macOS tutorial noting that macOS analysis support is no longer actively maintained as of the Volatility 3 parity release.
The existing plugins remain available but may not receive future updates.
Links to the official announcement for details.