Skip to content

Files

A File object is rarely used directly by end users, but it is a common base class for Input and Data structures that may contain files. The File object enables transparent serialization of binary file data for serialization to .json, .yaml, or .toml which makes saving data structures to disk in a human-readable format or sending them over HTTP seamless even when they contain binary data.

qcdata.Files

File model for handling string and binary data.

Binary data is encoded as base64 strings during serialization.

Attributes:

Name Type Description
files dict[str, str | bytes]

A dict mapping filename to str or bytes data.

add_file

add_file(
    filepath: Path | str, relative_dir: Path | None = None
) -> None

Add a file to the object.

The file is added to the files attribute with the filename as the key and the file data as the value. UTF-8 decodable files are stored as str; all other files are stored as bytes.

Parameters:

Name Type Description Default
filepath Path | str

The path to the file.

required
relative_dir Path | None

The directory to make the file relative to. Helpful when adding files from a subdirectory.

None
Example
    my_obj.add_file("path/to/file.txt")
    print(my_obj.files)
    # Output: {"file.txt": "file data"}
Source code in src/qcdata/models/base_models.py
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
def add_file(self, filepath: Path | str, relative_dir: Path | None = None) -> None:
    """Add a file to the object.

    The file is added to the `files` attribute with the filename as the key and
    the file data as the value. UTF-8 decodable files are stored as `str`; all
    other files are stored as `bytes`.

    Args:
        filepath: The path to the file.
        relative_dir: The directory to make the file relative to. Helpful when
            adding files from a subdirectory.

    Example:
        ```python
            my_obj.add_file("path/to/file.txt")
            print(my_obj.files)
            # Output: {"file.txt": "file data"}
        ```
    """
    filepath = Path(filepath)
    raw_bytes = filepath.read_bytes()
    try:
        data: str | bytes = raw_bytes.decode("utf-8")  # str
    except UnicodeDecodeError:
        data = raw_bytes  # bytes

    # Set filename relative to relative_dir
    if relative_dir:
        filename = str(filepath.relative_to(relative_dir))
    else:
        filename = filepath.name

    self.files[filename] = data
    # Add files to __pydantic_fields_set__ to ensure they are included in .save()
    self.__pydantic_fields_set__.add("files")

add_files

add_files(
    directory: StrOrPath,
    recursive: bool = False,
    exclude: list[str] | None = None,
) -> None

Add all files in a directory to the object.

Parameters:

Name Type Description Default
directory StrOrPath

The directory to add files from.

required
recursive bool

Whether to recursively add files from subdirectories.

False
exclude list[str] | None

A list of filenames to exclude from the directory.

None
Source code in src/qcdata/models/base_models.py
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
def add_files(
    self,
    directory: StrOrPath,
    recursive: bool = False,
    exclude: list[str] | None = None,
) -> None:
    """Add all files in a directory to the object.

    Args:
        directory: The directory to add files from.
        recursive: Whether to recursively add files from subdirectories.
        exclude: A list of filenames to exclude from the directory.
    """
    directory = Path(directory)
    if exclude is None:
        exclude = []
    if recursive:
        files = directory.rglob("*")
    else:
        files = directory.glob("*")
    for filepath in files:
        if filepath.is_file() and filepath.name not in exclude:
            self.add_file(filepath, directory)

save_files

save_files(directory: StrOrPath = Path('.')) -> None

Write all files to the specified directory.

Text data is written in text mode and binary data in binary mode. Parent directories are created for filenames that contain relative paths.

Parameters:

Name Type Description Default
directory StrOrPath

The directory to write the files to. Created if it does not exist (its parent must already exist). Defaults to the current working directory.

Path('.')
Source code in src/qcdata/models/base_models.py
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
def save_files(self, directory: StrOrPath = Path(".")) -> None:
    """Write all files to the specified directory.

    Text data is written in text mode and binary data in binary mode. Parent
    directories are created for filenames that contain relative paths.

    Args:
        directory: The directory to write the files to. Created if it does not
            exist (its parent must already exist). Defaults to the current
            working directory.
    """
    directory = Path(directory)
    directory.mkdir(exist_ok=True)
    for filename, data in self.files.items():
        mode = "w" if isinstance(data, str) else "wb"
        filepath = directory / filename
        # In case filename is a relative path, create the parent directories
        filepath.parent.mkdir(exist_ok=True, parents=True)
        filepath.open(mode).write(data)