Assorted filesystem related utility functions, some of which have been bloating cs.fileutils for too long.
Project description
Assorted filesystem related utility functions, some of which have been bloating cs.fileutils for too long.
Latest release 20250728:
- remove_protecting: truncate the portion of the basename in the temp file prefix, can blow the filesystem limit.
- shortpath: cope if there is no pwd.getpwuid function (nonUNIX).
Short summary:
atomic_directory: Decorator for a function which fills in a directory which calls the function against a temporary directory then renames the temporary to the target name on completion.findup: Walk up the filesystem tree looking for a directory wherecriterion(fspath)is notNone, wherefspathstarts atdirpath. Return the result ofcriterion(fspath). ReturnNoneif no such path is found.fnmatchdir: Return a list of the names indirpathmatching the globfnglob.FSPathBasedSingleton: The basis for aSingletonMixinbased onrealpath(self.fspath).HasFSPath: A mixin for an object with a.fspathattribute representing a filesystem location.is_valid_rpath: Test thatrpathis a clean relative path with no funny business.longpath: Returnpathwith prefixes and environment variables substituted. The converse ofshortpath().needdir: Create the directorydirpathif missing. ReturnTrueif the directory was made,Falseotherwise.RemotePath: A representation of a remote filesystem path (local ifhostisNone).remove_protecting: Remove the file atrmpathwhile protectingsafepathfrom destruction.rpaths: A shim forscandirtreeto yield relative file paths from a directory.scandirpaths: A shim forscandirtreeto yield filesystem paths from a directory.scandirtree: Generator to recurse overdirpath, yielding(is_dir,subpath)for all selected subpaths.shortpath: Returnfspathwith the first matching leading prefix replaced.update_linkdir: Updatelinkdirpathwith symlinks topaths. Remove unused names iftrim. Return a mapping of names inlinkdirpathto absolute forms ofpaths.validate_rpath: Test thatrpathis a clean relative path with no funny business; raiseValueErrorif the test fails.
Module contents:
-
atomic_directory(*da, **dkw): Decorator for a function which fills in a directory which calls the function against a temporary directory then renames the temporary to the target name on completion.Parameters:
infill_func: the function to fill in the target directorymake_placeholder: optional flag, defaultFalse: if true an empty directory will be make at the target name and after completion it will be removed and the completed directory renamed to the target name
-
findup(dirpath: str, criterion: Union[str, Callable[[str], Any]]) -> str: Walk up the filesystem tree looking for a directory wherecriterion(fspath)is notNone, wherefspathstarts atdirpath. Return the result ofcriterion(fspath). ReturnNoneif no such path is found.Parameters:
dirpath: the starting directorycriterion: astror a callable accepting astr
If
criterionis astr, look for the existence ofos.path.join(fspath,criterion).Example:
# find a directory containing a `.envrc` file envrc_path = findup('.', '.envrc') # find a Tagger rules file for the Downloads directory rules_path = findup(expanduser('~/Downloads', '.taggerrc') -
fnmatchdir(dirpath, fnglob): Return a list of the names indirpathmatching the globfnglob. -
class FSPathBasedSingleton(cs.obj.SingletonMixin, HasFSPath, cs.deco.Promotable): The basis for aSingletonMixinbased onrealpath(self.fspath).
FSPathBasedSingleton.__init__(self, fspath: Optional[str] = None, lock=None):
Initialise the singleton:
On the first call:
- set
.fspathtoself._resolve_fspath(fspath) - set
._locktolock(orcs.threads.NRLock()if not specified)
FSPathBasedSingleton.fspath_normalised(fspath: str):
Return the normalised form of the filesystem path fspath,
used as the key for the singleton registry.
This default returns realpath(fspath).
As a contracting example, the cs.ebooks.kindle.classic.KindleTree
class tries to locate the directory containing the book
database, and returns its realpath, allowing some imprecision.
FSPathBasedSingleton.promote(obj):
Promote None or str to a CalibreTree.
-
class HasFSPath: A mixin for an object with a.fspathattribute representing a filesystem location.The
__init__method just sets the.fspathattribute, and need not be called if the main class takes care of that itself.
HasFSPath.__init__(self, fspath):
Save fspath as .fspath; often done by the parent class.
HasFSPath.fnmatch(self, fnglob):
Return a list of the names in self.fspath matching the
glob fnglob.
HasFSPath.listdir(self):
Return os.listdir(self.fspath).
HasFSPath.pathto(self, *subpaths):
The full path to subpaths, comprising a relative path
below self.fspath.
This is a shim for os.path.join which requires that all
the subpaths be relative paths.
HasFSPath.shortpath:
The short version of self.fspath.
-
is_valid_rpath(rpath, log=None) -> bool: Test thatrpathis a clean relative path with no funny business.This is a Boolean wrapper for
validate_rpath(). -
longpath(path, prefixes=None): Returnpathwith prefixes and environment variables substituted. The converse ofshortpath(). -
needdir(dirpath, mode=511, *, use_makedirs=False, log=None) -> bool: Create the directorydirpathif missing. ReturnTrueif the directory was made,Falseotherwise.Parameters:
dirpath: the required directory pathmode: the permissions mode, default0o777log: logmakedirsormkdircalluse_makedirs: optional creation mode, defaultFalse; if true, useos.makedirs, otherwiseos.mkdir
-
class RemotePath(RemotePath, HasFSPath, cs.deco.Promotable): A representation of a remote filesystem path (local ifhostisNone).This is useful for things like
rsynctargets.
RemotePath.__init__(self, host, fspath):
dummy init since namedtuple does not have one
RemotePath.__str__(self):
Return the string form of this path.
RemotePath.from_str(pathspec: <staticmethod(<function RemotePath.str at 0x104e25940>)>):
Produce a RemotePathfrompathspec, a path with an optional leading [user@]rhost:` prefix.
RemotePath.from_tuple(cls, host_fspath: tuple):
Produce a RemotePathfromhost_fspath, a (host,fspath)` 2-tuple.
RemotePath.str(host, fspath):
Return the string form of a remote path.
-
remove_protecting(rmpath, safepath): Remove the file atrmpathwhile protectingsafepathfrom destruction.This is for situations such as "merging" two equivalent files where the "source" file (
rmpath) is to be removed, leaving the destination file (safepath). It can be that these are the same file (not merely links to the same file, but the same link/name); this is surprisingly hard to detect, and removing the source will then destroy the destination.Instead of checking carefully and unreliably, we instead make a "safe" hard link of the destination, remove the source, then try to link the safe link back to the destination. If that succeeds, we have recovered from the destruction. If that fails with
FileExistsErrorthen the destruction did not occur. Both are good. Other exceptions are released with an accompanying note about the path to the "safe" link.Example use:
if srcpath != dstpath and same_content(srcpath, dstpath): remove_protecting(srcpath, dstpath) -
rpaths(dirpath='.', **scan_kw): A shim forscandirtreeto yield relative file paths from a directory.Parameters:
dirpath: optional top directory, default'.'
Other keyword arguments are passed to
scandirtree. -
scandirpaths(dirpath='.', **scan_kw): A shim forscandirtreeto yield filesystem paths from a directory.Parameters:
dirpath: optional top directory, default'.'
Other keyword arguments are passed to
scandirtree. -
scandirtree(dirpath='.', *, include_dirs=False, name_selector=None, only_suffixes=None, skip_suffixes=None, sort_names=False, follow_symlinks=False, recurse=True): Generator to recurse overdirpath, yielding(is_dir,subpath)for all selected subpaths.Parameters:
dirpath: the directory to scan, default'.'include_dirs: if true yield directories; defaultFalsename_selector: optional callable to select particular names; the default is to select names not starting with a dot ('.')only_suffixes: if supplied, skip entries whose extension is not inonly_suffixesskip_suffixes: if supplied, skip entries whose extension is inskip_suffixessort_names: option flag, defaultFalse; yield entires in lexical order if truefollow_symlinks: optional flag, defaultFalse; passed toscandirrecurse: optional flag, defaultTrue; if true, recurse into subdrectories
-
shortpath(fspath, prefixes=None, *, collapseuser=False, foldsymlinks=False): Returnfspathwith the first matching leading prefix replaced.Parameters:
prefixes: optional list of(prefix,subst)pairscollapseuser: optional flag to enable detection of user home directory paths; defaultFalsefoldsymlinks: optional flag to enable detection of convenience symlinks which point deeper into the path; defaultFalse
The
prefixesis an optional iterable of(prefix,subst)to consider for replacement. Eachprefixis subject to environment variable substitution before consideration. The defaultprefixesis fromSHORTPATH_PREFIXES_DEFAULT:(('$HOME/', '~/'),). -
update_linkdir(linkdirpath: str, paths: Iterable[str], trim=False): Updatelinkdirpathwith symlinks topaths. Remove unused names iftrim. Return a mapping of names inlinkdirpathto absolute forms ofpaths.My example use is maintaining a small directory of wallpapers to shuffle, selected from a reference image tree.
-
validate_rpath(rpath: str): Test thatrpathis a clean relative path with no funny business; raiseValueErrorif the test fails.Tests:
- not empty or '.' or '..'
- not an absolute path
- normalised
- does not walk up out of its parent directory
Examples:
>>> validate_rpath('') False >>> validate_rpath('.')
Release Log
Release 20250728:
- remove_protecting: truncate the portion of the basename in the temp file prefix, can blow the filesystem limit.
- shortpath: cope if there is no pwd.getpwuid function (nonUNIX).
Release 20250528: New remove_protecting(rmpath,safepath): remove rmpath while protecting safepath from destruction.
Release 20250414:
- HasFSPath: provide an lt method which compares the .fspath attributes to facilitate sorting.
- New RemotePath(host,fspath) namedtuple subclass for [host:]fspath path specifications.
Release 20250325: New update_linkdir() imported from my wpr script.
Release 20241122:
- FSPathBasedSingleton: add a .promote method to promote a filesystem path to an instance.
- FSPathBasedSingleton: new fspath_normalised(fspath) class method to produce a normalised form of the fspath for use as the key to the singleton registry.
Release 20241007: FSPathBasedSingleton.init: use an NRLock for the default lock, using a late import with fallback to Lock.
Release 20241005: needdir: now returns True if the directory was made, False if it already existed.
Release 20240630: FSPathBasedSingleton: recent Pythons seem to check that init returns None, subclasses must test another way.
Release 20240623:
- shortpath(foldsymlinks=True): only examine symlinks which have clean subpaths in their link text - this avoids junk and also avoids stat()ing links which might be symlinks to mount points which might be offline.
- scandirtree: clean up the logic, possibly fix repeated mention of directories.
Release 20240522: shortpath: new collapseuser=False, foldsymlinks=False parameters, rename DEFAULT_SHORTEN_PREFIXES to SHORTPATH_PREFIXES_DEFAULT.
Release 20240422: New scandirtree scandir based version of os.walk, yielding (is_dir,fspath). New shim scandirpaths.
Release 20240412: HasFSPath: explain that the init is optional in the docstring.
Release 20240316: Fixed release upload artifacts.
Release 20240201:
- FSPathBasedSingleton: drop the default_factory parameter/attribute, let default_attr specify a callable.
- Singleton._resolve_fspath: fix reference to class name.
Release 20231129:
- HasFSPath: new listdir method.
- HasFSPath.pathto: accept multiple relative subpaths.
- FSPathBasedSingleton: accept cls.FSPATH_FACTORY as a factory function for the default fspath, makes it possible to defer the path lookup.
- Replace is_clean_subpath with validate_rpath/is_valid_rpath pair.
Release 20230806:
- Reimplement fnmatchdir using fnmatch.filter.
- No longer claim Python 2 compatibility.
Release 20230401: HasFSPath.shortpath: hand call before .fspath set.
Release 20221221: Replace use of cs.env.envsub with os.path.expandvars and drop unused environ parameter.
Release 20220918:
- FSPathBasedSingleton.init: return True on the first call, False on subsequent calls.
- FSPathBasedSingleton.init: probe dict for '_lock' instead of using hasattr (which plays poorly this early on with classes with their own getattr).
- needdir: accept optional
logparameter to log mkdir or makedirs. - HasFSPath: add a default str.
Release 20220805: Doc update.
Release 20220530:
FSPathBasedSingleton._resolve_fspath: new envvar and default_attr parameters.
Release 20220429:
- New HasFSPath and FSPathBasedSingleton.
- Add longpath and shortpath from cs.fileutils.
- New is_clean_subpath(subpath).
- New needdir(path).
- New fnmatchdir(dirpath,fnglob) pulled out from HasFSPath.fnmatch(fnglob).
Release 20220327: New module cs.fs to contain more filesystem focussed functions than cs.fileutils, which is feeling a bit bloated.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cs_fs-20250728.tar.gz.
File metadata
- Download URL: cs_fs-20250728.tar.gz
- Upload date:
- Size: 13.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1c10638f154a89ec8188701e556290bb43a996eb7e59457771b2f996f6e3b052
|
|
| MD5 |
63e4ced8f99fe80a5863e62735e46d46
|
|
| BLAKE2b-256 |
bd9668e006cd1567af3b95ee2d12a5bc123fd2bc1c68dd89f7bac093c1628c2d
|
File details
Details for the file cs_fs-20250728-py3-none-any.whl.
File metadata
- Download URL: cs_fs-20250728-py3-none-any.whl
- Upload date:
- Size: 13.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9cd08e6e7d231064b07c47a487953a21618c24736fc7f13ee4e4f73bd9dbf66c
|
|
| MD5 |
9971f1ce2e16a08e6720a776c201196d
|
|
| BLAKE2b-256 |
e15a09ef8392c78a93c93127c4938c6564cad707dcc9526e8e220c5cfaf15541
|