ifcurl/pyproject.toml
Bruno Postle 96aa1a2377 diff rendering: two-pass IFC diff with green/blue/red colouring
Implements the ifcgit/Bonsai diff algorithm for the preview service:

diff.py: step_ids_from_diff() parses git diff text (regex on +#NNN= / -#NNN=
lines) to classify step IDs as added/modified/removed.  expand_step_ids()
walks IfcShapeRepresentation, IfcObjectPlacement, IfcPropertySet, and
IfcTypeProduct relationships to promote changed sub-entities to the parent
IfcProduct that is visually affected.

render.py: render_diff() does two passes over the same camera.  Pass 1 renders
the head model with green=added, blue=modified, ghost=unchanged.  Pass 2
renders only the removed elements from the base model in red, using the camera
auto-fitted to pass 1.  PIL composites the passes: wherever pass 2 is not
white background it stamps onto pass 1.  Moved elements (modified) appear once
in blue with no doubling artefact.

git.py: diff_text() runs git diff against the cached bare repo clone and
returns the raw text for diff.py to parse.

service.py: GET+POST /render_diff endpoint.  Fetches both commits, gets
diff text, runs the full pipeline sandboxed.  Caches on disk when both refs
are immutable.  Pillow added to render/service extras.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 06:52:01 +01:00

64 lines
1.6 KiB
TOML

[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"
[project]
name = "ifcurl"
version = "0.0.0"
authors = [
{ name="Bruno Postle", email="bruno@postle.net" },
]
description = "Resolve and render ifc:// URLs pointing to IFC models in git repositories"
readme = "README.md"
license = { file = "LICENSE" }
requires-python = ">=3.10"
keywords = ["IFC", "BIM", "URL"]
classifiers = [
"Programming Language :: Python :: 3",
"License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)",
]
dependencies = ["ifcopenshell", "gitpython", "platformdirs"]
[project.optional-dependencies]
render = ["pyvista", "numpy", "Pillow"]
service = ["pyvista", "numpy", "Pillow", "fastapi", "uvicorn[standard]", "bcf"]
[project.scripts]
ifcurl = "ifcurl.__main__:main"
[project.urls]
Homepage = "https://github.com/brunopostle/ifcurl"
Issues = "https://github.com/brunopostle/ifcurl/issues"
[tool.setuptools.packages.find]
include = ["ifcurl*"]
exclude = ["test*"]
[tool.setuptools.package-data]
ifcurl = ["py.typed"]
[tool.pytest.ini_options]
testpaths = ["tests"]
[tool.ruff]
line-length = 120
[tool.ruff.lint]
preview = true
select = [
"E9", # io errors
"FA", # future annotations
"UP", # pyupgrade
"I", # import sorting
"RUF015",
"RUF022",
]
ignore = [
"UP007", # Optional to X | Y
"UP045", # Optional to X | None
"UP015", # Unnecessary mode argument
"UP028", # yield for -> yield from
"UP030", # implicit references for positional format fields
"UP031", # Replace % with .format
"UP032", # Replace .format with f-string
]