Installation and Setup
Supported Python versions
rms-pdsfile requires Python 3.11 or later.
Installing
For use as a library, install into the environment that will import it:
pip install rms-pdsfile
To have the command-line programs available system-wide without putting the package on any project’s dependency list, install it as an application instead:
pipx install rms-pdsfile
Either way the eleven console scripts land on PATH:
pdsarchives pdschecksums pdsdependency pdsindexshelf pdsinfoshelf pdslinkshelf
pds4archives pds4checksums pds4indexshelf pds4infoshelf pds4linkshelf
Three further programs ship as modules rather than as console scripts and are run with
python -m: crlf, re_validate and show_opus_products. Their chapters
give the full module path each one needs.
One program needs the dev extra
show_opus_products formats its output with tabulate, which is not a runtime
dependency of the package. Install the dev extra to run it:
pip install "rms-pdsfile[dev]"
Without it, every other program in this guide works and show_opus_products fails at
import.
Environment variables
Variable |
What it names |
|---|---|
|
The root of the PDS3 holdings tree. Its basename must be |
|
The root of the PDS4 holdings tree. Its basename must be |
|
Optional. The root of a duplicate log tree, used when |
The basenames are a requirement of the directory, not of the variable, and they are a
requirement rather than a habit. Every absolute path is turned into
the logical path the package works in by splitting it at the first /holdings/ or
/pds4-holdings/ component, so a root directory named anything else makes every path
under it unusable. Thirteen of the fourteen programs resolve holdings paths, and each of
them notices, in one of three ways:
the four checksum and info shelf programs print
Not a holdings subdirectory:and exit 1;the archive, link shelf and index shelf programs,
pdsdependencyandre_validate– eight in all – end in an unhandledValueErrortraceback, also with status 1;show_opus_products neither refuses nor crashes: it prints a
WARNING:line for the path and carries on to the next one, and the run exits 1.
crlf is the one that never resolves a holdings path at all, and a root’s name is nothing to it.
Only one of the fourteen programs reads the two holdings variables directly:
show_opus_products, which reads both, whichever kind of path it is
asked about, and fails with a KeyError if either is unset.
The other thirteen take their paths on the command line, and the twelve of them that
work in a holdings tree find their way around it by splitting the path at its
/holdings/ or /pds4-holdings/ component rather than by consulting a variable. A
relative path is resolved against the working directory first, so it is the resolved path
that has to sit under a root.
(Twelve, not thirteen: the thirteen that resolve holdings paths include
show_opus_products, which this paragraph’s thirteen do not, and this paragraph’s
thirteen include crlf, which resolves no holdings path – either subtraction leaves
twelve.) Every run in this guide was made with both variables set, and the
runs that resolve a path this way behave the same with them unset. Setting them is worth
doing in any case – it is what lets you write $PDS3_HOLDINGS_DIR/volumes/... rather
than typing the root each time, which is how every example in this guide is written.
One qualification, because “reads no environment variable” is easy to overstate: the library underneath these programs turns a logical path back into an absolute one by consulting, in order, a preloaded list of holdings directories, a cached one, and then the holdings environment variable. Several library operations reach it, among them resolving a link recorded in a link shelf. No example in this guide exercises that path, and no run recorded here needed the variable, but a command over data that does reach it may.
export PDS3_HOLDINGS_DIR=/path/to/holdings
export PDS4_HOLDINGS_DIR=/path/to/pds4-holdings
PDS_LOG_ROOT and --log are two ways of setting the same thing, and the flag wins:
a program takes --log if it is given, falls back to PDS_LOG_ROOT if it is not,
and writes no duplicate log tree if neither is set.
The Maintenance Tools: the Command Line They Share covers what a log root does.
The holdings tree layout
A PDS3 holdings tree, at its top level, looks like this. Every directory is optional in the sense that a tree holds the ones its data needs:
$PDS3_HOLDINGS_DIR/
volumes/ published PDS3 volumes
calibrated/ calibrated versions of them
diagrams/ diagram images
metadata/ index tables and other metadata
previews/ preview images
documents/ documentation, not archived or checksummed
archives-volumes/ one .tar.gz per volume
archives-calibrated/
archives-diagrams/
archives-metadata/
archives-previews/
checksums-volumes/ one *_md5.txt per volume
checksums-calibrated/
checksums-diagrams/
checksums-metadata/
checksums-previews/
checksums-archives-volumes/ one *_md5.txt per volume set of archives
checksums-archives-calibrated/
checksums-archives-diagrams/
checksums-archives-metadata/
checksums-archives-previews/
_infoshelf-volumes/ info shelves, one tree per category above
_infoshelf-calibrated/
_infoshelf-diagrams/
_infoshelf-metadata/
_infoshelf-previews/
_infoshelf-archives-volumes/
_infoshelf-archives-calibrated/
_infoshelf-archives-diagrams/
_infoshelf-archives-metadata/
_infoshelf-archives-previews/
_linkshelf-volumes/ link shelves
_linkshelf-calibrated/
_linkshelf-metadata/
_indexshelf-metadata/ index shelves, for metadata tables only
_volinfo/ one text file per volume set
A PDS4 tree uses the same category vocabulary – the volume types and the two prefixes
are one shared set – with bundles in place of volumes. What any given tree holds
is the subset its data needs:
$PDS4_HOLDINGS_DIR/
bundles/
metadata/
previews/
diagrams/
documents/
archives-bundles/
checksums-bundles/
_infoshelf-bundles/
_linkshelf-bundles/
_indexshelf-metadata/
Which of these a tree actually holds is up to its data. The three link shelf
directories in the PDS3 listing – _linkshelf-volumes/, _linkshelf-calibrated/
and _linkshelf-metadata/ – are the ones pdsdependency requires of
a volume, but nothing in pdslinkshelf restricts it to those three:
point it at a previews volume and it writes _linkshelf-previews/.
setup_new_holdings.sh, described in The Shell Scripts, creates the
empty PDS3 directories in one command.
The log tree
Twelve of the fourteen programs write log files: the ten of
The Maintenance Tools: the Command Line They Share, plus pdsdependency and
re_validate. Each writes one per target, in a directory that is not
inside the holdings tree, and the default place is a logs directory beside the
holdings root:
$PDS3_HOLDINGS_DIR/../logs/<program>/<category>/<unit set>/<log file>
Eight of the ten use exactly that shape. The two index shelf programs go one component
deeper, because their target is a table inside a unit rather than the unit; and
pdsdependency and re_validate go one shallower, dropping <category> so their
logs sit directly under a directory named for the volume set. Each of those four chapters
shows its own. crlf and show_opus_products write no
log files at all and report to the terminal only.
A log root, from --log or PDS_LOG_ROOT, adds a second copy of the same file
under that root, in the same shape. The Maintenance Tools: the Command Line They Share gives the file
names and the ERRORS.log and WARNINGS.log files that accompany them.
How to read the examples in this guide
Every block of output in this guide is what a real run printed, and every command that
could be run here was run. Five of the 56 command lines published were not run: the
three pip and pipx install lines and a repeat of one of them, which would have
replaced the very tree being documented, and the pdsdata-sync-volset.sh line in
The Shell Scripts, which needs macOS and two mounted drives. Each of those
five is quoted from a program’s own usage rather than from a run, and none of them has a
block of output beneath it.
Three kinds of substitution are made in what is published, and nothing else is changed:
the PDS3 and PDS4 holdings roots are written
$PDS3_HOLDINGS_DIRand$PDS4_HOLDINGS_DIR, and the directory containing a root – where the log tree sits – is written$PDS3_HOLDINGS_DIR/..or$PDS4_HOLDINGS_DIR/.., according to which root the program derived it from. The two roots shared one parent directory in these runs, so both forms name the same directory there and would name two in a tree whose roots sit apart;the directory the installed program was run from is dropped, so a console script appears by name even where the program echoes the absolute path it was invoked with, and the directory the package was imported from is written
<source root>, which is visible in the re_validate example because apython -mrun echoes the module’s own file path;where a run’s output is too long to show whole, the lines left out are replaced by a line reading
...and the surrounding prose says what was cut.
The runs were made against a copy of a holdings tree rather than a production one, since several of the tasks write into the tree. A timestamp, an elapsed time and an MD5 digest in an example are that run’s, and will differ in yours.