Commit Graph

4221 Commits

Author SHA1 Message Date
Richard Brice c5ba22451f Adds update_alignment_parameter_segment_tags function 2026-08-07 14:33:04 -07:00
Andrej730 4d0e5f6aee ifcopenshell.file: improve missing attribute error msg 2026-08-07 17:53:18 +05:00
Andrej730 027203008d black . 2026-08-06 19:11:27 +05:00
Dion Moult 74b405a9f7 Write GlobalId index when serializing to RocksDB
rocks_db_file_storage already exposes a `g|`-prefixed guid -> instance
name map, but RocksDbSerializer never populated it, so by_guid() on a
converted file always threw.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-06 10:20:03 +10:00
Dion Moult 38e0e0e297 Compare entity instances in one file by identity again
entity_instance.file is a property backed by a fresh SWIG wrapper on every
access, and ifcopenshell::file had no __eq__, so `self.file != other.file`
in entity_instance.__eq__ compared two throwaway wrappers and was always
true - even for an instance against itself. Every entity comparison
therefore took the deep get_info() branch, making distinct but structurally
identical instances compare equal and leaving the final `return False`
unreachable. Bonsai's TestAddRepresentationItemToShapeAspect showed this as
two separate IfcShapeAspects being treated as one, so the stale aspect was
never removed.

Restore the file_pointer() pair that was commented out on both
ifcopenshell::file and express::Base - IfcParseWrapper.i already described
it as the way to "trace file ownership of instances on the python side" -
and give file the __eq__/__hash__ it was missing. The express::Base one
needs $self->file() now that file_ lives on instance_data. This also
repairs rocksdb_lazy_instance.__eq__, which already called file_pointer().

EXPRESS `=` is value comparison and `:=:` is instance comparison, but
rule_compiler emits `==` for both (see the @todo on process_rel_op), and
derived attributes build their operands in the shared global file, so rules
compare same-file instances and need value semantics. Restore those for the
duration of rule execution with settings.compare_instances_by_value,
alongside the existing unpack_non_aggregate_inverses.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-06 10:20:03 +10:00
Richard Brice 048242783e Updates update_key_point_referents to confirm to CT 4.1.4.4.3 2026-08-05 07:26:27 -07:00
Andrej730 cf7a484ce1 black . 2026-08-04 14:24:32 +05:00
Dion Moult 409373d882 Assign / unassign sequence should be specific to sequence type
I previously incorrectly believed that sequence types are mutually exclusive. E.g. you can have max 1 relationship between two tasks. Now after looking at more schedules I realise it's logically allowed to have more than one sequence relationship. For example simultaneous SS + FF.
2026-08-04 13:01:23 +10:00
Andrej730 83a7836081 stub: document use_attribute_value_derived 2026-08-03 20:04:29 +05:00
Andrej730 cdf107e579 validate fixtures: validate expected error count 2026-08-03 19:51:10 +05:00
Andrej730 c1c94b9362 validate: document supported Path type 2026-08-03 18:44:06 +05:00
Andrej730 cb52013a5d validate: color output for readibility 2026-08-03 18:38:06 +05:00
Andrej730 de4ad60df3 validate: at the end print number of errors found 2026-08-03 18:24:59 +05:00
Andrej730 2fe177885e Drop unused log_entry_type named tuple (31cf1127a) 2026-08-03 18:24:47 +05:00
Andrej730 f457048285 rules fixtures: check number of expected failures 2026-08-03 17:51:26 +05:00
Andrej730 0e9ef70971 rules fixtures: append comment indicating fixture origin 2026-08-03 16:54:52 +05:00
Andrej730 ea0be33aa1 ifcopenshell.validate: typing for json logger statements 2026-08-03 16:54:52 +05:00
Andrej730 44ce7c7e8a rules fixture: nornallize headers
- to avoid some diffs on regeneration
- some fixtures had problems with the header, so `fail` for them wasn't
really testing the intended case, because small issues in the header
would make fixture fail regardless
2026-08-03 16:54:22 +05:00
Andrej730 e57c326ad1 rule fixtures: update fixture and generation script to match 4404470d9
IFCBSPLINECURVE is abstract and causing fail to fail even if point
dimensions wouldn't be checked.
2026-08-03 16:54:22 +05:00
Andrej730 5964160d67 rule fixtures: add missing generation scripts 2026-08-03 16:54:22 +05:00
Andrej730 26ab77bdf6 rule fixtures: script to regenerate all fixtures 2026-08-03 16:54:22 +05:00
Andrej730 7b2f4ad1cb rule fixture: update generation script to match a7e925b 2026-08-03 16:54:22 +05:00
Andrej730 8f67b905eb Fix ifcopenshell.file calls in rules fixtures, use simpler schema postfix 2026-08-03 16:54:22 +05:00
Andrej730 6edea83137 file.good - document return type 2026-08-03 16:54:22 +05:00
Andrej730 b1f388311c Return support for creating uninitialized files from Python
Created a new method to avoid complicating `ifcopenshell.file` ctor signature.
2026-08-03 16:54:22 +05:00
Andrej730 26b412cff6 Fix uses of ifcopenshell.file 2026-08-03 13:18:15 +05:00
Andrej730 a86667d063 Drop ignored delete_same_facet_edge_pairs from stub 2026-08-03 12:44:16 +05:00
Andrej730 aaa763ad21 Drop revenants from previously used linters 2026-08-03 12:22:31 +05:00
Andrej730 bfd9eeb9a1 Drop unused requirements.txt
Introduced in 47cad88, but it seems it was always documentation-only and then it was also covered elsewhere.
2026-08-03 12:11:49 +05:00
Andrej730 a655ef6cd2 Drop Python 2 workaround 2026-08-03 11:52:48 +05:00
Thomas Krijnen 1c6e2aa301 run black 2026-08-02 03:12:46 +02:00
Richard Brice e077390e3d add update_key_point_referents to label key alignment points 2026-08-01 15:24:03 -07:00
Richard Brice 80cc603932 alignment: rename get_referent_nest to get_stationing_nest 2026-08-01 15:21:50 -07:00
Thomas Krijnen 064ce00826 import Any 2026-08-01 14:16:12 +02:00
Thomas Krijnen 98ce2a1b46 Move __eq__ impl back to the mixin and fix test_rules.py test 2026-08-01 13:16:51 +02:00
Bartok 4ea05f79c3 docs: add Eigen to Linux install deps
Linux "basic dependencies" omitted libeigen3-dev even though
ifcgeom requires Eigen3 (find_package Eigen3 REQUIRED) and the
cmake snippet already passes -DEIGEN_DIR=/usr/include/eigen3.
macOS Homebrew line already installs eigen.

