cardinal_pythonlib.fileops
Original code copyright (C) 2009-2022 Rudolf Cardinal (rudolf@pobox.com).
This file is part of cardinal_pythonlib.
Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
File operations.
- class cardinal_pythonlib.fileops.FileWatcher(filenames: List[str])[source]
Watch several files for changes.
Initialize with a list of filenames to watch.
- cardinal_pythonlib.fileops.chown_r(path: str, user: str, group: str) None[source]
Performs a recursive
chown.
- cardinal_pythonlib.fileops.concatenate(src: List[str], dest: str, filesep: str = '\n')[source]
Concatenate multiple text files into one.
- cardinal_pythonlib.fileops.copy_tree_contents(srcdir: str, destdir: str, destroy: bool = False) None[source]
Recursive copy. Unlike
copy_tree_root(),copy_tree_contents()works as follows. With the file structure:/source/thing/a.txt /source/thing/b.txt /source/thing/somedir/c.txt
the command
copy_tree_contents("/source/thing", "/dest")
ends up creating:
/dest/a.txt /dest/b.txt /dest/somedir/c.txt
- cardinal_pythonlib.fileops.copy_tree_root(src_dir: str, dest_parent: str) None[source]
Copies a directory
src_dirinto the directorydest_parent. That is, with a file structure like:/source/thing/a.txt /source/thing/b.txt /source/thing/somedir/c.txt
the command
copy_tree_root("/source/thing", "/dest")
ends up creating
/dest/thing/a.txt /dest/thing/b.txt /dest/thing/somedir/c.txt
- cardinal_pythonlib.fileops.copyglob(src: str, dest: str, allow_nothing: bool = False, allow_nonfiles: bool = False) None[source]
Copies files whose filenames match the glob src” into the directory “dest”. Raises an error if no files are copied, unless allow_nothing is True.
- Parameters:
- Raises:
ValueError – if no files are found and
allow_nothingis not set
- cardinal_pythonlib.fileops.delete_files_within_dir(directory: str, filenames: List[str]) None[source]
Delete files within
directorywhose filename exactly matches one offilenames.
- cardinal_pythonlib.fileops.exists_locked(filepath: str) Tuple[bool, bool][source]
Checks if a file is locked by opening it in append mode. (If no exception is thrown in that situation, then the file is not locked.)
- Parameters:
filepath¶ – file to check
- Returns:
(exists, locked)- Return type:
tuple
See https://www.calazan.com/how-to-check-if-a-file-is-locked-in-python/.
- cardinal_pythonlib.fileops.find(pattern: str, path: str) List[str][source]
Finds files in
pathwhose filenames matchpattern(viafnmatch.fnmatch()).
- cardinal_pythonlib.fileops.find_first(pattern: str, path: str) str[source]
Finds first file in
pathwhose filename matchespattern(viafnmatch.fnmatch()), or raisesIndexError.
- cardinal_pythonlib.fileops.gen_filenames(starting_filenames: List[str], recursive: bool) Generator[str, None, None][source]
From a starting list of files and/or directories, generates filenames of all files in the list, and (if
recursiveis set) all files within directories in the list.
- cardinal_pythonlib.fileops.get_directory_contents_size(directory: str = '.') int[source]
Returns the total size of all files within a directory.
See https://stackoverflow.com/questions/1392413/calculating-a-directorys-size-using-python.
- Parameters:
directory¶ – directory to check
- Returns:
size in bytes
- Return type:
int
- cardinal_pythonlib.fileops.mkdir_p(path: str) None[source]
Makes a directory, and any intermediate (parent) directories if required.
This is the UNIX
mkdir -p DIRECTORYcommand; of course, we useos.makedirs()instead, for portability.
- cardinal_pythonlib.fileops.moveglob(src: str, dest: str, allow_nothing: bool = False, allow_nonfiles: bool = False) None[source]
As for
copyglob(), but moves instead.
- cardinal_pythonlib.fileops.preserve_cwd(func: Callable) Callable[source]
Decorator to preserve the current working directory in calls to the decorated function.
Example:
@preserve_cwd def myfunc(): os.chdir("/faraway") os.chdir("/home") myfunc() assert os.getcwd() == "/home"
- cardinal_pythonlib.fileops.purge(path: str, pattern: str) None[source]
Deletes all files in
pathmatchingpattern(viafnmatch.fnmatch()).
- cardinal_pythonlib.fileops.pushd(directory: str) None[source]
Context manager: changes directory and preserves the original on exit.
Example:
with pushd(new_directory): # do things
- cardinal_pythonlib.fileops.relative_filename_within_dir(filename: str, directory: str) str[source]
Starting with a (typically absolute)
filename, returns the part of the filename that is relative to the directorydirectory. If the file is not within the directory, returns an empty string.
- cardinal_pythonlib.fileops.require_executable(executable: str) None[source]
If
executableis not found byshutil.which(), raiseFileNotFoundError.
- cardinal_pythonlib.fileops.rmglob(pattern: str) None[source]
Deletes all files whose filename matches the glob
pattern(viaglob.glob()).
- cardinal_pythonlib.fileops.shutil_rmtree_onerror(func: Callable[[str], None], path: str, exc_info: Tuple[Any | None, BaseException | None, TracebackType | None]) None[source]
Error handler for
shutil.rmtree.If the error is due to an access error (read only file) it attempts to add write permission and then retries.
If the error is for another reason it re-raises the error.
Usage:
shutil.rmtree(path, onerror=shutil_rmtree_onerror)See https://stackoverflow.com/questions/2656322/shutil-rmtree-fails-on-windows-with-access-is-denied
- cardinal_pythonlib.fileops.which_and_require(executable: str, fullpath: bool = False) str[source]
Ensures that
executableis on the path, and returns it (or its full path viashutil.which()).
- cardinal_pythonlib.fileops.which_with_envpath(executable: str, env: Dict[str, str]) str[source]
Performs a
shutil.which()command using the PATH from the specified environment.Reason: when you use
run([executable, ...], env)and thereforesubprocess.run([executable, ...], env=env), the PATH that’s searched forexecutableis the parent’s, not the new child’s – so you have to find the executable manually.