Skip to content

Commit

Permalink
Use traverser in importer and add test cases- (Task #5)
Browse files Browse the repository at this point in the history
Try to use the traverser in the importer and reactivating the
full_import test case showed problems with assemblies having the same
name and uuid as their part.
To further investigate that, test cases were added in the traverser.

---
Task #5: Implement Import Functionality
  • Loading branch information
JAmmermann-DLR committed Dec 2, 2019
1 parent e7af193 commit 694b1dd
Show file tree
Hide file tree
Showing 6 changed files with 373 additions and 52 deletions.
24 changes: 6 additions & 18 deletions VirtualSatelliteCAD/json_io/json_importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,11 @@
import FreeCADGui
from freecad.active_document import ActiveDocument
from json_io.parts.json_part_factory import JsonPartFactory
from json_io.products.json_product_assembly import JsonProductAssembly
from json_io.json_definitions import get_part_name_uuid
from json_io.products.json_product_assembly_tree_traverser import JsonProductAssemblyTreeTraverser
from json_io.json_definitions import get_part_name_uuid, JSON_PRODUCTS, JSON_PARTS

import json
from freecad import active_document

App = FreeCAD
Gui = FreeCADGui
Expand Down Expand Up @@ -89,27 +90,14 @@ def full_import(self, filepath):
Log("Please provide a valid JSON\n")
return

json_parts = json_object['Parts']
json_parts = json_object[JSON_PARTS]

part_file_names = []
for part in json_parts:
part_file_names.append(self.create_or_update_part(part))

# json assembly with json product object
json_product = JsonProductAssembly().parse_from_json(json_object['Products'])

# name the freecad document after the root product
freecad_name = json_product.name

# If there is a root document with the same name open already:
# assume that all changes of the current import are valid (CRUD)
# so clear the document
ActiveDocument(self.working_output_directory).clear_if_open_document(freecad_name)

active_document = ActiveDocument(self.working_output_directory).open_set_and_get_document(freecad_name)
json_product.write_to_freecad(active_document)

active_document.save_as(freecad_name)
traverser = JsonProductAssemblyTreeTraverser(self.working_output_directory)
json_product, active_document = traverser.traverse_and_parse_from_json(json_object[JSON_PRODUCTS])

Log(f"Import successful\n")

Expand Down
20 changes: 12 additions & 8 deletions VirtualSatelliteCAD/json_io/json_spread_sheet.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,18 @@ def write_to_freecad(self, active_document):
sheet_line = FREECAD_PART_SHEET_ATTRIBUTE_START_LINE
for json_part_attribute_name in list(self._json_part_or_product.attributes.keys()):

json_part_attribute_value = str(getattr(self._json_part_or_product, json_part_attribute_name))
json_part_attribute_unit = self._json_part_or_product.attributes[json_part_attribute_name]

sheet.set("A" + str(sheet_line), json_part_attribute_name)
sheet.set("B" + str(sheet_line), json_part_attribute_value)
sheet.set("C" + str(sheet_line), json_part_attribute_unit)

sheet_line += 1
# TODO: added this try catch because some children would not have part_name and attribute (because they are assemblies)
try:
json_part_attribute_value = str(getattr(self._json_part_or_product, json_part_attribute_name))
json_part_attribute_unit = self._json_part_or_product.attributes[json_part_attribute_name]

sheet.set("A" + str(sheet_line), json_part_attribute_name)
sheet.set("B" + str(sheet_line), json_part_attribute_value)
sheet.set("C" + str(sheet_line), json_part_attribute_unit)

sheet_line += 1
except AttributeError as e:
print(e)

# Recompute the sheet, so that all properties are correctly written
# if not recomputed accessing the properties will result in none objects
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,11 @@ def traverse(self, json_object, depth=0):
# if the current depth has no list in the _lst_of_depths, add it
if(len(self._lst_of_depths) < depth + 1):
self._lst_of_depths.append([])
Log(f"Added depth {depth} to _lst_of_depths")
Log(f"Added depth {depth} to _lst_of_depths\n")

# append found assembly to the list
self._lst_of_depths[depth].append(json_object)
Log(f"Found assembly '{json_object[JSON_ELEMENT_NAME]}' at {depth}")
Log(f"Found assembly '{json_object[JSON_ELEMENT_NAME]}' at {depth}\n")

# recursive call on all children
for child in json_object[JSON_ELEMNT_CHILDREN]:
Expand All @@ -65,19 +65,23 @@ def parse_from_json(self):
"""
Iterate through the list created by traversing the tree in reverse and parse the found product assemblies
"""
json_product = None
json_product, active_document = None, None

# parse in reverse order
for depth in reversed(self._lst_of_depths):
for assembly in depth:
Log(f"Parsing '{assembly[JSON_ELEMENT_NAME]}'")
Log(f"Parsing '{assembly[JSON_ELEMENT_NAME]}'\n")

json_product = JsonProductAssembly().parse_from_json(assembly)
active_document = ActiveDocument(self.working_output_directory).open_set_and_get_document(json_product.get_unique_name())
json_product.write_to_freecad(active_document)
active_document.save_as(json_product.get_unique_name())
active_document.save_and_close_active_document(json_product.get_unique_name()) # + "_assembly")

return json_product
# the last json_product is the root of the assembly, open it again for the UI
if(json_product is not None):
active_document = ActiveDocument(self.working_output_directory).open_set_and_get_document(json_product.get_unique_name())

return json_product, active_document

def traverse_and_parse_from_json(self, json_object):
self.traverse(json_object)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,16 @@
# SPDX-License-Identifier: LGPL-3.0-or-later
#
from test.test_setup import AWorkingDirectoryTest
from test.json_io.test_json_data import TEST_JSON_PRODUCT_WITH_CHILDREN_WITH_CHILD, TEST_JSON_PRODUCT_WITHOUT_CHILDREN
from test.json_io.test_json_data import TEST_JSON_PRODUCT_WITH_CHILDREN_WITH_CHILD, TEST_JSON_PRODUCT_WITHOUT_CHILDREN, \
TEST_JSON_FULL_VISCUBE, TEST_JSON_PRODUCT_WITH_CHILDREN_WITH_CHILD_SUBASSEMBLY_IS_NO_PART, \
TEST_JSON_PRODUCT_SUBASSEMBLY_WITH_SAME_PART
import json
from json_io.products.json_product_assembly_tree_traverser import JsonProductAssemblyTreeTraverser
from json_io.json_definitions import JSON_ELEMENT_NAME
from freecad.active_document import ActiveDocument
import unittest
import glob
import os


class TestJsonProductAssemblyTreeTraverser(AWorkingDirectoryTest):
Expand All @@ -36,6 +41,11 @@ def setUpClass(cls):
def tearDown(self):
super().tearDown()

def clearWorkingDirectory(self):
filelist = glob.glob(os.path.join(self._WORKING_DIRECTORY, "*"))
for f in filelist:
os.remove(f)

def test_traverse_json(self):
json_data = TEST_JSON_PRODUCT_WITH_CHILDREN_WITH_CHILD
self.create_Test_Part()
Expand All @@ -55,7 +65,7 @@ def test_traverse_json(self):
def test_parse_json_from_tree_without_traversing(self):

traverser = JsonProductAssemblyTreeTraverser(self._WORKING_DIRECTORY)
self.assertIsNone(traverser.parse_from_json(), "Parsing no read in json object will result in 'None'")
self.assertIsNone(traverser.parse_from_json()[0], "Parsing no read in json object will result in 'None'")

def test_traverse_and_parse_json_tree(self):
json_data = TEST_JSON_PRODUCT_WITH_CHILDREN_WITH_CHILD
Expand All @@ -78,6 +88,73 @@ def test_traverse_and_parse_json_tree(self):
active_document = ActiveDocument(self._WORKING_DIRECTORY).open_set_and_get_document("BasePlateBottom1_e8794f3d_86ec_44c5_9618_8b7170c45484")
self.assertEquals(len(active_document.app_active_document.RootObjects), 6, "Found correct amount of root objects 3 objects plus 3 sheets")

def test_traverse_and_parse_json_tree_subassembly_no_part(self):
self.clearWorkingDirectory()
json_data = TEST_JSON_PRODUCT_WITH_CHILDREN_WITH_CHILD_SUBASSEMBLY_IS_NO_PART
self.create_Test_Part()

json_object = json.loads(json_data)

traverser = JsonProductAssemblyTreeTraverser(self._WORKING_DIRECTORY)
traverser.traverse(json_object)
lst_of_depths = traverser._lst_of_depths

self.assertEqual(len(lst_of_depths), 2, "Found the right amount of 2 assemblies")

traverser.parse_from_json()

# in this test case the product assembly "BasePlateBottom2" only has a child and not a part reference
active_document = ActiveDocument(self._WORKING_DIRECTORY).open_set_and_get_document("BasePlateBottom2_e8794f3d_86ec_44c5_9618_8b7170c45484")
self.assertEquals(len(active_document.app_active_document.RootObjects), 2, "Found correct amount of root objects 1 objects plus 1 sheets")

active_document = ActiveDocument(self._WORKING_DIRECTORY).open_set_and_get_document("BasePlateBottom1_e8794f3d_86ec_44c5_9618_8b7170c45484")
self.assertEquals(len(active_document.app_active_document.RootObjects), 6, "Found correct amount of root objects 3 objects plus 3 sheets")

def test_traverse_and_parse_json_tree_subassembly_same_part(self):
self.clearWorkingDirectory()
json_data = TEST_JSON_PRODUCT_SUBASSEMBLY_WITH_SAME_PART
self.create_Test_Part()

json_object = json.loads(json_data)

traverser = JsonProductAssemblyTreeTraverser(self._WORKING_DIRECTORY)
traverser.traverse(json_object)
lst_of_depths = traverser._lst_of_depths

self.assertEqual(len(lst_of_depths), 2, "Found the right amount of 2 assemblies")

traverser.parse_from_json()

# in this test case the product assembly "BasePlateBottom2" only has a child and not a part reference
active_document = ActiveDocument(self._WORKING_DIRECTORY).open_set_and_get_document("BasePlate_3d3708fd_5c6c_4af9_b710_d68778466084")
self.assertEquals(len(active_document.app_active_document.RootObjects), 4, "Found correct amount of root objects 2 objects plus 2 sheets")

active_document = ActiveDocument(self._WORKING_DIRECTORY).open_set_and_get_document("BasePlateBottom1_e8794f3d_86ec_44c5_9618_8b7170c45484")
self.assertEquals(len(active_document.app_active_document.RootObjects), 6, "Found correct amount of root objects 3 objects plus 3 sheets")

# TODO remove/adapt
@unittest.SkipTest
def test_traverse_and_parse_json_tree3(self):
json_data = TEST_JSON_FULL_VISCUBE
self.create_Test_Part()

json_object = json.loads(json_data)

traverser = JsonProductAssemblyTreeTraverser(self._WORKING_DIRECTORY)
traverser.traverse(json_object)
lst_of_depths = traverser._lst_of_depths

self.assertEqual(len(lst_of_depths), 2, "Found the right amount of 2 assemblies")

traverser.parse_from_json()

# this should have similar results to test_create_part_product_assembly_and_subassembly_with_root_part_manual in TestJsonProductAssembly
active_document = ActiveDocument(self._WORKING_DIRECTORY).open_set_and_get_document("BeamStructure_2afb23c9_f458_4bdb_a4e7_fc863364644f")
self.assertEquals(len(active_document.app_active_document.RootObjects), 6, "Found correct amount of root objects 3 objects plus 3 sheets")

active_document = ActiveDocument(self._WORKING_DIRECTORY).open_set_and_get_document("SpaceCube_a3533e02_125c_4066_bffe_d046d8d8342a")
self.assertEquals(len(active_document.app_active_document.RootObjects), 10, "Found correct amount of root objects 5 objects plus 5 sheets")

def test_traverse_and_parse_json_tree_rootassembly_without_children(self):
json_data = TEST_JSON_PRODUCT_WITHOUT_CHILDREN
self.create_Test_Part()
Expand All @@ -87,4 +164,4 @@ def test_traverse_and_parse_json_tree_rootassembly_without_children(self):
traverser = JsonProductAssemblyTreeTraverser(self._WORKING_DIRECTORY)
traverser.traverse_and_parse_from_json(json_object)

self.assertIsNone(traverser.parse_from_json())
self.assertIsNone(traverser.parse_from_json()[0], "Parsing a json object without children")
Loading

0 comments on commit 694b1dd

Please sign in to comment.