Skip to content

Circular import error in ifcopenshell.util.shape_builder prevents importing recipes that use ShapeBuilder (v0.8.4.post1) #7562

@jonatanjacobsson

Description

@jonatanjacobsson

Bug Description

Description

When attempting to import recipes that depend on ifcopenshell.util.shape_builder (such as OffsetObjectPlacements), a circular import error occurs. This prevents these recipes from being loaded or executed.

Environment

  • ifcopenshell version: 0.8.4.post1 (also affects 0.8.4)
  • ifcpatch version: 0.8.4
  • Python version: 3.11
  • OS: Linux (Docker container)

Minimal Reproduction

# This fails with circular import error
from ifcpatch.recipes.OffsetObjectPlacements import Patcher

Or when using ifcpatch:

import ifcopenshell
import ifcpatch

ifc_file = ifcopenshell.open("model.ifc")

# This fails when it tries to import the recipe
output = ifcpatch.execute({
    "input": "model.ifc",
    "file": ifc_file,
    "recipe": "OffsetObjectPlacements",
    "arguments": ["0", "0", "1000", "true", "0", "0", "90"]
})

Attachments

No response

Debug and Error Output

## Error Traceback


Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/usr/local/lib/python3.11/site-packages/ifcpatch/recipes/OffsetObjectPlacements.py", line 24, in <module>
    from ifcopenshell.util.shape_builder import ShapeBuilder
  File "/usr/local/lib/python3.11/site-packages/ifcopenshell/util/shape_builder.py", line 26, in <module>
    import ifcopenshell.util.element
  File "/usr/local/lib/python3.11/site-packages/ifcopenshell/util/element.py", line 22, in <module>
    import ifcopenshell.util.representation
  File "/usr/local/lib/python3.11/site-packages/ifcopenshell/util/representation.py", line 24, in <module>
    import ifcopenshell.util.shape
  File "/usr/local/lib/python3.11/site-packages/ifcopenshell/util/shape.py", line 27, in <module>
    from ifcopenshell.util.shape_builder import VectorType
ImportError: cannot import name 'VectorType' from partially initialized module 'ifcopenshell.util.shape_builder' (most likely due to a circular import) (/usr/local/lib/python3.11/site-packages/ifcopenshell/util/shape_builder.py)


## Analysis

The circular import chain is:

1. `shape_builder.py` imports `ifcopenshell.util.element`
2. `element.py` imports `ifcopenshell.util.representation`
3. `representation.py` imports `ifcopenshell.util.shape`
4. `shape.py` imports `VectorType` from `ifcopenshell.util.shape_builder`
5. But `shape_builder.py` hasn't finished initializing yet → **ImportError**

## Affected Recipes

At minimum:
- `OffsetObjectPlacements` (confirmed)
- Potentially any other recipe that imports from `ifcopenshell.util.shape_builder`

## Possible Solutions

1. **Use `TYPE_CHECKING` for type hints**: Move the `VectorType` import in `shape.py` inside an `if TYPE_CHECKING:` block since it's only used for type annotations

2. **Move type definitions**: Create a separate `types.py` module for shared type definitions like `VectorType`

3. **Lazy imports**: Defer the import of `shape_builder` in `shape.py` until it's actually needed at runtime

## Workaround

As a temporary workaround, you can pre-initialize `shape_builder` with a mock `VectorType` before importing the recipe:


import sys
import types
from typing import Any

# Create mock shape_builder with VectorType
mock_shape_builder = types.ModuleType('ifcopenshell.util.shape_builder')
mock_shape_builder.VectorType = Any
sys.modules['ifcopenshell.util.shape_builder'] = mock_shape_builder

# Import base modules (shape.py will use mock VectorType)
import ifcopenshell
import ifcopenshell.util.shape

# Remove mock and import real module
del sys.modules['ifcopenshell.util.shape_builder']
import ifcopenshell.util.shape_builder

# Now recipes work
from ifcpatch.recipes.OffsetObjectPlacements import Patcher  # Success!

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions