Skip to content

object

object

The EmbeddedObject proxy — a file embedded in a document as an OLE object.

Word can embed a whole file inside a document and show it as an icon or a preview image that opens the original application on double-click. The read side matters on its own: for a document containing embedded attachments there was previously no way to discover that they exist, let alone extract them.

This is a different thing from the two neighbouring features. Document.add_alt_chunk() imports content and dissolves it into the document when Word opens the file; an OLE object stays a distinct embedded file. Run.add_picture() embeds an image with no underlying document.

EmbeddedObject

EmbeddedObject(
    object_elm: CT_Object, parent: ProvidesStoryPart
)

Bases: StoryChild

An OLE object embedded in a run — a spreadsheet, a PDF, another document.

Reached through Run.embedded_objects or Document.embedded_objects.

Source code in src/docx/object.py
def __init__(self, object_elm: CT_Object, parent: t.ProvidesStoryPart):
    super().__init__(parent)
    self._element = object_elm
    self._object = object_elm

prog_id property

prog_id: str | None

The application Word launches for this object, e.g. "Excel.Sheet.12".

None when the object names none. This is what tells Word which application to open; an object whose ProgID names nothing installed is one Word shows but cannot open.

is_linked property

is_linked: bool

True when the object links to an external file rather than embedding it.

A linked object's bytes are not in the package, so blob is None.

shows_icon property

shows_icon: bool

True when Word shows this object as an icon rather than a preview.

embedded_part property

embedded_part: Part | None

The package part holding the embedded file, or None.

None for a linked object, and for an embedded one whose relationship the document does not resolve — which is a broken document rather than an error here.

blob property

blob: bytes | None

The bytes of the embedded file, or None when there are none to give.

This is the useful half — extracting an attachment from a document:

for obj in document.embedded_objects:
    if obj.blob is not None:
        Path(obj.filename or "attachment").write_bytes(obj.blob)

content_type property

content_type: str | None

The content type of the embedded part, or None when there is no part.

filename property

filename: str | None

The partname's basename, e.g. "oleObject1.bin", or None.

OOXML does not record the original file name of an embedded object; this is the name of the part it landed in, which is what a caller extracting it has to work with.

image property

image: Image | None

The icon or preview image Word displays for this object, or None.

Every OLE object has one — Word cannot render the embedded file itself — so None means the document is missing it rather than that the object has none.

add_embedded_object

add_embedded_object(
    run: object,
    path_or_stream: str | PathLike[str] | IO[bytes],
    *,
    icon: str | PathLike[str] | IO[bytes],
    prog_id: str | None = None,
    width: Length | None = None,
    height: Length | None = None,
) -> EmbeddedObject

Embed path_or_stream in run as an OLE object; see Run.add_embedded_object.

Source code in src/docx/object.py
def add_embedded_object(
    run: object,
    path_or_stream: str | os.PathLike[str] | IO[bytes],
    *,
    icon: str | os.PathLike[str] | IO[bytes],
    prog_id: str | None = None,
    width: Length | None = None,
    height: Length | None = None,
) -> EmbeddedObject:
    """Embed `path_or_stream` in `run` as an OLE object; see :meth:`.Run.add_embedded_object`."""
    part = run.part  # pyright: ignore[reportAttributeAccessIssue]
    package = part.package
    assert package is not None

    blob = _read_blob(path_or_stream)
    partname = package.next_partname("/word/embeddings/oleObject%d.bin")
    object_part = Part(partname, CT.OFC_OLE_OBJECT, blob, package)
    object_rId = part.relate_to(object_part, RT.OLE_OBJECT)

    icon_rId, icon_image = part.get_or_add_image(icon)
    cx = width if width is not None else icon_image.width
    cy = height if height is not None else icon_image.height

    ordinal = _next_shape_ordinal(part)
    # -- the shape id must be unique in the document, and `o:OLEObject/@ShapeID` names
    # -- it, so the two are generated together --
    shape_id = "_x0000_i%04d" % ordinal

    object_elm = parse_xml(
        "<w:object %s>\n"
        '  <v:shape id="%s" type="#_x0000_t75" style="width:%.2fpt;height:%.2fpt">\n'
        '    <v:imagedata r:id="%s" o:title=""/>\n'
        "  </v:shape>\n"
        '  <o:OLEObject Type="Embed" ProgID="%s" ShapeID="%s" DrawAspect="Icon"'
        ' ObjectID="_%d" r:id="%s"/>\n'
        "</w:object>"
        % (
            nsdecls("w", "v", "o", "r"),
            shape_id,
            Emu(cx).pt,
            Emu(cy).pt,
            icon_rId,
            prog_id or _DEFAULT_PROG_ID,
            shape_id,
            ordinal,
            object_rId,
        )
    )
    run._r.append(object_elm)  # pyright: ignore[reportPrivateUsage]
    return EmbeddedObject(object_elm, run)  # pyright: ignore[reportArgumentType]

iter_embedded_objects

iter_embedded_objects(
    element: object, parent: ProvidesStoryPart
) -> list[EmbeddedObject]

The EmbeddedObject instances under element, in document order.

Source code in src/docx/object.py
def iter_embedded_objects(
    element: object, parent: t.ProvidesStoryPart
) -> list[EmbeddedObject]:
    """The |EmbeddedObject| instances under `element`, in document order."""
    return [
        EmbeddedObject(obj, parent)
        for obj in element.xpath(".//w:object")  # pyright: ignore[reportAttributeAccessIssue]
    ]