+def remove_newlines(x: str) -> str:
+ """Trivial function to be used as a line_transformer in
+ :meth:`slurp_file` for no newlines in file contents"""
+ return x.replace('\n', '')
+
+
+def strip_whitespace(x: str) -> str:
+ """Trivial function to be used as a line_transformer in
+ :meth:`slurp_file` for no leading / trailing whitespace in
+ file contents"""
+ return x.strip()
+
+
+def remove_hash_comments(x: str) -> str:
+ """Trivial function to be used as a line_transformer in
+ :meth:`slurp_file` for no # comments in file contents"""
+ return re.sub(r'#.*$', '', x)
+
+
+def slurp_file(
+ filename: str,
+ *,
+ skip_blank_lines=False,
+ line_transformers: Optional[List[Callable[[str], str]]] = None,
+):
+ """Reads in a file's contents line-by-line to a memory buffer applying
+ each line transformation in turn.
+
+ Args:
+ filename: file to be read
+ skip_blank_lines: should reading skip blank lines?
+ line_transformers: little string->string transformations
+ """
+
+ ret = []
+ xforms = []
+ if line_transformers is not None:
+ for x in line_transformers:
+ xforms.append(x)
+ if not file_is_readable(filename):
+ raise Exception(f'{filename} can\'t be read.')
+ with open(filename) as rf:
+ for line in rf:
+ for transformation in xforms:
+ line = transformation(line)
+ if skip_blank_lines and line == '':
+ continue
+ ret.append(line)
+ return ret
+
+
+def remove(path: str) -> None:
+ """Deletes a file. Raises if path refers to a directory or a file
+ that doesn't exist.
+
+ Args:
+ path: the path of the file to delete
+
+ >>> import os
+ >>> filename = '/tmp/file_utils_test_file'
+ >>> os.system(f'touch {filename}')
+ 0
+ >>> does_file_exist(filename)
+ True
+ >>> remove(filename)
+ >>> does_file_exist(filename)
+ False
+ """
+ os.remove(path)
+
+
+def delete(path: str) -> None:
+ """This is a convenience for my dumb ass who can't remember os.remove
+ sometimes.
+ """
+ os.remove(path)
+
+
+def without_extension(path: str) -> str:
+ """Remove one (the last) extension from a file or path.
+
+ Args:
+ path: the path from which to remove an extension
+
+ Returns:
+ the path with one extension removed.
+
+ >>> without_extension('foobar.txt')
+ 'foobar'
+
+ >>> without_extension('/home/scott/frapp.py')
+ '/home/scott/frapp'
+
+ >>> f = 'a.b.c.tar.gz'
+ >>> while('.' in f):
+ ... f = without_extension(f)
+ ... print(f)
+ a.b.c.tar
+ a.b.c
+ a.b
+ a
+
+ >>> without_extension('foobar')
+ 'foobar'
+
+ """
+ return os.path.splitext(path)[0]
+
+
+def without_all_extensions(path: str) -> str:
+ """Removes all extensions from a path; handles multiple extensions
+ like foobar.tar.gz -> foobar.
+
+ Args:
+ path: the path from which to remove all extensions
+
+ Returns:
+ the path with all extensions removed.
+
+ >>> without_all_extensions('/home/scott/foobar.1.tar.gz')
+ '/home/scott/foobar'
+
+ """
+ while '.' in path:
+ path = without_extension(path)
+ return path
+
+
+def get_extension(path: str) -> str:
+ """Extract and return one (the last) extension from a file or path.
+
+ Args:
+ path: the path from which to extract an extension
+
+ Returns:
+ The last extension from the file path.
+
+ >>> get_extension('this_is_a_test.txt')
+ '.txt'
+
+ >>> get_extension('/home/scott/test.py')
+ '.py'
+
+ >>> get_extension('foobar')
+ ''
+
+ """
+ return os.path.splitext(path)[1]
+
+
+def get_all_extensions(path: str) -> List[str]:
+ """Return the extensions of a file or path in order.
+
+ Args:
+ path: the path from which to extract all extensions.
+
+ Returns:
+ a list containing each extension which may be empty.
+
+ >>> get_all_extensions('/home/scott/foo.tar.gz.1')
+ ['.tar', '.gz', '.1']