Skip to content

Guard view providers against a None ViewObject (headless support) - #2

Open
masonhensley wants to merge 1 commit into
iplayfast:mainfrom
masonhensley:fix/headless-viewprovider-guard
Open

masonhensley wants to merge 1 commit into
iplayfast:mainfrom
masonhensley:fix/headless-viewprovider-guard

Conversation

@masonhensley

Copy link
Copy Markdown

Problem

Any gear creation fails under freecadcmd, which makes the workbench unusable from scripts and CI:

AttributeError: 'NoneType' object has no attribute 'Proxy'
  planetaryGearCreator.py:337  ViewProviderGearResult(gear_obj.ViewObject, icon)
  genericGear.py:3411          obj.Proxy = self

Headless FreeCAD is built without the Gui module, so obj.ViewObject is None. It works in the GUI, which is why this isn't visible in normal use.

Root cause

The geometry code is already headless-clean — validators, profile math, and the PartDesign build all run fine. Only the unconditional view provider attachment fails.

Twelve call sites pass .ViewObject straight into a view provider:

planetaryGearCreator, wormGear, globoidWormGear, globoidWormGearV2, globoidWormGearV4, genevaWheel, hypoidGear, screwGear, nonCircularGear, unifiedGear, gearStack

They funnel through five constructors, so guarding those fixes all twelve at once rather than patching each call site:

  • genericGear.ViewProviderGearResult (9 of the 12)
  • genericGear.ViewProviderGenericGear
  • gearStack.ViewProviderGearStack
  • unifiedGear.UnifiedSpurGearViewProvider
  • cycloidGearCreator.ViewProviderCycloidGearBoxResult

planetaryGearCreator already has a GUI_AVAILABLE flag and correctly guards its dialog class with it — this extends the same idea to the view providers.

Fix

Early return when the view object is None. 20 lines, 4 files, no GUI behaviour change: a non-None view object takes the original path untouched.

Verification

Against this branch under freecadcmd (FreeCAD 1.1.3, macOS arm64), with no other patches or shims:

from freecad.GearWorkBench import planetaryGearCreator as pgc
doc = App.newDocument("t")
res = pgc.createPlanetarySystem(doc, "Spur", 12, 42, 96, 3, 0.7, 20.0, 10.0, 0.0, 0.25)
doc.recompute()

Builds a complete 9:1 system — sun 480.95 mm³, three planets 6562.69 mm³ each, ring 8247.02 mm³, every shape isValid(), tooth counts correct in the polar patterns (12 / 42). Volumes sit just below the analytic solid-disc figures, as expected once tooth spaces, bore, and keyway are removed. On main the same script raises before building anything.

Also re-ran a 4:1 config (15/15/45, m=1.0) as a regression check, and confirmed the GUI path is unaffected.

🤖 Generated with Claude Code

Gear creation raises AttributeError under freecadcmd, where FreeCAD is
built without the Gui module and obj.ViewObject is None:

    AttributeError: 'NoneType' object has no attribute 'Proxy'

The geometry code itself is headless-clean; only the unconditional view
provider attachment fails. Twelve call sites pass .ViewObject straight
into a view provider (planetary, worm, globoid x3, geneva, hypoid,
screw, non-circular, unified, gear stack), and they funnel through five
constructors, so the guard goes there rather than at each call site.

planetaryGearCreator already has a GUI_AVAILABLE flag and correctly
guards its dialog class with it; this extends the same idea to the
view providers.

No GUI behaviour change: a non-None view object takes the original
path untouched.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant