Skip to content

freecad_helpers

freecad.datamanager_wb.freecad_helpers

Shared helper utilities for interacting with FreeCAD documents.

These helpers centralize small FreeCAD-facing operations (document access, object lookup, expression iteration, copy-on-change filtering) behind a narrow API. Most functions accept an optional FreeCadContext so they can be tested outside FreeCAD.

build_expression_key(*, obj_name, lhs)

Build the canonical expression key string for a named expression entry.

Source code in freecad/datamanager_wb/freecad_helpers.py
def build_expression_key(*, obj_name: str, lhs: object) -> str:
    """Build the canonical expression key string for a named expression entry."""
    if str(lhs).startswith("."):
        return f"{obj_name}{lhs}"
    return f"{obj_name}.{lhs}"

get_active_document(*, ctx=None)

Return the currently active document, if any.

Source code in freecad/datamanager_wb/freecad_helpers.py
def get_active_document(*, ctx: FreeCadContext | None = None) -> object | None:
    """Return the currently active document, if any."""
    return get_port(ctx).get_active_document()

get_copy_on_change_groups(doc)

Return all CopyOnChange groups found in the given document.

Source code in freecad/datamanager_wb/freecad_helpers.py
def get_copy_on_change_groups(doc: object) -> list[object]:
    """Return all CopyOnChange groups found in the given document."""
    groups: list[object] = []
    direct = _get_direct_copy_on_change_group(doc)
    if direct is not None:
        groups.append(direct)
    groups.extend(_iter_copy_on_change_named_groups(doc))
    return groups

get_copy_on_change_names(*, doc, type_id)

Return object names of the given type_id under CopyOnChange groups.

Source code in freecad/datamanager_wb/freecad_helpers.py
def get_copy_on_change_names(*, doc: object, type_id: str) -> set[str]:
    """Return object names of the given `type_id` under CopyOnChange groups."""
    seen: set[int] = set()
    names: set[str] = set()

    def visit(o: object) -> None:
        oid = id(o)
        if oid in seen:
            return
        seen.add(oid)

        if getattr(o, "TypeId", None) == type_id:
            name = get_object_name(o)
            if name is not None:
                names.add(name)
            return

        for child in iter_object_children(o):
            visit(child)

    for group in get_copy_on_change_groups(doc):
        visit(group)

    return names

get_object_name(obj)

Return the object's internal Name if present and non-empty.

Source code in freecad/datamanager_wb/freecad_helpers.py
def get_object_name(obj: object) -> str | None:
    """Return the object's internal `Name` if present and non-empty."""
    name = getattr(obj, "Name", None)
    if isinstance(name, str) and name:
        return name
    return None

get_typed_object(doc, name, *, type_id)

Return a named document object only if its TypeId matches.

Source code in freecad/datamanager_wb/freecad_helpers.py
def get_typed_object(doc: object, name: str, *, type_id: str) -> object | None:
    """Return a named document object only if its `TypeId` matches."""
    getter = getattr(doc, "getObject", None)
    if not callable(getter):
        return None
    obj = getter(name)
    if obj is None or getattr(obj, "TypeId", None) != type_id:
        return None
    return cast(object, obj)

iter_document_objects(doc)

Yield non-null objects from a FreeCAD document's Objects list.

Source code in freecad/datamanager_wb/freecad_helpers.py
def iter_document_objects(doc: object) -> Iterator[object]:
    """Yield non-null objects from a FreeCAD document's `Objects` list."""
    for obj in getattr(doc, "Objects", []) or []:
        if obj is not None:
            yield obj

iter_expression_engine_entries(doc)

Yield (obj, lhs, expr_text) tuples for expression engine entries.

Source code in freecad/datamanager_wb/freecad_helpers.py
def iter_expression_engine_entries(doc: object) -> Iterator[tuple[object, object, object]]:
    """Yield `(obj, lhs, expr_text)` tuples for expression engine entries."""
    for obj in iter_document_objects(doc):
        for expr in _iter_expression_engine(obj):
            parsed = _try_parse_expression(expr)
            if parsed is None:
                continue
            lhs, expr_text = parsed
            yield obj, lhs, expr_text

iter_named_expression_engine_entries(doc)

Yield (obj_name, lhs, expr_text) tuples for expression engine entries.

Source code in freecad/datamanager_wb/freecad_helpers.py
def iter_named_expression_engine_entries(doc: object) -> Iterator[tuple[str, object, object]]:
    """Yield `(obj_name, lhs, expr_text)` tuples for expression engine entries."""
    for obj, lhs, expr_text in iter_expression_engine_entries(doc):
        obj_name = get_object_name(obj)
        if obj_name is None:
            continue
        yield obj_name, lhs, expr_text

iter_object_children(obj)

Yield child objects by traversing common FreeCAD container attributes.

Source code in freecad/datamanager_wb/freecad_helpers.py
def iter_object_children(obj: object) -> Iterator[object]:
    """Yield child objects by traversing common FreeCAD container attributes."""
    yield from _iter_non_null(getattr(obj, "Group", None))
    yield from _iter_non_null(getattr(obj, "OutList", None))