dlb.fs
— Filesystem paths¶
This module provides classes to represent and access filesystem objects in a safe and platform-independent manner,
most prominently dlb.fs.Path
and its subclasses.
Path objects¶
-
class
dlb.fs.
Path
¶ A
dlb.fs.Path
represents the path of a filesystem object in a platform-independent manner and expresses whether the object is a directory or not. All operations on instances ofdlb.fs.Path
show the same behaviour on every platform (with the exception ofnative
). Its instances are immutable and hashable (they can be used in sets or as keys in dictionaries).All represented paths are either absolute or relative to the working directory of a process.
The interface is similar to
pathlib
and conversion from and topathlib
paths is supported.If the path represented by a
dlb.fs.Path
is meaningful as a concrete path on the platform the code is running on,native
returns it in the form of adlb.fs.Path.Native
instance, which can then be used to access the filesystem (like apathlib.Path
).On all platform the following properties hold:
'/'
is used as a path component separator.- A path does not contain
'\0'
. - A path is absolute if and only if it starts with
'/'
; it is relative if and only if it is not absolute. - A component
'..'
means the parent directory of the path before it. - A component
'.'
means the directory of the path before it; a non-empty path with all such components removed is equivalent to the original one. - A sequence of two or more consequent
'/'
is equivalent to a single'/'
, except at the beginning of the path. - At the beginning of the path:
- Three or more consequent
'/'
are equivalent to a single'/'
- Exactly two consequent
'/'
(followed be a character other than'/'
) means that the following component is to be interpreted in a implementation-defined manner (e.g. ISO 1003.1-2008 or UNC paths)
- Three or more consequent
- If the platform supports symbolic links, it resolves them as specified in ISO 1003.1-2008
(which means that
'..'
cannot be collapsed without knowing the filesystem’s content).
dlb.fs.Path
instances are comparable with each other by=
,<
etc. They are also comparable with strings andpathlib.PurePath
. Comparison is done case-sensitively and component-wise, observing the equivalence relations described below. A non-directory path is smaller than an otherwise identical directory path. If a directory path d is a prefix of another path p, then d < p. Any relative path is smaller than any absolute path.Usage example:
p = dlb.fs.PortablePath('a/b/c/') / 'x/y' p.relative_to(...) ... = str(p.native) with p.native.open() as f: f.readline()
The
dlb.fs.Path
class supports the following methods and attributes:-
Path
(path[, is_dir=None])¶ Constructs a path from another path or a string.
If path is a string, it is interpreted as the string representation of a path in Posix style with
/
as a component separator. It must not by empty. If path is apathlib.Path
, it must be either absolute or relative. If path is a sequence, all its members are converted to str and are interpreted as path components; its first component must be''
for a relative path.If is_dir is
None
, the ending of path determines whether is considered a directory path or not; it is if it ends with'/'
or a'.'
or'..'
component.If is_dir is
True
, the path is considered a directory path irrespective ofpath
.If is_dir is
False
, the path is considered a non-directory path irrespective ofpath
However, if path represents'.'
or endwith a'..'
component, aValueError
exception is raised.Parameters: - path (str |
Path
|pathlib.PurePath
) – portable string representation or path object - is_dir (NoneType | bool) –
True
if this is a directory path,False
if not andNone
for derivation from path
Raises: - TypeError – if path is neither a string nor a path
- ValueError – if path is an empty string
- ValueError – if path is a
pathlib.PurePath
which is neither absolute nor relative
Examples:
>>> p = Path('a/b/').is_dir() True >>> p = Path(pathlib.PureWindowsPath('C:\\Windows'), is_dir=True) >>> p Path('/C:/Windows/') >>> p.is_dir() True >>> p = Path('x/y/..', is_dir=False) Traceback (most recent call last): ... ValueError: cannot be the path of a non-directory: 'x/y/..' >>> Path('x/y/z.tar.gz')[:-2] Path('x/') >>> Path('x/y/z.tar.gz').parts[-1] 'z.tar.gz'
- path (str |
-
is_normalized
()¶ Returns: True
if and only if this represents a normalized path (i.e. it contains no'..'
components)Return type: bool
-
relative_to(other, collapsable=False):
Returns a version of this path relative to the directory path represented by other.
If collapsable is
False
, this path must be a prefix of other. If collapsable isTrue
, other is treated as a collapsable path and the minimum of necessary..
components is prepended.Return type: class of this object
Raises: - ValueError – if this is a non-directory path
- ValueError – if other is not a prefix of this
-
iterdir
(name_filter='', recurse_name_filter=None, follow_symlinks=True, cls=None)¶ Yields all path objects of the directory contents denoted by this path and matched by the name filters. The paths are duplicate-free and in a defined and repeatable order, but not necessarily sorted. Their class is the class of this object if cls is
None
and cls otherwise.The path of an existing filesystem object is eventually yielded if and only if
- its name matches the name filter name_filter and
- it is contained in a matched directory.
A directory is a matched directory if and only if it is the directory d denoted by this path or a direct subdirectory of a matched directory whose name matches the name filter recurse_name_filter. If follow_symlinks is
True
, a symbolic link to an existing directory is considered a direct subdirectory of the director containing the symbolic link. If follow_symlinks isFalse
or the target of the symbolic link does not exist, it is considered a non-directory.name_filter and recurse_name_filter are name filters. A name filter can be
None
— no name matches this filter- a callable c accepting exactly one argument — a name n matches this filter if and only if
bool(c(n))
isTrue
- a compiled regular expression r — a name n matches this filter if and only if
r.fullmatch(n))
is notNone
- a non-empty regular expression string
s
— a name n matches this filter if and only ifre.compile(s).fullmatch(n))
is notNone
- an empty string — every name matches this filter
Example:
for p in dlb.fs.Path('src/').iterdir(name_filter=r'(?i).+\.cpp', recurse_name_filter=lambda n: '.' not in n): ...
Return type: cls | class of this object
Raises: - TypeError – if cls is neither
None
nor a subclass ofdlb.fs.Path
- TypeError – if name_filter or recurse_name_filter are not both name filters
- ValueError – if this is a non-directory path
-
iterdir_r
(name_filter='', recurse_name_filter=None, follow_symlinks=True, cls=None)¶ Like
iterdir()
, but all returns paths are relative to this path.
-
list
(name_filter='', recurse_name_filter=None, follow_symlinks=True, cls=None)¶ Returns all paths yielded by
iterdir()
as a sorted list.Example:
>>> dlb.fs.NoSpacePath('src/').list(name_filter=r'(?i).+\.cpp') [NoSpacePath('src/Clock.cpp'), NoSpacePath('src/main.cpp')]
-
list_r
(name_filter='', recurse_name_filter=None, follow_symlinks=True, cls=None)¶ Returns all paths yielded by
iterdir_r()
as a sorted list.Example:
>>> dlb.fs.NoSpacePath('src/').list(name_filter=r'(?i).+\.cpp') [NoSpacePath('Clock.cpp'), NoSpacePath('main.cpp')]
-
__getitem__(key):
A subpath (a slice of the path).
The resulting path is absolute (with the same anchor) if and only if the slice starts at 0. The resulting path is a non-directory path if and only if it contains the last component and if this path is a non-directory path.
The slice step must be positive.
Examples:
>>> dlb.fs.Path('src/comp/lib/Core.cpp')[:-2] Path('src/comp/' >>> dlb.fs.Path('src/comp/..')[:-1] Path('src/comp/'
Parameters: Return type: class of this object
Returns: subpath
Raises: - TypeError – if key is not a slice
- ValueError – if this is an absolute path and key is an empty slice
-
parts
¶ A tuple giving access to the path’s various components:
>>> p = Path('/usr/bin/python3') >>> p.parts ('/', 'usr', 'bin', 'python3')
Return type: tuple(str)
-
native
¶ This path as a native path. Use it to access the filesystem:
p = Path('/usr/bin/') with open(p.native) as f: ...
This attribute cannot be written.
Return type: dlb.fs.Path.Native
Raises: ValueError – if this path is not representable as Path.Native
-
pure_posix
¶ This path as a
pathlib.PurePosixPath
:>>> p = Path('/usr/bin/') >>> p.pure_posix PurePosixPath('/usr/bin')
This attribute cannot be written.
Return type: pathlib.PurePosixPath
-
pure_windows
¶ This path as a
pathlib.PureWindowsPath
:>>> p = Path('/C:/Program Files/') >>> p.pure_windows PureWindowsPath('C:/Program Files')
This attribute cannot be written.
Return type: pathlib.PureWindowsPath
-
class
Path.
Native
¶ A native path whose instances can be used much like ones from
pathlib.Path
and is aos.PathLike
.For each subclass P of
dlb.fs.Path
there is a corresponding subclassP.Native
which imposes the same restrictions on its representable paths as P.If Q is a subclass of P and P is a subclass of
dlb.fs.Path
, thenQ.Native
is a subclass ofP.Native
.Example (on a Posix system):
>>> dlb.fs.NoSpacePath.Native('/tmp/x y') Traceback (most recent call last): ... ValueError: invalid path for 'NoSpacePath': '/tmp/x y' (must not contain space)
In contrast to
pathlib.Path
, conversion to string is done in a safe way: relative paths are guaranteed to start with'.'
.Example (on a Posix system):
>>> str(Path.Native('-rf')) './-rf'
Instances of
dlb.fs.Path.Native
and its subclasses should not be constructed directly, but by accessingdlb.fs.Path.native
.Example (on a Posix system):
with open(dlb.fs.NoSpacePath('/tmp/x/a').native) as f: ... = f.read()
-
raw
¶ This path as a
pathlib.Path
. Use it to access the filesystem in an object-oriented manner:p = Path('/usr/bin/') ... = p.native.raw.is_dir()
This attribute cannot be written.
Constructing a
pathlib.Path
is an expensive operation. For performance-critical tasks, usep.native
and functions for string-like paths instead: e.g.os.path.isdir(p.native)
instead ofp.native.raw.is_dir()
.
-
Restricting paths¶
By subclassing dlb.fs.Path
, additional restrictions to the set of value values can be imposed
(trying to construct a dlb.fs.Path
from an invalid value raises an ValueError
exception).
A subclass of dlb.fs.Path
should implement only check_restriction_to_base()
.
-
class
dlb.fs.
RelativePath
¶ A
dlb.fs.Path
which represents a relative path.
-
class
dlb.fs.
AbsolutePath
¶ A
dlb.fs.Path
which represents an absolute path.
-
class
dlb.fs.
NormalizedPath
¶ A
dlb.fs.Path
which represents a normalized path (without'..'
components).
-
class
dlb.fs.
NoSpacePath
¶ A
dlb.fs.Path
whose components do not contain' '
.
-
class
dlb.fs.
PosixPath
¶ A
dlb.fs.Path
which represents a POSIX-compliant (ISO 1003.1-2008) paths in its least-constricted form.Every non-empty string, which does not contain
'/'
or U+0000 (NUL) is a valid component. Components are separated by'/'
.For every path prefix (in the POSIX sense) {NAME_MAX} and {PATH_MAX} are considered unlimited.
Relevant parts of ISO 1003.1-2008:
- section 4.12 Pathname Resolution
- section 4.5 File Hierarchy
- section 4.6 Filenames
- section 4.7 Filename Portability
- section 3.267 Pathname
- section 3.269 Path Prefix
- limits.h
-
class
dlb.fs.
PortablePosixPath
¶ A
dlb.fs.PosixPath
which represents a POSIX-compliant (ISO 1003.1-2008) path in its strictest form. Any path whose support is not required by POSIX or is declared as non-portable is considered invalid.A component cannot be longer than 14 characters, which must all be members of the Portable Filename Character Set.
The length of the string representation of the path is limited to 255 characters.
No absolute path prefix other than
'/'
is allowed (because implementation-defined).
-
class
dlb.fs.
WindowsPath
¶ A
dlb.fs.Path
which represents a Microsoft Windows-compliant file or directory path in its least-constricted form, which is either relative or absolute and is not a reserved non-directory path (e.g.NUL
).It cannot represent incomplete paths which are neither absolute nor relative to the current working directory (e.g.
C:a\b
and\\name
). It cannot represent NTFS stream names, Win32 file namespaces or Win32 device namespaces.
-
class
dlb.fs.
PortableWindowsPath
¶ A
dlb.fs.WindowsPath
which represents a Microsoft Windows-compliant path in its strictest form.A component cannot end with
' '
or'.'
(except'.'
and'..'
) and cannot be longer than 255 characters. The path cannot not be longer than 259 characters.
-
class
dlb.fs.
PortablePath
¶