Content and attachments

Bundles can have local content embedded in the XML document, or attachments. Attachments are files that are referenced from the XML using the src attribute. Bundles with attachments are stored as zip files.

The <link>, <repository> and <file> nodes of the bundle XML all have an optional src attribute that can reference attachments. The path of src is relative to the location of the XML document of the bundle. The src attribute can refer to a single file or a directory. When src references a directory, all files in that directory and subdirectories thereof are part of the bundle. When working with an existing zip bundle, the files are accessed directly from the zip file.

The Link, Repository and File classes provide several methods to access the attachment, for example open() and copy_to(). All file access methods are documented in the SrcAttachmentMixin mixin.

When creating a bundle the src attribute should refer to the file or directory to attach. These files or directories need to remain available on the filesystem until the bundle has been exported using the to_buffer(), to_file() or to_directory() methods, and when using the latter export method, the src paths may not overlap the path to export the bundle to.

API

exception momotor.bundles.elements.content.AttachmentContent

Raised when the content is in an attachment.

Subclass of ValueError. This exception is raised when trying to access the value property of an element that has content stored in an external attachment (via the src attribute) rather than inline content.

exception momotor.bundles.elements.content.NoContent

Raised when no content was provided.

Subclass of ValueError. This exception is raised when trying to access the value property of an element that has no content set.

class momotor.bundles.elements.content.ContentAttachmentElement(bundle)

A full content element supporting attachments.

Contents can be string, bytes, boolean, integer, float or decimal.Decimal values, or provided as an attachment using the src attribute.

and Bundle itself.

Parameters:

bundle (Bundle) – The Bundle containing this element

file_size(path=None)

Get file size for the content.

Return type:

int | None

Returns:

The file size

has_attachment_content()

Returns True if the element has an existing attachment

Return type:

bool

has_writable_content()

Check if the attachment content can be written.

Returns:

True if the element has attachment content that can be written

is_dir(path=None)

Check if the attachment is a directory.

Parameters:

path (str | PurePath | None) – Optional subpath within the attachment

Return type:

bool

Returns:

True if the attachment (or subpath) refers to a directory

Raises:

FileNotFoundError – If the attachment or path doesn’t exist

open(path=None)

Open the attachment file for reading. Handles opening files directly from filesystem and from zipped bundles

Parameters:

path (str | PurePath | None) – for directory attachments, path selects a file in that directory

Return type:

IO[bytes]

Returns:

the opened file

Raises:
  • FileNotFoundError – if the element has no attachment (when src is None), or when it’s a directory and path does not exist in that directory

  • IsADirectoryError – when it’s a directory

read(path=None)

Read the contents of the attachment

Parameters:

path (str | PurePath | None) – for directory attachments, path selects a file in that directory

Return type:

bytes

Returns:

A bytes object with the full file contents

property type_: str | None

The type attribute.

class momotor.bundles.elements.content.ContentBasicElement(bundle)
A basic content element. Contents can be string or boolean values.

and Bundle itself.

Parameters:

bundle (Bundle) – The Bundle containing this element

HAS_ENCODING: ClassVar[bool] = False
VALID_PROCESSED_TYPES: ClassVar[tuple[type, ...]] = (<class 'str'>, <class 'bool'>)
class momotor.bundles.elements.content.ContentFullElement(bundle)

A full content element.

Contents can be string, bytes, boolean, integer, float or decimal.Decimal values.

and Bundle itself.

Parameters:

bundle (Bundle) – The Bundle containing this element

HAS_ENCODING: ClassVar[bool] = True
VALID_PROCESSED_TYPES: ClassVar[tuple[type, ...]] = (<class 'str'>, <class 'bool'>, <class 'bytes'>, <class 'int'>, <class 'float'>, <class 'decimal.Decimal'>)
property encoding: str | None

encoding attribute: read-only, the encoding is automatically determined from the value

property type_: str | None

The type attribute. Indicates the type of the value attribute: string, integer or float

momotor.bundles.elements.content.NO_CONTENT = <object object>

A sentinel value indicating there is no content.

class momotor.bundles.mixins.attachments.SrcAttachmentMixin(*args, **kwargs)

Mixin providing external file attachment functionality.

