Execute an ifcopenshell.api function with CLI-provided string arguments. Args: model: The open IFC model. module: API module name (e.g. "root"). function: Function name (e.g. "create_entity"). raw_kwargs: String keyword arguments from the CLI. Returns:
(
model: ifcopenshell.file,
module: str,
function: str,
raw_kwargs: dict[str, str],
)
| 40 | |
| 41 | |
| 42 | def run_api( |
| 43 | model: ifcopenshell.file, |
| 44 | module: str, |
| 45 | function: str, |
| 46 | raw_kwargs: dict[str, str], |
| 47 | ) -> dict: |
| 48 | """Execute an ifcopenshell.api function with CLI-provided string arguments. |
| 49 | |
| 50 | Args: |
| 51 | model: The open IFC model. |
| 52 | module: API module name (e.g. "root"). |
| 53 | function: Function name (e.g. "create_entity"). |
| 54 | raw_kwargs: String keyword arguments from the CLI. |
| 55 | |
| 56 | Returns: |
| 57 | A dict with {"ok": True, "result": ...} on success, |
| 58 | or {"ok": False, "error": "..."} on failure. |
| 59 | """ |
| 60 | try: |
| 61 | fn = _import_function(module, function) |
| 62 | except (ImportError, AttributeError) as e: |
| 63 | return {"ok": False, "error": f"Cannot find function '{module}.{function}': {e}"} |
| 64 | |
| 65 | try: |
| 66 | hints = typing.get_type_hints(fn) |
| 67 | except Exception: |
| 68 | hints = {} |
| 69 | |
| 70 | sig = inspect.signature(fn) |
| 71 | coerced_kwargs = {} |
| 72 | |
| 73 | # Pass 1: coerce ifcopenshell.file-typed params first (e.g. library= in append_asset). |
| 74 | # The opened file is then used as the lookup file for entity resolution in pass 2. |
| 75 | opened_files: list[ifcopenshell.file] = [] |
| 76 | for name, value_str in raw_kwargs.items(): |
| 77 | if name not in sig.parameters: |
| 78 | return {"ok": False, "error": f"Unknown parameter '{name}' for {module}.{function}"} |
| 79 | hint = hints.get(name) |
| 80 | if not _is_file_type(hint): |
| 81 | continue |
| 82 | try: |
| 83 | coerced = coerce_value(value_str, hint, model) |
| 84 | coerced_kwargs[name] = coerced |
| 85 | if isinstance(coerced, ifcopenshell.file): |
| 86 | opened_files.append(coerced) |
| 87 | except (ValueError, TypeError) as e: |
| 88 | return {"ok": False, "error": f"Cannot convert parameter '{name}': {e}"} |
| 89 | |
| 90 | # Pass 2: coerce remaining params. Entity instance IDs are resolved from the opened |
| 91 | # library file (if any), since you are always appending from another file, never |
| 92 | # from the current model. |
| 93 | lookup_file = opened_files[0] if opened_files else None |
| 94 | for name, value_str in raw_kwargs.items(): |
| 95 | if name in coerced_kwargs: |
| 96 | continue |
| 97 | if name not in sig.parameters: |
| 98 | return {"ok": False, "error": f"Unknown parameter '{name}' for {module}.{function}"} |
| 99 | hint = hints.get(name) |