Bug: Loading failure in files without any Part objects

Here's the place for discussion related to coding in FreeCAD, C++ or Python. Design, interfaces and structures.
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
Post Reply
matthijskooijman
Posts: 72
Joined: Thu Mar 25, 2021 10:59 am

Bug: Loading failure in files without any Part objects

Post by matthijskooijman »

While making some small test files for another problem, I noticed a peculiar problem. After a lot of digging, I've noticed this problem occurs when using a file containing a BuildingPart, but no Part:: objects. In such files, as attached, ViewProviderBuildingPart.attach() will try to execute coin.SoType.fromName("SoBrepEdgeSet").createInstance(), which fails because PartGui (which initializes and registers SoBrepEdgeSet) is not loaded yet.

For example when you load the attached file (which can be created be creating a single Arch level object), this problem shows. Not that it only shows up the first time you load a file (at least when auto-opening a workbench after loading the file, which loads PartGui), so restart FreeCAD before trying.

Image

On the commandline, you get:

Code: Select all

01:28:24  Traceback (most recent call last):
  File "/home/matthijs/docs/src/upstream/FreeCAD/build/Mod/Arch/ArchBuildingPart.py", line 601, in attach
    lin.coordIndex.setValues([0,1,-1,2,3,-1,4,5,-1])
<class 'AttributeError'>: 'NoneType' object has no attribute 'coordIndex'
01:28:24  Traceback (most recent call last):
  File "/home/matthijs/docs/src/upstream/FreeCAD/build/Mod/Arch/ArchBuildingPart.py", line 725, in onChanged
    self.txt.string.setValue(txt)
<class 'AttributeError'>: 'ViewProviderBuildingPart' object has no attribute 'txt'
The first is because coin.SoType.fromName("SoBrepEdgeSet").createInstance() returns None, the second is because the first error terminated the attach method halfway. Another symptom of this is that the ViewProvider will not have any display modes defined, which causes it to remain invisible (grayed out) even though its Visibility is True (this is what started my digging).

This issue does not show up in most files, since you'll usually have some Part-based object somewhere in the tree (like a Site object). This means it's probably a fairly minor problem, mostly prone to show up in tiny test files, but it would be good to get this fixed anyway (ideally in a way that makes the dependencies more explicit as well).

A quick way to fix this would be to just import ParGui where needed, e.g.

Code: Select all

--- a/src/Mod/Arch/ArchBuildingPart.py
+++ b/src/Mod/Arch/ArchBuildingPart.py
@@ -589,6 +589,7 @@ def attach(self,vobj):
         self.Object = vobj.Object
         self.clip = None
         from pivy import coin
+        import PartGui  # for SoBrepEdgeSet
         self.sep = coin.SoGroup()
         self.mat = coin.SoMaterial()
         self.sep.addChild(self.mat)
But there's a few more places where this might happen, and having those imports all over (especially since the imports themselves are not directly used) is not so nice. It would be slightly nicer if the resulting SoBrepEdgeSet was actually exported on a python level, so you could just write PartGui.SoBrepEdgeSet.createInstance() (or something like that), making it more explicit what the import is for.

Alternatively, if this SoBrepEdgeSet is widely used, maybe it should be moved to some more generic place and always initialized?

There's a few more places and also other classes that I think might be susceptible to the same problem (haven't checked these yet, though):

Code: Select all

$ git grep coin.SoType.fromName
Gui/Inventor/SoDrawingGrid.cpp:grid=coin.SoType.fromName("SoDrawingGrid").createInstance()
Mod/Arch/ArchAxis.py:        self.lineset = coin.SoType.fromName("SoBrepEdgeSet").createInstance()
Mod/Arch/ArchBuildingPart.py:        lin = coin.SoType.fromName("SoBrepEdgeSet").createInstance()
Mod/Arch/ArchSectionPlane.py:        #fs = coin.SoType.fromName("SoBrepFaceSet").createInstance() # this causes a FreeCAD freeze for me
Mod/Arch/ArchSectionPlane.py:        ls = coin.SoType.fromName("SoBrepEdgeSet").createInstance()
Mod/Arch/ArchStructure.py:                self.pointset = coin.SoType.fromName("SoBrepPointSet").createInstance()
Mod/Arch/ArchStructure.py:                self.lineset = coin.SoType.fromName("SoBrepEdgeSet").createInstance()
Mod/Draft/draftguitools/gui_trackers.py:            self.selnode = coin.SoType.fromName("SoFCSelection").createInstance()
Mod/Draft/draftguitools/gui_trackers.py:        self.dimnode = coin.SoType.fromName("SoDatumLabel").createInstance()
Mod/Draft/draftviewproviders/view_dimension.py:        self.line = coin.SoType.fromName("SoBrepEdgeSet").createInstance()
Mod/Draft/draftviewproviders/view_dimension.py:        self.arc = coin.SoType.fromName("SoBrepEdgeSet").createInstance()
Mod/Draft/draftviewproviders/view_label.py:        self.line = coin.SoType.fromName("SoBrepEdgeSet").createInstance()
Mod/Draft/draftviewproviders/view_label.py:        self.frame = coin.SoType.fromName("SoBrepEdgeSet").createInstance()
Mod/Draft/draftviewproviders/view_wpproxy.py:        ls = coin.SoType.fromName("SoBrepEdgeSet").createInstance()
Mod/Path/PathScripts/PathDressupTagGui.py:        self.scale = coin.SoType.fromName('SoShapeScale').createInstance()
Mod/Path/PathScripts/PathJobGui.py:        self.axs = coin.SoType.fromName('SoAxisCrossKit').createInstance()
Mod/Path/PathScripts/PathJobGui.py:        self.sca = coin.SoType.fromName('SoShapeScale').createInstance()
Mod/Path/PathScripts/PathJobGui.py:        self.scs = coin.SoType.fromName('SoShapeScale').createInstance()
Attachments
NoParts.FCStd
(9.52 KiB) Downloaded 36 times
Post Reply