Adds support for referencing external files via the src attribute. Handles both filesystem and ZIP bundle-based attachments with validation, copying, and export capabilities.

See attachments for details on how attachments are handled differently for new vs. existing bundles.

copy_to(destination, *, name=None)

Copy an attachment this element refers to, to given destination directory.

If the attachment is a file, creates a new file in the given directory. If name is provided this will be the name of the new file, otherwise the name of the source file is used.

If the attachment is a directory, copies the contents of the source directory to the destination directory. If name is provided it is created as a new directory inside the destination directory.

Will not overwrite an existing file or directory.

Parameters:
Raises:
Return type:

Path

file_ctime(path=None)

Get file creation time for the attachment.

Return type:

struct_time | None

file_hashes(hash_names)

Calculate the hashes of the file.

Only for file attachments. Will return an empty dictionary if the file does not exist or is a directory.

Parameters:

hash_names (Iterable[str]) – Names of the hashes to calculate. Should be valid arguments to hashlib.new()

Return type:

dict[str, str]

Returns:

A dictionary hash-algorithm -> hash

file_size(path=None)

Get file size for the attachment.

Return type:

int | None

has_attachment_content()

Check if the element has attachment content.

Return type:

bool

Returns:

True if the element has an attachment with content

has_bundle()

Check if src references a file associated with a bundle.

Return type:

bool

Returns:

True if src references a file associated with a bundle

has_writable_content()

Check if the attachment content can be written.

Return type:

bool

Returns:

True if the element has attachment content that can be written

has_zip_bundle()

Check if src references a file in a zipped bundle.

Return type:

bool

Returns:

True if src references a file associated with a zipped bundle

is_dir(path=None)

Check if the attachment is a directory.

Parameters:

path (str | PurePath | None) – Optional subpath within the attachment

Return type:

bool

Returns:

True if the attachment (or subpath) refers to a directory

Raises:

FileNotFoundError – If the attachment or path doesn’t exist

iterdir(*, include_empty_root=False)

Recursively iterate the contents of a directory attachment. The returned paths are relative to self.absolute_path

If the attachment is an empty directory and include_empty_root is True, a single None value is yielded

Return type:

Generator[PurePath | None, None, None]

open(path=None)

Open the attachment file for reading. Handles opening files directly from filesystem and from zipped bundles

Parameters:

path (str | PurePath | None) – for directory attachments, path selects a file in that directory

Return type:

IO[bytes]

Returns:

the opened file

Raises:
  • FileNotFoundError – if the element has no attachment (when src is None), or when it’s a directory and path does not exist in that directory

  • IsADirectoryError – when it’s a directory

read(path=None)

Read the contents of the attachment

Parameters:

path (str | PurePath | None) – for directory attachments, path selects a file in that directory

Return type:

bytes

Returns:

A bytes object with the full file contents

validate_hashes(expected_hashes)

Validate hash values of the file.

Only for file attachments

Parameters:

expected_hashes (dict[str, str]) – A dictionary of hash-algorithm -> hash items

Return type:

bool

Returns:

True of the hashes are the expected values

property absolute_path: Path

Get the absolute path of the attachment referenced by src

Raises:

ZippedAttachment – when the attachment is in a zipped bundle and therefor has no filesystem path

bundle
property export_src: PurePath

The export path of the attachment, converted to be safe for use in ZIP files

property src: PurePath | None

src attribute: file path of the content.

property src_bundle: Bundle | None

If src is a relative path, the Bundle src references to.

An src attribute with a relative path is always associated with a bundle, either the current bundle or another bundle from which this src was copied from using recreate(). The bundle provides the base path for the relative path.

class momotor.bundles.mixins.attachments.AttachmentSrc(path=None, bundle=None, *, validate=True)

Represents a source reference for bundle attachments.

Encapsulates the path and bundle information for an attachment, handling both absolute filesystem paths and relative paths within bundles. Validates that the referenced path exists when validation is enabled.

Parameters:
  • path (PurePath | None) – Path to the attachment (absolute or relative to bundle)

  • bundle (Bundle | None) – Bundle containing the attachment (for relative paths)

  • validate – Whether to validate path existence during initialization

Raises:

FileNotFoundError – If validate=True and the path doesn’t exist

bundle: Bundle | None = None
path: PurePath | None = None