fix: 修复 FCStd 导入后变换异常
parent
0bd5ccb2ad
commit
58c9eae33c
@ -0,0 +1,482 @@
|
|||||||
|
import importlib
|
||||||
|
import sys
|
||||||
|
import types
|
||||||
|
import unittest
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
REPO_ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
MODULE_DIR = REPO_ROOT / "src" / "Mod" / "FreeCADExchange"
|
||||||
|
if str(MODULE_DIR) not in sys.path:
|
||||||
|
sys.path.insert(0, str(MODULE_DIR))
|
||||||
|
|
||||||
|
|
||||||
|
def _install_fake_freecad(source_doc):
|
||||||
|
class Vector:
|
||||||
|
def __init__(self, x=0.0, y=0.0, z=0.0):
|
||||||
|
self.x = float(x)
|
||||||
|
self.y = float(y)
|
||||||
|
self.z = float(z)
|
||||||
|
|
||||||
|
class Rotation:
|
||||||
|
def __init__(self, axis=None, angle=None):
|
||||||
|
self.Axis = axis
|
||||||
|
self.Angle = angle
|
||||||
|
|
||||||
|
class Placement:
|
||||||
|
def __init__(self, base=None, rotation=None):
|
||||||
|
self.Base = base or Vector()
|
||||||
|
self.Rotation = rotation or Rotation()
|
||||||
|
|
||||||
|
fake_freecad = types.ModuleType("FreeCAD")
|
||||||
|
fake_freecad.Vector = Vector
|
||||||
|
fake_freecad.Rotation = Rotation
|
||||||
|
fake_freecad.Placement = Placement
|
||||||
|
fake_freecad.Console = types.SimpleNamespace(
|
||||||
|
PrintMessage=lambda *args, **kwargs: None,
|
||||||
|
PrintWarning=lambda *args, **kwargs: None,
|
||||||
|
PrintError=lambda *args, **kwargs: None,
|
||||||
|
)
|
||||||
|
fake_freecad.ActiveDocument = None
|
||||||
|
fake_freecad.set_active_document_calls = []
|
||||||
|
|
||||||
|
def set_active_document(name):
|
||||||
|
fake_freecad.set_active_document_calls.append(name)
|
||||||
|
|
||||||
|
def close_document(*args, **kwargs):
|
||||||
|
fake_freecad.ActiveDocument = None
|
||||||
|
|
||||||
|
fake_freecad.setActiveDocument = set_active_document
|
||||||
|
fake_freecad.listDocuments = lambda: {}
|
||||||
|
fake_freecad.openDocument = lambda *args, **kwargs: source_doc
|
||||||
|
fake_freecad.closeDocument = close_document
|
||||||
|
sys.modules["FreeCAD"] = fake_freecad
|
||||||
|
|
||||||
|
fake_freecadgui = types.ModuleType("FreeCADGui")
|
||||||
|
fake_freecadgui.SendMsgToActiveView = lambda *args, **kwargs: None
|
||||||
|
fake_freecadgui.addCommand = lambda *args, **kwargs: None
|
||||||
|
fake_freecadgui.getDocument = lambda *args, **kwargs: object()
|
||||||
|
fake_freecadgui.Selection = types.SimpleNamespace(getSelection=lambda: [])
|
||||||
|
sys.modules["FreeCADGui"] = fake_freecadgui
|
||||||
|
|
||||||
|
fake_importgui = types.ModuleType("ImportGui")
|
||||||
|
fake_importgui.insert = lambda *args, **kwargs: None
|
||||||
|
sys.modules["ImportGui"] = fake_importgui
|
||||||
|
|
||||||
|
fake_device_preview = types.ModuleType("DevicePreview")
|
||||||
|
fake_device_preview.find_main_exchange_document = lambda *args, **kwargs: None
|
||||||
|
sys.modules["DevicePreview"] = fake_device_preview
|
||||||
|
|
||||||
|
|
||||||
|
class FakeViewObject:
|
||||||
|
def __init__(self):
|
||||||
|
self.Visibility = True
|
||||||
|
self.ShapeColor = None
|
||||||
|
|
||||||
|
|
||||||
|
class FakeShape:
|
||||||
|
def copy(self):
|
||||||
|
return FakeShape()
|
||||||
|
|
||||||
|
|
||||||
|
class FakeObject:
|
||||||
|
def __init__(self, name, type_id):
|
||||||
|
self.Name = name
|
||||||
|
self.Label = name
|
||||||
|
self.TypeId = type_id
|
||||||
|
self._deleted = False
|
||||||
|
self._raise_name_when_deleted = False
|
||||||
|
self._raise_group_when_deleted = False
|
||||||
|
self._raise_inlist_when_deleted = False
|
||||||
|
self.PropertiesList = []
|
||||||
|
self.Group = []
|
||||||
|
self.InList = []
|
||||||
|
self.Links = []
|
||||||
|
self.ViewObject = FakeViewObject()
|
||||||
|
self.Placement = sys.modules["FreeCAD"].Placement()
|
||||||
|
self.Shape = FakeShape()
|
||||||
|
|
||||||
|
def __getattribute__(self, name):
|
||||||
|
if name == "Name":
|
||||||
|
data = object.__getattribute__(self, "__dict__")
|
||||||
|
if data.get("_deleted") and data.get("_raise_name_when_deleted"):
|
||||||
|
raise RuntimeError("Cannot access attribute 'Name' of deleted object")
|
||||||
|
if name == "Group":
|
||||||
|
data = object.__getattribute__(self, "__dict__")
|
||||||
|
if data.get("_deleted") and data.get("_raise_group_when_deleted"):
|
||||||
|
raise RuntimeError("Cannot access attribute 'Group' of deleted object")
|
||||||
|
if name == "InList":
|
||||||
|
data = object.__getattribute__(self, "__dict__")
|
||||||
|
if data.get("_deleted") and data.get("_raise_inlist_when_deleted"):
|
||||||
|
raise RuntimeError("Cannot access attribute 'InList' of deleted object")
|
||||||
|
return object.__getattribute__(self, name)
|
||||||
|
|
||||||
|
def isDerivedFrom(self, type_name):
|
||||||
|
if self.TypeId == type_name:
|
||||||
|
return True
|
||||||
|
if type_name == "App::DocumentObjectGroup":
|
||||||
|
return self.TypeId in {"App::DocumentObjectGroup", "App::Part"}
|
||||||
|
if type_name == "App::LocalCoordinateSystem":
|
||||||
|
return self.TypeId in {"Part::LocalCoordinateSystem", "PartDesign::CoordinateSystem"}
|
||||||
|
return False
|
||||||
|
|
||||||
|
def addProperty(self, prop_type, prop_name, group_name, description):
|
||||||
|
if prop_name not in self.PropertiesList:
|
||||||
|
self.PropertiesList.append(prop_name)
|
||||||
|
|
||||||
|
def addObject(self, child):
|
||||||
|
if child not in self.Group:
|
||||||
|
self.Group.append(child)
|
||||||
|
if self not in child.InList:
|
||||||
|
child.InList.append(self)
|
||||||
|
for dependency in list(getattr(child, "Links", []) or []):
|
||||||
|
if dependency not in self.Group:
|
||||||
|
self.Group.append(dependency)
|
||||||
|
if self not in dependency.InList:
|
||||||
|
dependency.InList.append(self)
|
||||||
|
|
||||||
|
|
||||||
|
class FakeDocument:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
name,
|
||||||
|
filename="",
|
||||||
|
detach_on_remove=True,
|
||||||
|
raise_name_when_deleted=False,
|
||||||
|
raise_group_when_deleted=False,
|
||||||
|
raise_inlist_when_deleted=False,
|
||||||
|
):
|
||||||
|
self.Name = name
|
||||||
|
self.FileName = filename
|
||||||
|
self.Objects = []
|
||||||
|
self.detach_on_remove = detach_on_remove
|
||||||
|
self.raise_name_when_deleted = raise_name_when_deleted
|
||||||
|
self.raise_group_when_deleted = raise_group_when_deleted
|
||||||
|
self.raise_inlist_when_deleted = raise_inlist_when_deleted
|
||||||
|
|
||||||
|
def addObject(self, type_name, name):
|
||||||
|
obj = FakeObject(name, type_name)
|
||||||
|
obj._raise_name_when_deleted = self.raise_name_when_deleted
|
||||||
|
obj._raise_group_when_deleted = self.raise_group_when_deleted
|
||||||
|
obj._raise_inlist_when_deleted = self.raise_inlist_when_deleted
|
||||||
|
self.Objects.append(obj)
|
||||||
|
return obj
|
||||||
|
|
||||||
|
def getObject(self, name):
|
||||||
|
for obj in self.Objects:
|
||||||
|
if obj.Name == name:
|
||||||
|
return obj
|
||||||
|
return None
|
||||||
|
|
||||||
|
def removeObject(self, name):
|
||||||
|
target = self.getObject(name)
|
||||||
|
if target is None:
|
||||||
|
return
|
||||||
|
self.Objects = [obj for obj in self.Objects if obj is not target]
|
||||||
|
target._deleted = True
|
||||||
|
if self.detach_on_remove:
|
||||||
|
for obj in self.Objects:
|
||||||
|
if target in getattr(obj, "Group", []):
|
||||||
|
obj.Group.remove(target)
|
||||||
|
if target in getattr(obj, "InList", []):
|
||||||
|
obj.InList.remove(target)
|
||||||
|
|
||||||
|
def copyObject(self, source_obj, recursive):
|
||||||
|
copies = {}
|
||||||
|
|
||||||
|
def clone(obj):
|
||||||
|
if obj in copies:
|
||||||
|
return copies[obj]
|
||||||
|
copied = FakeObject(obj.Name, obj.TypeId)
|
||||||
|
copied._raise_name_when_deleted = self.raise_name_when_deleted
|
||||||
|
copied._raise_group_when_deleted = self.raise_group_when_deleted
|
||||||
|
copied._raise_inlist_when_deleted = self.raise_inlist_when_deleted
|
||||||
|
copied.Label = obj.Label
|
||||||
|
copied.PropertiesList = list(getattr(obj, "PropertiesList", []) or [])
|
||||||
|
copied.Placement = obj.Placement
|
||||||
|
for prop in copied.PropertiesList:
|
||||||
|
setattr(copied, prop, getattr(obj, prop, None))
|
||||||
|
self.Objects.append(copied)
|
||||||
|
copies[obj] = copied
|
||||||
|
if recursive:
|
||||||
|
copied.Links = [
|
||||||
|
clone(child)
|
||||||
|
for child in list(getattr(obj, "Links", []) or [])
|
||||||
|
]
|
||||||
|
for child in copied.Links:
|
||||||
|
if copied not in child.InList:
|
||||||
|
child.InList.append(copied)
|
||||||
|
for child in list(getattr(obj, "Group", []) or []):
|
||||||
|
copied.addObject(clone(child))
|
||||||
|
copied.OriginFeatures = [
|
||||||
|
clone(child)
|
||||||
|
for child in list(getattr(obj, "OriginFeatures", []) or [])
|
||||||
|
]
|
||||||
|
return copied
|
||||||
|
|
||||||
|
return clone(source_obj)
|
||||||
|
|
||||||
|
|
||||||
|
def _reload_modules():
|
||||||
|
for name in [
|
||||||
|
"DeviceImport",
|
||||||
|
"TemplateSemantics",
|
||||||
|
"TerminalObjects",
|
||||||
|
]:
|
||||||
|
sys.modules.pop(name, None)
|
||||||
|
device_import = importlib.import_module("DeviceImport")
|
||||||
|
template_semantics = importlib.import_module("TemplateSemantics")
|
||||||
|
return device_import, template_semantics
|
||||||
|
|
||||||
|
|
||||||
|
class FcstdDeviceImportTest(unittest.TestCase):
|
||||||
|
def test_fcstd_import_preserves_template_slots_without_live_template_lcs(self):
|
||||||
|
source = FakeDocument("Source", r"D:\models\breaker.FCStd")
|
||||||
|
_install_fake_freecad(source)
|
||||||
|
app = sys.modules["FreeCAD"]
|
||||||
|
|
||||||
|
body = source.addObject("Part::Feature", "Body")
|
||||||
|
terminal = source.addObject("Part::LocalCoordinateSystem", "Terminal_D1")
|
||||||
|
terminal.Label = "D1"
|
||||||
|
terminal.Placement = app.Placement(
|
||||||
|
app.Vector(11, 22, 33),
|
||||||
|
app.Rotation(app.Vector(0, 0, 1), 90),
|
||||||
|
)
|
||||||
|
terminal.addProperty("App::PropertyString", "Role", "QET Template", "")
|
||||||
|
terminal.Role = "Terminal"
|
||||||
|
terminal.addProperty("App::PropertyString", "QetTemplateSlotName", "QET Template", "")
|
||||||
|
terminal.QetTemplateSlotName = "D1"
|
||||||
|
|
||||||
|
x_axis = source.addObject("App::Line", "Terminal_D1_XAxis")
|
||||||
|
terminal.OriginFeatures = [x_axis]
|
||||||
|
terminal.addObject(x_axis)
|
||||||
|
|
||||||
|
doc = FakeDocument("QETScene")
|
||||||
|
device_group = doc.addObject("App::Part", "QETDevice_breaker")
|
||||||
|
|
||||||
|
device_import, template_semantics = _reload_modules()
|
||||||
|
|
||||||
|
copied_objects = device_import._import_fcstd_into_group(
|
||||||
|
doc,
|
||||||
|
device_group,
|
||||||
|
source.FileName,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual([body.Name], [obj.Name for obj in copied_objects])
|
||||||
|
self.assertEqual(["Body"], [obj.Name for obj in device_group.Group])
|
||||||
|
self.assertNotIn("Terminal_D1", [obj.Name for obj in doc.Objects])
|
||||||
|
self.assertNotIn("Terminal_D1_XAxis", [obj.Name for obj in doc.Objects])
|
||||||
|
self.assertIn("QetTemplateSlotsJson", device_group.PropertiesList)
|
||||||
|
|
||||||
|
slots = template_semantics.collect_terminal_hints(device_group)
|
||||||
|
|
||||||
|
self.assertEqual(1, len(slots))
|
||||||
|
self.assertEqual("D1", slots[0]["name"])
|
||||||
|
self.assertEqual(11.0, slots[0]["base"].x)
|
||||||
|
self.assertEqual(90.0, slots[0]["rotation"]["angle"])
|
||||||
|
self.assertIsNone(slots[0]["source_object"])
|
||||||
|
|
||||||
|
def test_fcstd_import_keeps_link_dependencies_out_of_device_group(self):
|
||||||
|
source = FakeDocument("Source", r"D:\models\breaker.FCStd")
|
||||||
|
_install_fake_freecad(source)
|
||||||
|
|
||||||
|
solid = source.addObject("Part::Feature", "Solid")
|
||||||
|
solid_001 = source.addObject("Part::Feature", "Solid001")
|
||||||
|
compound = source.addObject("Part::Compound2", "Compound")
|
||||||
|
compound.Links = [solid, solid_001]
|
||||||
|
solid.InList.append(compound)
|
||||||
|
solid_001.InList.append(compound)
|
||||||
|
|
||||||
|
doc = FakeDocument("QETScene")
|
||||||
|
device_group = doc.addObject("App::Part", "QETDevice_breaker")
|
||||||
|
|
||||||
|
device_import, _ = _reload_modules()
|
||||||
|
|
||||||
|
copied_objects = device_import._import_fcstd_into_group(
|
||||||
|
doc,
|
||||||
|
device_group,
|
||||||
|
source.FileName,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(1, len(copied_objects))
|
||||||
|
self.assertEqual("Part::Feature", copied_objects[0].TypeId)
|
||||||
|
self.assertEqual("Compound", copied_objects[0].Label)
|
||||||
|
self.assertEqual(copied_objects, device_group.Group)
|
||||||
|
self.assertEqual([], copied_objects[0].Links)
|
||||||
|
self.assertIsNone(doc.getObject("Compound"))
|
||||||
|
self.assertIsNone(doc.getObject("Solid"))
|
||||||
|
self.assertIsNone(doc.getObject("Solid001"))
|
||||||
|
|
||||||
|
def test_fcstd_import_restores_target_document_after_closing_source_doc(self):
|
||||||
|
source = FakeDocument("Source", r"D:\models\breaker.FCStd")
|
||||||
|
_install_fake_freecad(source)
|
||||||
|
app = sys.modules["FreeCAD"]
|
||||||
|
|
||||||
|
source.addObject("Part::Feature", "Body")
|
||||||
|
|
||||||
|
doc = FakeDocument("QETScene")
|
||||||
|
device_group = doc.addObject("App::Part", "QETDevice_breaker")
|
||||||
|
|
||||||
|
device_import, _ = _reload_modules()
|
||||||
|
|
||||||
|
device_import._import_fcstd_into_group(
|
||||||
|
doc,
|
||||||
|
device_group,
|
||||||
|
source.FileName,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertIs(app.ActiveDocument, doc)
|
||||||
|
self.assertIn("QETScene", app.set_active_document_calls)
|
||||||
|
|
||||||
|
def test_non_fcstd_import_clears_stored_template_slots_from_previous_fcstd(self):
|
||||||
|
source = FakeDocument("Source", r"D:\models\breaker.FCStd")
|
||||||
|
_install_fake_freecad(source)
|
||||||
|
|
||||||
|
doc = FakeDocument("QETScene")
|
||||||
|
device_group = doc.addObject("App::Part", "QETDevice_breaker")
|
||||||
|
device_group.addProperty(
|
||||||
|
"App::PropertyString",
|
||||||
|
"QetTemplateSlotsJson",
|
||||||
|
"QET Exchange",
|
||||||
|
"",
|
||||||
|
)
|
||||||
|
device_group.QetTemplateSlotsJson = (
|
||||||
|
'{"terminal_slots":[{"name":"D1","label":"D1","base":[1,2,3]}]}'
|
||||||
|
)
|
||||||
|
|
||||||
|
device_import, template_semantics = _reload_modules()
|
||||||
|
|
||||||
|
def insert_step_body(name, docName, merge, useLinkGroup):
|
||||||
|
doc.addObject("Part::Feature", "StepBody")
|
||||||
|
|
||||||
|
device_import.ImportGui.insert = insert_step_body
|
||||||
|
|
||||||
|
copied_objects = device_import._import_model_into_group(
|
||||||
|
doc,
|
||||||
|
device_group,
|
||||||
|
r"D:\models\breaker.step",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(["StepBody"], [obj.Name for obj in copied_objects])
|
||||||
|
self.assertEqual("", device_group.QetTemplateSlotsJson)
|
||||||
|
self.assertEqual([], template_semantics.collect_terminal_hints(device_group))
|
||||||
|
|
||||||
|
def test_fcstd_import_detaches_removed_template_lcs_from_parent_group(self):
|
||||||
|
source = FakeDocument("Source", r"D:\models\breaker.FCStd")
|
||||||
|
_install_fake_freecad(source)
|
||||||
|
app = sys.modules["FreeCAD"]
|
||||||
|
|
||||||
|
body = source.addObject("Part::Feature", "Body")
|
||||||
|
terminal = source.addObject("Part::LocalCoordinateSystem", "Terminal_D1")
|
||||||
|
terminal.Placement = app.Placement(app.Vector(1, 2, 3), app.Rotation())
|
||||||
|
terminal.addProperty("App::PropertyString", "Role", "QET Template", "")
|
||||||
|
terminal.Role = "Terminal"
|
||||||
|
terminal.addProperty("App::PropertyString", "QetTemplateSlotName", "QET Template", "")
|
||||||
|
terminal.QetTemplateSlotName = "D1"
|
||||||
|
|
||||||
|
doc = FakeDocument("QETScene", detach_on_remove=False)
|
||||||
|
device_group = doc.addObject("App::Part", "QETDevice_breaker")
|
||||||
|
|
||||||
|
device_import, _ = _reload_modules()
|
||||||
|
|
||||||
|
copied_objects = device_import._import_fcstd_into_group(
|
||||||
|
doc,
|
||||||
|
device_group,
|
||||||
|
source.FileName,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual([body.Name], [obj.Name for obj in copied_objects])
|
||||||
|
self.assertEqual(["Body"], [obj.Name for obj in device_group.Group])
|
||||||
|
|
||||||
|
def test_fcstd_import_does_not_revisit_deleted_origin_features(self):
|
||||||
|
source = FakeDocument("Source", r"D:\models\breaker.FCStd")
|
||||||
|
_install_fake_freecad(source)
|
||||||
|
app = sys.modules["FreeCAD"]
|
||||||
|
|
||||||
|
body = source.addObject("Part::Feature", "Body")
|
||||||
|
terminal = source.addObject("Part::LocalCoordinateSystem", "Terminal_D1")
|
||||||
|
terminal.Placement = app.Placement(app.Vector(1, 2, 3), app.Rotation())
|
||||||
|
terminal.addProperty("App::PropertyString", "Role", "QET Template", "")
|
||||||
|
terminal.Role = "Terminal"
|
||||||
|
terminal.addProperty("App::PropertyString", "QetTemplateSlotName", "QET Template", "")
|
||||||
|
terminal.QetTemplateSlotName = "D1"
|
||||||
|
|
||||||
|
x_axis = source.addObject("App::Line", "Terminal_D1_XAxis")
|
||||||
|
terminal.OriginFeatures = [x_axis]
|
||||||
|
terminal.addObject(x_axis)
|
||||||
|
|
||||||
|
doc = FakeDocument("QETScene", raise_group_when_deleted=True)
|
||||||
|
device_group = doc.addObject("App::Part", "QETDevice_breaker")
|
||||||
|
|
||||||
|
device_import, _ = _reload_modules()
|
||||||
|
|
||||||
|
copied_objects = device_import._import_fcstd_into_group(
|
||||||
|
doc,
|
||||||
|
device_group,
|
||||||
|
source.FileName,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual([body.Name], [obj.Name for obj in copied_objects])
|
||||||
|
self.assertEqual(["Body"], [obj.Name for obj in device_group.Group])
|
||||||
|
|
||||||
|
def test_fcstd_import_does_not_touch_inlist_after_origin_feature_deleted(self):
|
||||||
|
source = FakeDocument("Source", r"D:\models\breaker.FCStd")
|
||||||
|
_install_fake_freecad(source)
|
||||||
|
app = sys.modules["FreeCAD"]
|
||||||
|
|
||||||
|
body = source.addObject("Part::Feature", "Body")
|
||||||
|
terminal = source.addObject("Part::LocalCoordinateSystem", "Terminal_D1")
|
||||||
|
terminal.Placement = app.Placement(app.Vector(1, 2, 3), app.Rotation())
|
||||||
|
terminal.addProperty("App::PropertyString", "Role", "QET Template", "")
|
||||||
|
terminal.Role = "Terminal"
|
||||||
|
terminal.addProperty("App::PropertyString", "QetTemplateSlotName", "QET Template", "")
|
||||||
|
terminal.QetTemplateSlotName = "D1"
|
||||||
|
|
||||||
|
x_axis = source.addObject("App::Line", "Terminal_D1_XAxis")
|
||||||
|
terminal.OriginFeatures = [x_axis]
|
||||||
|
terminal.addObject(x_axis)
|
||||||
|
|
||||||
|
doc = FakeDocument("QETScene", raise_inlist_when_deleted=True)
|
||||||
|
device_group = doc.addObject("App::Part", "QETDevice_breaker")
|
||||||
|
|
||||||
|
device_import, _ = _reload_modules()
|
||||||
|
|
||||||
|
copied_objects = device_import._import_fcstd_into_group(
|
||||||
|
doc,
|
||||||
|
device_group,
|
||||||
|
source.FileName,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual([body.Name], [obj.Name for obj in copied_objects])
|
||||||
|
self.assertEqual(["Body"], [obj.Name for obj in device_group.Group])
|
||||||
|
|
||||||
|
def test_fcstd_import_does_not_read_name_from_deleted_template_lcs_when_returning_objects(self):
|
||||||
|
source = FakeDocument("Source", r"D:\models\breaker.FCStd")
|
||||||
|
_install_fake_freecad(source)
|
||||||
|
app = sys.modules["FreeCAD"]
|
||||||
|
|
||||||
|
body = source.addObject("Part::Feature", "Body")
|
||||||
|
terminal = source.addObject("Part::LocalCoordinateSystem", "Terminal_D1")
|
||||||
|
terminal.Placement = app.Placement(app.Vector(1, 2, 3), app.Rotation())
|
||||||
|
terminal.addProperty("App::PropertyString", "Role", "QET Template", "")
|
||||||
|
terminal.Role = "Terminal"
|
||||||
|
terminal.addProperty("App::PropertyString", "QetTemplateSlotName", "QET Template", "")
|
||||||
|
terminal.QetTemplateSlotName = "D1"
|
||||||
|
|
||||||
|
doc = FakeDocument("QETScene", raise_name_when_deleted=True)
|
||||||
|
device_group = doc.addObject("App::Part", "QETDevice_breaker")
|
||||||
|
|
||||||
|
device_import, _ = _reload_modules()
|
||||||
|
|
||||||
|
copied_objects = device_import._import_fcstd_into_group(
|
||||||
|
doc,
|
||||||
|
device_group,
|
||||||
|
source.FileName,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual([body.Name], [obj.Name for obj in copied_objects])
|
||||||
|
self.assertEqual(["Body"], [obj.Name for obj in device_group.Group])
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
Loading…
Reference in New Issue