nobodd.path
Defines the FatPath class, a Path-like class for interacting with
directories and sub-directories in a FatFileSystem
instance. You should never need to construct this class directly; instead it
should be derived from the root attribute
which is itself a FatPath instance.
>>> from nobodd.disk import DiskImage
>>> from nobodd.fs import FatFileSystem
>>> img = DiskImage('test.img')
>>> fs = FatFileSystem(img.partitions[1].data)
>>> for p in fs.root.iterdir():
... print(repr(p))
...
FatPath(<FatFileSystem label='TEST' fat_type='fat16'>, '/foo')
FatPath(<FatFileSystem label='TEST' fat_type='fat16'>, '/bar.txt')
FatPath(<FatFileSystem label='TEST' fat_type='fat16'>, '/setup.cfg')
FatPath(<FatFileSystem label='TEST' fat_type='fat16'>, '/baz')
FatPath(<FatFileSystem label='TEST' fat_type='fat16'>, '/adir')
FatPath(<FatFileSystem label='TEST' fat_type='fat16'>, '/BDIR')
FatPath
- class nobodd.path.FatPath(fs, *pathsegments)[source]
A
Path-like object representing a filepath within an associatedFatFileSystem.There is rarely a need to construct this class directly. Instead, instances should be obtained via the
rootproperty of aFatFileSystem. If constructed directly, fs is aFatFileSysteminstance, and pathsegments is the sequence of strings to be joined with a path separator into the path.Instances provide almost all the facilities of the
pathlib.Pathclass they are modeled after, including the crucialopen()method,iterdir(),glob(), andrglob()for enumerating directories,stat(),is_dir(), andis_file()for querying information about files, division for construction of new paths, and all the usualname,parent,stem, andsuffixattributes. When theFatFileSystemis writable, thenunlink(),touch(),mkdir(),rmdir(), andrename()may also be used.Instances are also comparable for the purposes of sorting, but only within the same
FatFileSysteminstance (comparisons across file-system instances raiseTypeError).- exists()[source]
Whether the path points to an existing file or directory:
>>> fs <FatFileSystem label='TEST' fat_type='fat16'> >>> (fs.root / 'foo').exists() True >>> (fs.root / 'fooo').exists() False
- glob(pattern)[source]
Glob the given relative pattern in the directory represented by this path, yielding matching files (of any kind):
>>> fs <FatFileSystem label='TEST' fat_type='fat16'> >>> sorted((fs.root / 'nobodd').glob('*.py')) [FatPath(<FatFileSystem label='TEST' fat_type='fat16'>, '/nobodd/__init__.py'), FatPath(<FatFileSystem label='TEST' fat_type='fat16'>, '/nobodd/disk.py'), FatPath(<FatFileSystem label='TEST' fat_type='fat16'>, '/nobodd/fat.py'), FatPath(<FatFileSystem label='TEST' fat_type='fat16'>, '/nobodd/fs.py'), FatPath(<FatFileSystem label='TEST' fat_type='fat16'>, '/nobodd/gpt.py'), FatPath(<FatFileSystem label='TEST' fat_type='fat16'>, '/nobodd/main.py'), FatPath(<FatFileSystem label='TEST' fat_type='fat16'>, '/nobodd/mbr.py'), FatPath(<FatFileSystem label='TEST' fat_type='fat16'>, '/nobodd/tftp.py'), FatPath(<FatFileSystem label='TEST' fat_type='fat16'>, '/nobodd/tools.py')]
Patterns are the same as for
fnmatch(), with the addition of “**” which means “this directory and all subdirectories, recursively”. In other words, it enables recurisve globbing.Warning
Using the “
**” pattern in large directory trees may consume an inordinate amount of time.
- is_absolute()[source]
Return whether the path is absolute or not. A path is considered absolute if it has a “/” prefix.
- is_dir()[source]
Return a
boolindicating whether the path points to a directory.Falseis also returned if the path doesn’t exist.
- is_file()[source]
Returns a
boolindicating whether the path points to a regular file.Falseis also returned if the path doesn’t exist.
- is_mount()[source]
Returns a
boolindicating whether the path is a mount point. In this implementation, this is onlyTruefor the root path.
- iterdir()[source]
When the path points to a directory, yield path objects of the directory contents:
>>> fs <FatFileSystem label='TEST' fat_type='fat16'> >>> for child in fs.root.iterdir(): child ... FatPath(<FatFileSystem label='TEST' fat_type='fat16'>, '/foo') FatPath(<FatFileSystem label='TEST' fat_type='fat16'>, '/bar.txt') FatPath(<FatFileSystem label='TEST' fat_type='fat16'>, '/setup.cfg') FatPath(<FatFileSystem label='TEST' fat_type='fat16'>, '/baz') FatPath(<FatFileSystem label='TEST' fat_type='fat16'>, '/adir') FatPath(<FatFileSystem label='TEST' fat_type='fat16'>, '/BDIR')
The children are yielded in arbitrary order (the order they are found in the file-system), and the special entries
'.'and'..'are not included.
- joinpath(*other)[source]
Calling this method is equivalent to combining the path with each of the other arguments in turn:
>>> fs <FatFileSystem label='TEST' fat_type='fat16'> >>> fs.root FatPath(<FatFileSystem label='TEST' fat_type='fat16'>, '/') >>> fs.root.joinpath('nobodd') FatPath(<FatFileSystem label='TEST' fat_type='fat16'>, '/nobodd') >>> fs.root.joinpath('nobodd', 'main.py') FatPath(<FatFileSystem label='TEST' fat_type='fat16'>, '/nobodd/main.py')
- match(pattern)[source]
Match this path against the provided glob-style pattern. Returns a
boolindicating if the match is successful.If pattern is relative, the path may be either relative or absolute, and matching is done from the right:
>>> fs <FatFileSystem label='TEST' fat_type='fat16'> >>> f = fs / 'nobodd' / 'mbr.py' >>> f FatPath(<FatFileSystem label='TEST' fat_type='fat16'>, '/nobodd/mbr.py') >>> f.match('*.py') True >>> f.match('nobodd/*.py') True >>> f.match('/*.py') False
As FAT file-systems are case-insensitive, all matches are likewise case-insensitive.
- mkdir(mode=511, parents=False, exist_ok=False)[source]
Create a new directory at this given path. The mode parameter exists only for compatibility with
pathlib.Pathand is otherwise ignored. If the path already exists,FileExistsErroris raised.If parents is true, any missing parents of this path are created as needed.
If parents is false (the default), a missing parent raises
FileNotFoundError.If exist_ok is false (the default),
FileExistsErroris raised if the target directory already exists.If exist_ok is true,
FileExistsErrorexceptions will be ignored (same behavior as the POSIXmkdir -pcommand), but only if the last path component is not an existing non-directory file.
- open(mode='r', buffering=-1, encoding=None, errors=None, newline=None)[source]
Open the file pointed to by the path, like the built-in
open()function does. The mode, buffering, encoding, errors and newline options are as for theopen()function. If successful, aFatFileinstance is returned.
- read_bytes()[source]
Return the binary contents of the pointed-to file as a bytes object:
>>> fs <FatFileSystem label='TEST' fat_type='fat16'> >>> (fs.root / 'foo').read_text() b'foo\n'
- read_text(encoding=None, errors=None)[source]
Return the decoded contents of the pointed-to file as a string:
>>> fs <FatFileSystem label='TEST' fat_type='fat16'> >>> (fs.root / 'foo').read_text() 'foo\n'
- relative_to(*other)[source]
Compute a version of this path relative to the path represented by other. If it’s impossible,
ValueErroris raised.
- rename(target)[source]
Rename this file or directory to the given target, and return a new
FatPathinstance pointing to target. If target exists and is a file, it will be replaced silently. target can be either a string or another path object:>>> p = fs.root / 'foo' >>> p.open('w').write('some text') 9 >>> target = fs.root / 'bar' >>> p.rename(target) FatPath(<FatFileSystem label='TEST' fat_type='fat16'>, '/bar') >>> target.read_text() 'some text'
The target path must be absolute. There are no guarantees of atomic behaviour (in contrast to
os.rename()).Note
pathlib.Path.rename()permits relative paths, but interprets them relative to the working directory which is a conceptFatPathdoes not support.
- resolve(strict=False)[source]
Make the path absolute, resolving any symlinks. A new
FatPathobject is returned.".."components are also eliminated (this is the only method to do so). If the path doesn’t exist and strict isTrue,FileNotFoundErroris raised. If strict isFalse, the path is resolved as far as possible and any remainder is appended without checking whether it exists.Note that as there is no concept of the “current” directory within
FatFileSystem, relative paths cannot be resolved by this function, only absolute.
- rglob(pattern)[source]
This is like calling
glob()with a prefix of “**/” to the specified pattern.
- stat(*, follow_symlinks=True)[source]
Return a
os.stat_resultobject containing information about this path:>>> fs <FatFileSystem label='TEST' fat_type='fat16'> >>> p = (fs.root / 'nobodd' / 'main.py') >>> p.stat().st_size 388 >>> p.stat().st_ctime 1696606672.02
Note
In a FAT file-system,
atimehas day resolution,mtimehas 2-second resolution, andctimehas either 2-second or millisecond resolution depending on the driver that created it. Directories have no timestamp information.The follow_symlinks parameter is included purely for compatibility with
pathlib.Path.stat(); it is ignored as symlinks are not supported.
- touch(mode=438, exist_ok=True)[source]
Create a file at this given path. The mode parameter is only present for compatibility with
pathlib.Pathand is otherwise ignored. If the file already exists, the function succeeds if exist_ok isTrue(and its modification time is updated to the current time), otherwiseFileExistsErroris raised.
- unlink(missing_ok=False)[source]
Remove this file. If the path points to a directory, use
rmdir()instead.If missing_ok is
False(the default),FileNotFoundErroris raised if the path does not exist. If missing_ok isTrue,FileNotFoundErrorexceptions will be ignored (same behaviour as the POSIXrm -fcommand).
- with_name(name)[source]
Return a new path with the
namechanged. If the original path doesn’t have a name,ValueErroris raised.
- with_stem(stem)[source]
Return a new path with the
stemchanged. If the original path doesn’t have a name,ValueErroris raised.
- with_suffix(suffix)[source]
Return a new path with the
suffixchanged. If the original path doesn’t have a suffix, the new suffix is appended instead. If the suffix is an empty string, the original suffix is removed.
- write_bytes(data)[source]
Open the file pointed to in bytes mode, write data to it, and close the file:
>>> p = fs.root / 'my_binary_file' >>> p.write_bytes(b'Binary file contents') 20 >>> p.read_bytes() b'Binary file contents'
An existing file of the same name is overwritten.
- write_text(data, encoding=None, errors=None, newline=None)[source]
Open the file pointed to in text mode, write data to it, and close the file:
>>> p = fs.root / 'my_text_file' >>> p.write_text('Text file contents') 18 >>> p.read_text() 'Text file contents'
An existing file of the same name is overwritten. The optional parameters have the same meaning as in
open().
- property anchor
Returns the concatenation of the drive and root. This is always “/”.
- property fs
Returns the
FatFileSysteminstance that this instance was constructed with.
- property name
A string representing the final path component, excluding the root:
>>> fs <FatFileSystem label='TEST' fat_type='fat16'> >>> p = (fs.root / 'nobodd' / 'main.py') >>> p.name 'main.py'
- property parent
The logical parent of the path:
>>> fs <FatFileSystem label='TEST' fat_type='fat16'> >>> p = (fs.root / 'nobodd' / 'main.py') >>> p.parent FatPath(<FatFileSystem label='TEST' fat_type='fat16'>, '/nobodd')
You cannot go past an anchor:
>>> p = (fs.root / 'nobodd' / 'main.py') >>> p.parent.parent.parent FatPath(<FatFileSystem label='TEST' fat_type='fat16'>, '/')
- property parents
An immutable sequence providing access to the logical ancestors of the path:
>>> fs <FatFileSystem label='TEST' fat_type='fat16'> >>> p = (fs.root / 'nobodd' / 'main.py') >>> p.parents (FatPath(<FatFileSystem label='TEST' fat_type='fat16'>, '/nobodd'), FatPath(<FatFileSystem label='TEST' fat_type='fat16'>, '/'))
- property parts
A tuple giving access to the path’s various components:
>>> fs <FatFileSystem label='TEST' fat_type='fat16'> >>> p = (fs.root / 'nobodd' / 'main.py') >>> p.parts ['/', 'nobodd', 'main.py']
- property root
Returns a string representing the root. This is always “/”.
- property stem
The final path component, without its suffix:
>>> fs <FatFileSystem label='TEST' fat_type='fat16'> >>> p = (fs.root / 'nobodd' / 'main.py') >>> p.stem 'main'
- property suffix
The file extension of the final component, if any:
>>> fs <FatFileSystem label='TEST' fat_type='fat16'> >>> p = (fs.root / 'nobodd' / 'main.py') >>> p.suffix '.py'
- property suffixes
A list of the path’s file extensions:
>>> fs <FatFileSystem label='TEST' fat_type='fat16'> >>> p = (fs.root / 'nobodd.tar.gz') >>> p.suffixes ['.tar', '.gz']
Support functions
- nobodd.path.get_cluster(entry, fat_type)[source]
Given entry, a
DirectoryEntry, and the fat_type indicating the size of FAT clusters, return the first cluster of the file associated with the directory entry.