Source code for pyiron_base.jobs.job.extension.files
import os
from itertools import islice
from typing import Generator, List, Optional, Union
from pyiron_base.jobs.job.util import (
_working_directory_list_files,
_working_directory_read_file,
)
[docs]
class File:
__slots__ = ("_path",)
[docs]
def __init__(self, path: str):
self._path = path
def __str__(self) -> str:
return self._path
def _read(self, tail: Optional[int] = None) -> List[str]:
return _working_directory_read_file(
working_directory=os.path.dirname(str(self)),
file_name=os.path.basename(str(self)),
tail=tail,
)
def __iter__(self) -> Generator:
return iter(self._read())
[docs]
def abspath(self) -> str:
"""
Absolute path to file object
Returns:
str: absolute path
"""
return os.path.abspath(self._path)
[docs]
def list(self, lines: Optional[int] = None) -> List[str]:
"""
Return file content as list of lines.
Args:
lines (int): only return the first `lines` lines
Return:
list of str: file content
"""
return list(islice(iter(self), lines))
[docs]
def tail(self, lines: int = 100) -> None:
"""
Print the last `lines` to stdout.
Args:
lines (int): number of output lines
"""
print(*self._read(tail=lines), sep="")
def __eq__(self, other: Union[str, "File"]) -> bool:
return self.__str__().__eq__(other)
[docs]
class FileBrowser:
"""
Allows to browse the files in a job directory.
By default this object prints itself as a listing of the job directory and
the files inside.
>>> job.files
/path/to/my/job:
\tpyiron.log
\terror.out
Access to the names of files is provided with :meth:`.list`
>>> job.files.list()
['pyiron.log', 'error.out', 'INCAR']
Access to the contents of files is provided by indexing into this object,
which returns a list of lines in the file
>>> job.files['error.out']
["Oh no\n", "Something went wrong!\n"]
The :meth:`.tail` method prints the last lines of a file to stdout
>>> job.files.tail('error.out', lines=1)
Something went wrong!
For files that have valid python variable names can also be accessed by
attribute notation
>>> job.files.INCAR # doctest: +SKIP
File('INCAR')
"""
__slots__ = ("_working_directory",)
[docs]
def __init__(self, working_directory: str):
self._working_directory = os.path.abspath(os.path.expanduser(working_directory))
def _get_file_dict(self) -> dict:
return {
f.replace(".", "_"): f
for f in _working_directory_list_files(
working_directory=self._working_directory
)
}
def __dir__(self) -> List[str]:
return list(self._get_file_dict().keys()) + super().__dir__()
[docs]
def list(self) -> List[str]:
"""
List all files in the working directory of the job.
"""
return _working_directory_list_files(working_directory=self._working_directory)
def _ipython_display_(self) -> None:
path = self._job.working_directory + ":"
files = [
"\t" + str(f)
for f in _working_directory_list_files(
working_directory=self._working_directory
)
]
print(os.linesep.join([path, *files]))
[docs]
def tail(self, file: str, lines: int = 100) -> None:
"""
Print the last lines of a file.
Args:
file (str): filename
lines (int): number of lines to print
Raises:
FileNotFoundError: if the given file does not exist
"""
return self[file].tail(lines=lines)
def __getitem__(self, item: str) -> Union[File, "FileBrowser"]:
sub = os.path.join(self._working_directory, item)
if os.path.isdir(sub):
return FileBrowser(sub)
if item in _working_directory_list_files(
working_directory=self._working_directory,
include_archive=False,
):
return File(os.path.join(self._working_directory, item))
elif item in _working_directory_list_files(
working_directory=self._working_directory,
include_archive=True,
):
return File(os.path.join(self._working_directory, item))
else:
raise FileNotFoundError(item)
def __getattr__(self, item: str) -> Union[File, "FileBrowser"]:
if item.startswith("__") and item.endswith("__"):
raise AttributeError(item)
else:
try:
return self[self._get_file_dict()[item]]
except KeyError:
raise FileNotFoundError(item) from None