Closes #6903

Generated with the assistance of an AI coding tool.
2026-08-01 10:50:34 +02:00
Petru Conduraru 6b917ba36d Fix test_rules.py filtering by sys.argv, which empties the corpus under pytest
test_file's parametrize list was filtered with `sys.argv[1] in
os.path.basename(fn)`, reading the raw process argv instead of a
pytest-native option. Under a bare `pytest` invocation sys.argv[1] is
pytest's own first CLI token, never a match, so the 138-fixture EXPRESS
rule corpus in test/fixtures/rules collapses to an empty parametrize and
pytest reports it as a single skipped test rather than an error. Under
CI's actual invocation (pytest -p no:pytest-blender -n $NPROCS test ...)
sys.argv[1] is "-p", which happens to substring-match 47 of the 138
fixtures, so CI has been silently running a coincidental 34% slice of
the corpus with no signal anything was wrong.

Replaced the module-level list comprehension with a pytest_generate_tests
hook plus a --rule CLI option (added via a new test/conftest.py). This
runs the full corpus by default under any pytest invocation, still
allows filtering to one rule for local debugging via --rule, and no
longer collides with pytest's own argv.

Verified all 138 fixtures collect and pass under the fixed harness
(63 fail- fixtures each raise a violation, 75 pass- fixtures raise none).

Generated with the assistance of an AI coding tool.
2026-08-01 10:50:30 +02:00
Petru Conduraru 913f9f2262 ifcopenshell.template: fix timestring ignoring an explicit timestamp of 0
create(timestamp=0) computed the FILE_NAME timestring with
`d.get("timestamp") or time.time()`, which treats 0 (a legitimate
epoch timestamp) as unset because 0 is falsy. The header ended up
with the current wall-clock time in FILE_NAME while IFCOWNERHISTORY
correctly stored CreationDate=0, an inconsistent pair of dates in
the same file. Switched to an explicit None check so an explicit
timestamp of 0 is honoured the same way any other explicit
timestamp is.

Generated with the assistance of an AI coding tool.
2026-08-01 10:49:17 +02:00
Bartok b997726564 docs: add Eigen to Linux install deps
Linux "basic dependencies" omitted libeigen3-dev even though
ifcgeom requires Eigen3 (find_package Eigen3 REQUIRED) and the
cmake snippet already passes -DEIGEN_DIR=/usr/include/eigen3.
macOS Homebrew line already installs eigen.

Closes #6903

Generated with the assistance of an AI coding tool.
2026-07-31 12:49:37 +02:00
Petru Conduraru 25713a486a Fix test_rules.py filtering by sys.argv, which empties the corpus under pytest
test_file's parametrize list was filtered with `sys.argv[1] in
os.path.basename(fn)`, reading the raw process argv instead of a
pytest-native option. Under a bare `pytest` invocation sys.argv[1] is
pytest's own first CLI token, never a match, so the 138-fixture EXPRESS
rule corpus in test/fixtures/rules collapses to an empty parametrize and
pytest reports it as a single skipped test rather than an error. Under
CI's actual invocation (pytest -p no:pytest-blender -n $NPROCS test ...)
sys.argv[1] is "-p", which happens to substring-match 47 of the 138
fixtures, so CI has been silently running a coincidental 34% slice of
the corpus with no signal anything was wrong.

Replaced the module-level list comprehension with a pytest_generate_tests
hook plus a --rule CLI option (added via a new test/conftest.py). This
runs the full corpus by default under any pytest invocation, still
allows filtering to one rule for local debugging via --rule, and no
longer collides with pytest's own argv.

Verified all 138 fixtures collect and pass under the fixed harness
(63 fail- fixtures each raise a violation, 75 pass- fixtures raise none).

Generated with the assistance of an AI coding tool.
2026-07-31 10:38:58 +02:00
Petru Conduraru 1f9a0a53bb ifcopenshell.template: fix timestring ignoring an explicit timestamp of 0
create(timestamp=0) computed the FILE_NAME timestring with
`d.get("timestamp") or time.time()`, which treats 0 (a legitimate
epoch timestamp) as unset because 0 is falsy. The header ended up
with the current wall-clock time in FILE_NAME while IFCOWNERHISTORY
correctly stored CreationDate=0, an inconsistent pair of dates in
the same file. Switched to an explicit None check so an explicit
timestamp of 0 is honoured the same way any other explicit
timestamp is.

Generated with the assistance of an AI coding tool.
2026-07-31 10:19:33 +02:00
Dion Moult 3fc83847dd Get SQL is_a() working again 2026-07-30 21:56:33 +10:00
Thomas Krijnen 6bcfb175a3 Bring back create_entity() based on global file dict 2026-07-29 13:48:18 +02:00
Dion Moult 19a1d88970 Fix all ty diagnostics on ifcviewer-wgpu (ci-lint ty-ios + ty-bonsai)
This branch carried v0.8.0's strict `[tool.ty.rules] all = "error"` config but
not the source fixes that were made upstream to satisfy it, so both ci-lint ty
gates were failing: `poe ty-ios` reported 256 diagnostics and `poe ty-bonsai`
258. Both are now clean.

Most fixes are ported from v0.8.0 and follow two idioms: initialise a name
before a conditional that may not bind it (plus an `assert` where the invariant
is real but not provable), and close an exhaustive `if`/`elif` chain with
`else: assert False, <discriminant>`.

The branch's own newer accessors are preserved throughout - `.file`,
`.declaration`, `file.types()`, `get_max_id()` are kept rather than reverted to
`wrapped_data.*`, and non-ty upstream changes (notably the in-progress geometry
cache removal) are deliberately not pulled in.

Notable fixes that are not straight ports:

* ifcopenshell_wrapper.pyi: `entity_instance.file` was declared as
  `def file(self) -> file`, where the property name shadows the `class file`
  below it, so the annotation resolved to `Unknown`. Every `element.file` in
  the codebase was therefore unchecked. Qualifying it to `ifcopenshell.file`
  restores `.schema` to its Literal union and surfaces no new diagnostics.

* model/wall.py: a duplicated merge fragment in the void-straddle path ran an
  always-true `if void_straddles:` that read `new_opening` from the mutually
  exclusive branch (stale value, or NameError on the first iteration), followed
  by an unreachable duplicate `elif`. Removing it makes the file match v0.8.0.

* light/operator.py: upstream's own fix unpacks three targets from two values
  and raises ValueError unconditionally; corrected to `None, None, None`.

* assign_system.py, validate.py, geom/main.py: walrus-in-genexp is valid at
  runtime (PEP 572 binds in the containing scope) but ty does not model it;
  rewritten as explicit loops, matching upstream.

Verified: poe ty-ios, poe ty-bonsai, ruff check src/ nix/, black --check .,
and compileall -W error at py3.10 (ifcopenshell-python) and py3.11 (bonsai).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 19:14:39 +10:00
Dion Moult c9c3beb139 poe ruff 2026-07-26 18:05:39 +10:00
Dion Moult 291d7d8441 black . 2026-07-26 18:03:09 +10:00
dependabot[bot] 695e91ef1a Bump lxml from 4.9.1 to 6.1.0 in /src/ifcopenshell-python
Bumps [lxml](https://github.com/lxml/lxml) from 4.9.1 to 6.1.0.
- [Release notes](https://github.com/lxml/lxml/releases)
- [Changelog](https://github.com/lxml/lxml/blob/master/CHANGES.txt)
- [Commits](https://github.com/lxml/lxml/compare/lxml-4.9.1...lxml-6.1.0)

---
updated-dependencies:
- dependency-name: lxml
  dependency-version: 6.1.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
(cherry picked from commit a85d5cc990)
2026-07-25 23:18:33 +10:00
Petru Conduraru 10028de0d7 Resolve nested complex quantity paths in the selector (#2041)
get_element_value could not reach the members of an IfcPhysicalComplexQuantity
(or IfcComplexProperty) by their natural path. util.element expands a complex
quantity into a dict whose nested members live under a "properties" sub-dict,
but the selector's dict navigation only looked at the top level, so
"Qto_Custom.Layer1.Width" returned None and IfcCsv exported nothing for it.
Only the internal "Qto_Custom.Layer1.properties.Width" path worked.

When a key is not a direct member of the value dict, descend into its
"properties" sub-dict so nested quantities/properties resolve with the
natural "Set.Complex.Nested" path. Direct keys still take priority, so the
explicit ".properties." path stays backward compatible and the regex branch
is untouched.

Verified: Qto_Custom.Layer1.Width -> 0.1 and Layer1.Height -> 2.5 (were
None), the sibling simple NetArea still resolves, the legacy .properties.
path still works, and IfcCsv now exports the nested value. test_selector.py:
38 passed (adds test_selecting_a_nested_complex_quantity).

Generated with the assistance of an AI coding tool.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
(cherry picked from commit 21122c0d28)
2026-07-25 23:18:33 +10:00
Petru Conduraru 1416af510a style.assign_representation_styles: fix crash on IfcPresentationStyleAssignment #7883
When replacing a style on an item whose previous IfcStyledItem wraps its styles
in the deprecated IfcPresentationStyleAssignment, and the assignment is not
being reused (use_style_assignment is False, e.g. an IFC4 file authored by
AVEVA E3D), the else branch called remove_same_type_styles(style_assignment)
with style_assignment still None, raising
AttributeError: 'NoneType' object has no attribute 'Styles'. Operate on style_,
the assignment found in the current iteration, instead of the accumulator.
Verified red-green with a minimal IFC4 file using IfcPresentationStyleAssignment.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit 82f73c29ea)
2026-07-25 23:18:33 +10:00
Petru Conduraru f761156dea Selector: negate list comparisons as an aggregate #8129
compare() recursed into list values passing the negated comparison through,
so != meant "at least one item differs" and both = and != matched the same
elements on any multi-valued property (e.g. an enumerated property with two
values selected). Strip the negation for the per-item comparison and negate
the aggregate instead, so != means "no item equals" and stays the complement
of =. The same applies to !*=.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit 209c44db83)
2026-07-25 23:18:33 +10:00