mvs: Because one mv is rarely enough
Motivation
Renaming a bunch of files and directories can be tedious, error-prone work. Command-line tools to perform such tasks are numerous. Perhaps the most classic example was the Perl rename script, which has been available or installable on most Unix-inspired operating systems since the early 1990s.
The core idea of rename was excellent. The user supplied a snippet of Perl
code as a command-line argument, followed by the original paths. Each original
path was pumped through the code snippet to generate the corresponding new
path. Because Perl was designed to make it easy to manipulate strings with very
little code, users could efficiently rename paths directly on the command line.
Even if you hardly knew Perl but at least understood how to operate its compact
regular-expression substitution syntax, you could become quite adept at bulk
path renaming.
$ rename 's/foo/bar/' *
Unfortunately, the script was a chainsaw – undeniably useful, but able to
inflict devastation after a single false move. As a result, I rarely used
rename directly for my bulk renaming needs, which were extensive on several
projects I worked on. Instead, I wrote my own Perl script to do the job. Its
operation was roughly the same, but it included precautions to help me avoid
disastrous mistakes. The most important were checking that the new paths did
not collide with existing paths on the file system and including an inspection
and confirmation step by default.
The mvs library is an updated and enhanced version of those ideas, but
implemented in a language I use regularly (Python) rather than one in which
I have become rusty (Perl).
The mvs executable
The primary use case envisioned for the library is its executable. In broad
terms, there are two ways to perform bulk renaming with the mvs command: (1)
the user provides original file paths and a snippet of Python code to perform
the original-to-new computation, or (2) the user provides both original paths
and new paths directly.
Either way, before any renaming occurs, mvs checks for common problems that
might occur in bulk renaming scenarios, provides an informative listing of the
proposed renamings grouping them into meaningful categories based on those
checks, and waits for user confirmation before attempting any renamings. In
addition, the script logs detailed information about the renamings to support
the user in the event that they later regret what they have done.
The script provides various command-line options to customize its behavior, supports user preferences, and provides detailed documentation on policy, process, listings, input path structures, user-supplied code, problem checking, configuration, logging, and caveats.
Installation and examples
Install the library in the usual way.
$ pip install mvs
Get usage help and detailed documentation.
$ mvs --help
$ mvs --details
A simple example:
$ mvs a b --rename 'return f"{o}.new"'
Programmatic usage
The mvs package also supports bulk renaming via a programmatic API. This can be
done by creating a RenamingPlan instance and then calling its
rename_paths() method. Initialization parameters and their defaults are as
follows.
from mvs import RenamingPlan
plan = RenamingPlan(
# Sequence of paths and their structure.
inputs,
structure = 'flat',
# User-supplied renaming and filtering code (str or callable).
# See mvs --details for additional information.
rename_code = None,
filter_code = None,
# Other parameters related to user-supplied code.
indent = 4,
seq_start = 1,
seq_step = 1,
# Additional rigor in the face of problems.
# See mvs --details.
skip = None,
strict = None,
)
plan.rename_paths()
If you do not want to rename paths immediately but do want to prepare everything for renaming, including performing the checks for problems, you can use the library in a more deliberative fashion: first prepare; then check the information provided by the plan; if desired, proceed with renaming; and in the event of unexpected failure, get information about which item led to the exception.
# The library's supported imports.
from mvs import RenamingPlan, MvsError, __version__
# Configure plan.
plan = RenamingPlan(...)
# Prepare for renaming.
plan.prepare()
# All relevant information about the plan and its renamings.
print(plan.as_dict)
# Whether preparation failed.
print(plan.failed)
# The renamings organized into four groups:
# - filtered out by user code;
# - excluded, due to unresolvable problems;
# - skipped, due to resolvable problems configured by user an ineligible;
# - active renamings.
print(plan.filtered)
print(plan.excluded)
print(plan.skipped)
print(plan.active)
# Try to rename.
try:
plan.rename_paths()
except Exception as e:
# The index of the active Renaming that was being handled
# when the exception occurred. Renamings before that index were
# renamed succesfully; renamings after it were not attempted.
i = plan.tracking_index
print(i)
# Two ways to see the offending renaming.
print(plan.tracking_rn)
print(plan.active[i])
# Renamings that were performed.
print(plan.active[:i])
# Renamings that were not attempted.
print(plan.active[i + 1:])
Metadata
Release files for mvs 2.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| mvs-2.0.0.tar.gz | 53.0 kB | Without provenance | Details for mvs-2.0.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| mvs-2.0.0-py3-none-any.whl | Python 3 | none | any | Details for mvs-2.0.0-py3-none-any.whl |
Total release size: 88.8 kB
Release files / mvs-2.0.0.tar.gz
| Download URL | mvs-2.0.0.tar.gz |
|---|---|
| Size | 53.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5545a471a8dd2df1bed8a5142f4b6aea0b2fdbccd7a9d5e07f98b9878962c0b2
|
|
BLAKE2b-256 checksum How to use checksums |
b9257f0cd9ac57c073d34accd42c2feed9fa3abb10f70b3986a91149afe9ea48
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.9.4
|
Release files / mvs-2.0.0-py3-none-any.whl
| Download URL | mvs-2.0.0-py3-none-any.whl |
|---|---|
| Size | 35.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ecc97fb769f96b35d7c3a0b787972e36a7849422dd90a804566ab729eec80dd8
|
|
BLAKE2b-256 checksum How to use checksums |
96ddbe8cbd1f14ebec6f8fafda93bd906d1a2780acf810effd48a9cc36d83e66
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.9.4
|
Security for mvs 2.0.0
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.