Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 

README.md

ifcedit

A CLI wrapper that exposes all 350+ ifcopenshell.api mutation functions as shell commands. Functions are auto-discovered at runtime via introspection -- no hardcoded list to maintain.

Installation

pip install ifcedit

Requires ifcopenshell.

Usage

ifcedit <command> [options] [--format json|text]

Three subcommands: list to discover functions, docs to read their documentation, and run to execute them.

Subcommands

list

Discover available API modules and their functions.

List all modules:

ifcedit list
[
  {
    "module": "root",
    "description": "Functions for creating project-level entities",
    "functions": ["create_entity", "remove_product", "copy_class"],
    "count": 3
  },
  {
    "module": "spatial",
    "description": "Functions for managing spatial relationships",
    "functions": ["assign_container", "unassign_container"],
    "count": 2
  }
]

List functions in a module:

ifcedit list root
[
  {
    "name": "create_entity",
    "description": "Create an IFC entity with optional initial attributes",
    "params": [
      {"name": "ifc_class", "type": "str", "required": true},
      {"name": "name", "type": "Optional[str]"}
    ]
  }
]

docs

Show full documentation for a specific function, including parameter descriptions from docstrings and return type.

ifcedit docs root.create_entity
{
  "module": "root",
  "function": "create_entity",
  "description": "Create an IFC entity with optional initial attributes",
  "long_description": "This function creates a new entity instance...",
  "params": [
    {
      "name": "ifc_class",
      "type": "str",
      "required": true,
      "description": "The IFC class name (e.g. 'IfcWall', 'IfcProject')"
    },
    {
      "name": "name",
      "type": "Optional[str]",
      "description": "Optional name attribute"
    }
  ],
  "return_type": "ifcopenshell.entity_instance",
  "return_description": "The newly created entity instance"
}

run

Execute an API function against an IFC file. Parameters are passed as --key value pairs after the function name.

ifcedit run model.ifc root.create_entity --ifc_class IfcWall --name "My Wall"
{
  "ok": true,
  "result": {"id": 42, "type": "IfcWall", "name": "My Wall"}
}

Options:

  • -o, --output <path> -- write to a different file instead of overwriting the input
  • --dry-run -- validate parameters without executing or saving
# Save to a new file
ifcedit run model.ifc root.create_entity -o out.ifc --ifc_class IfcWall

# Validate without executing
ifcedit run model.ifc root.create_entity --dry-run --ifc_class IfcWall

Dry-run output shows the resolved parameters:

{
  "ok": true,
  "dry_run": true,
  "module": "root",
  "function": "create_entity",
  "args": {"ifc_class": "IfcWall", "name": "My Wall"}
}

Parameter type coercion

CLI strings are automatically converted to the types expected by each API function, using the function's type annotations:

Type CLI input Python value
str "hello" "hello"
int "42" or "#42" 42
float "3.14" 3.14
bool "true", "1", "yes" True
Optional[X] "none" None
entity_instance "42" or "#42" resolved from model by step ID
list[entity_instance] "5,6,7" or "[5, 6, 7]" list of resolved entities
dict '{"key": "val"}' parsed JSON object
Literal["A", "B"] "A" validated against allowed values

Examples

# Create a project
ifcedit run model.ifc root.create_entity --ifc_class IfcProject --name "My Project"

# Assign an element to a storey
ifcedit run model.ifc spatial.assign_container --products 10 --relating_structure 4

# Assign multiple elements at once
ifcedit run model.ifc aggregate.assign_object --products "5,6,7" --relating_object 1

# Add a property set
ifcedit run model.ifc pset.add_pset --product 10 --name "Pset_WallCommon"

# Edit properties
ifcedit run model.ifc pset.edit_pset --pset 15 \
    --properties '{"IsExternal": true, "FireRating": "2HR"}'

foreach

Apply an API function to each element in a JSON array read from stdin. {field} placeholders in argument values are substituted with fields from each JSON object. The model is opened once and saved once regardless of how many elements are processed.

ifcquery model.ifc select 'IfcWindow' | ifcedit foreach model.ifc root.remove_product --product {id}
{"ok": true, "count": 36, "errors": []}

Placeholder tokens match the fields emitted by ifcquery — typically {id}, {type}, and {name}:

ifcquery model.ifc select 'IfcDoor' | ifcedit foreach model.ifc attribute.edit_attributes \
    --product {id} --attributes '{"Name": "Door"}'

Options:

  • -o, --output <path> -- write to a different file instead of overwriting the input

Output:

  • count -- number of elements successfully processed
  • errors -- list of per-element failures, each with index, item, and error; processing continues past errors
{
  "ok": false,
  "count": 34,
  "errors": [
    {"index": 2, "item": {"id": 55, "type": "IfcWindow", "name": "W03"}, "error": "Entity #55 not found in model"}
  ]
}

Exit code is 1 if any element failed.

quantify

Run quantity take-off (QTO) on an IFC file, computing physical measurements (volume, area, length, count, weight) and writing them back as IfcElementQuantity property sets. Uses ifc5d rules.

List available rules:

ifcedit quantify list
[
  {"name": "IFC4QtoBaseQuantities"},
  {"name": "IFC4X3QtoBaseQuantities"}
]

Run QTO on a file:

ifcedit quantify run model.ifc IFC4QtoBaseQuantities
ifcedit quantify run model.ifc IFC4QtoBaseQuantities --selector IfcWall
ifcedit quantify run model.ifc IFC4QtoBaseQuantities -o model_qto.ifc
{"ok": true, "rule": "IFC4QtoBaseQuantities", "elements_quantified": 42}

Options:

  • --selector <query> -- ifcopenshell selector to restrict elements (default: all IfcElement)
  • -o, --output <path> -- write to a different file instead of overwriting the input

Note: quantify run writes geometry-based measurements and requires the IfcOpenShell C++ geometry bindings for elements with computed quantities.

Error handling

Errors are reported in the JSON response:

{
  "ok": false,
  "error": "Entity #999 not found in model"
}

Exit code is 0 on success, 1 on error.

Relationship to ifcquery

ifcedit and ifcquery are complementary tools:

  • ifcquery reads and inspects IFC models (summary, tree, info, select, relations, clash, validate, schedule, cost, schema, contexts, materials, plot, render)
  • ifcedit modifies IFC models by wrapping ifcopenshell.api functions, and runs QTO via quantify

A typical workflow: inspect with ifcquery, look up the right API function with ifcedit docs, then apply changes with ifcedit run.

The two tools also compose directly in shell scripts. Use ifcquery --format ids to feed a list of IDs into a run parameter, or pipe ifcquery select JSON into ifcedit foreach to apply an operation to every matching element:

# Aggregate — pass all IDs as a list parameter
ifcedit run model.ifc spatial.unassign_container \
    --products "$(ifcquery model.ifc --format ids select 'IfcWall')"

# Fan-out — one operation per element, model opened and saved once
ifcquery model.ifc select 'IfcWindow' | ifcedit foreach model.ifc root.remove_product --product {id}

License

LGPLv3+ -- see the IfcOpenShell project license.