Implement identifier, desc, and instructions for specification node in IDS

This commit is contained in:
Dion Moult
2022-05-10 19:26:12 +10:00
parent a24c4b269a
commit ae298de8dc
2 changed files with 145 additions and 82 deletions
+26 -14
View File
@@ -49,7 +49,7 @@ class ids:
def __init__( def __init__(
self, self,
title="Title", title="Untitled",
copyright=None, copyright=None,
version=None, version=None,
description=None, description=None,
@@ -79,7 +79,7 @@ class ids:
""" """
self.specifications = [] self.specifications = []
self.info = {} self.info = {}
self.info["title"] = title or "Unnamed" self.info["title"] = title or "Untitled"
if copyright: if copyright:
self.info["copyright"] = copyright self.info["copyright"] = copyright
if version: if version:
@@ -211,7 +211,9 @@ class ids:
class specification: class specification:
"""Represents the XML <specification> node and its two children <applicability> and <requirements>""" """Represents the XML <specification> node and its two children <applicability> and <requirements>"""
def __init__(self, name="Specification", use="required", ifcVersion="IFC2X3"): def __init__(
self, name="Unnamed", use="required", ifcVersion="IFC2X3", identifier=None, description=None, instructions=None
):
"""Create a specification to be added in ids. """Create a specification to be added in ids.
:param name:, defaults to "Specification" :param name:, defaults to "Specification"
@@ -219,11 +221,14 @@ class specification:
:param use: 'required'|'optional', defaults to "required" :param use: 'required'|'optional', defaults to "required"
:type use: str, optional :type use: str, optional
""" """
self.name = name self.name = name or "Unnamed"
self.applicability = None self.applicability = None
self.requirements = None self.requirements = None
self.ifcVersion = ifcVersion
self.use = use self.use = use
self.ifcVersion = ifcVersion
self.identifier = identifier
self.description = description
self.instructions = instructions
def asdict(self): def asdict(self):
"""Converts object to a dictionary, adding required attributes. """Converts object to a dictionary, adding required attributes.
@@ -232,21 +237,28 @@ class specification:
:rtype: dict :rtype: dict
""" """
# if older python collections.OrderedDict() # if older python collections.OrderedDict()
spec_dict = { results = {
"@name": self.name, "@name": self.name,
"@use": self.use, "@use": self.use,
"@ifcVersion": self.ifcVersion, "@ifcVersion": self.ifcVersion,
"applicability": {}, "applicability": {},
"requirements": {}, "requirements": {},
} }
for x in ["applicability", "requirements"]: for attribute in ["identifier", "description", "instructions"]:
for fac in (getattr(self, x)).terms: value = getattr(self, attribute)
if value:
results[f"@{attribute}"] = value
for clause_type in ["applicability", "requirements"]:
clause = getattr(self, clause_type)
if not clause:
continue
for fac in clause.terms:
fclass = type(fac).__name__ fclass = type(fac).__name__
if fclass in spec_dict[x]: if fclass in results[clause_type]:
spec_dict[x][fclass].append(fac.asdict()) results[clause_type][fclass].append(fac.asdict())
else: else:
spec_dict[x][fclass] = [fac.asdict()] results[clause_type][fclass] = [fac.asdict()]
return spec_dict return results
@staticmethod @staticmethod
def parse(ids_dict): def parse(ids_dict):
@@ -417,7 +429,7 @@ class facet(metaclass=meta_facet):
def __getattr__(self, attr): def __getattr__(self, attr):
if attr in getattr(self, 'node', None): if attr in getattr(self, "node", None):
v = self.node[attr] v = self.node[attr]
# BUG list of dictionaries should not happen # BUG list of dictionaries should not happen
@@ -753,7 +765,7 @@ class partOf(facet):
# }, # what if not first item of refs? # }, # what if not first item of refs?
# ) # )
else: else:
return facet_evaluation(False, "is not a part of %s" % self.node['@entity']) return facet_evaluation(False, "is not a part of %s" % self.node["@entity"])
class property(facet): class property(facet):
+86 -35
View File
@@ -17,10 +17,11 @@
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>. # along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
import os import os
import pytest
import logging import logging
import unittest import unittest
import tempfile import tempfile
import requests import xmlschema
from bcf import bcfxml from bcf import bcfxml
import ifcopenshell import ifcopenshell
from ifcopenshell import ids from ifcopenshell import ids
@@ -163,8 +164,15 @@ class TestIdsAuthoring(unittest.TestCase):
# TODO test this without resorting to hooking into logger output # TODO test this without resorting to hooking into logger output
def test_create_an_ids_with_minimal_information(self): def test_create_an_ids_with_minimal_information(self):
specs = ids.ids(title="title") specs = ids.ids()
assert specs.info == {"title": "title"} assert specs.asdict() == {
"@xmlns": "http://standards.buildingsmart.org/IDS",
"@xmlns:xs": "http://www.w3.org/2001/XMLSchema",
"@xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
"@xsi:schemaLocation": "http://standards.buildingsmart.org/IDS/ids_05.xsd",
"info": {"title": "Untitled"},
"specifications": [],
}
def test_create_an_ids_with_all_possible_information(self): def test_create_an_ids_with_all_possible_information(self):
specs = ids.ids( specs = ids.ids(
@@ -177,22 +185,83 @@ class TestIdsAuthoring(unittest.TestCase):
purpose="purpose", purpose="purpose",
milestone="milestone", milestone="milestone",
) )
assert specs.info["title"] == "title" assert specs.asdict() == {
assert specs.info["copyright"] == "copyright" "@xmlns": "http://standards.buildingsmart.org/IDS",
assert specs.info["version"] == "version" "@xmlns:xs": "http://www.w3.org/2001/XMLSchema",
assert specs.info["description"] == "description" "@xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
assert specs.info["author"] == "author@test.com" "@xsi:schemaLocation": "http://standards.buildingsmart.org/IDS/ids_05.xsd",
assert specs.info["date"] == "2020-01-01" "info": {
assert specs.info["purpose"] == "purpose" "title": "title",
assert specs.info["milestone"] == "milestone" "copyright": "copyright",
"version": "version",
"description": "description",
"author": "author@test.com",
"date": "2020-01-01",
"purpose": "purpose",
"milestone": "milestone",
},
"specifications": [],
}
def test_check_invalid_ids_information(self): def test_check_invalid_ids_information(self):
specs = ids.ids(title=None) specs = ids.ids(title=None, author="author", date="9999-99-99")
assert specs.info["title"] == "Unnamed" assert specs.asdict() == {
specs = ids.ids(author="author") "@xmlns": "http://standards.buildingsmart.org/IDS",
assert not specs.info.get("author") "@xmlns:xs": "http://www.w3.org/2001/XMLSchema",
specs = ids.ids(date="9999-99-99") "@xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
assert not specs.info.get("date") "@xsi:schemaLocation": "http://standards.buildingsmart.org/IDS/ids_05.xsd",
"info": {"title": "Untitled"},
"specifications": [],
}
def test_authoring_an_ids_with_no_specifications_is_invalid(self):
specs = ids.ids()
with pytest.raises(xmlschema.validators.exceptions.XMLSchemaChildrenValidationError):
specs.to_string()
def test_create_specification_with_minimal_information(self):
spec = ids.specification()
assert spec.asdict() == {
"@name": "Unnamed",
"@use": "required",
"@ifcVersion": "IFC2X3", # :(
"applicability": {},
"requirements": {},
}
def test_create_specification_with_all_possible_information(self):
spec = ids.specification(
name="name",
use="use",
ifcVersion="version",
identifier="identifier",
description="description",
instructions="instructions",
)
assert spec.asdict() == {
"@name": "name",
"@use": "use",
"@ifcVersion": "version",
"@identifier": "identifier",
"@description": "description",
"@instructions": "instructions",
"applicability": {},
"requirements": {},
}
def test_ids_add_content(self):
i = ids.ids(title="My IDS")
i.specifications.append(ids.specification(name="Test_Specification"))
self.assertEqual(i.specifications[0].name, "Test_Specification")
m = ids.material.create(location="any", value="Test_Value")
i.specifications[0].add_applicability(m)
self.assertEqual(i.specifications[0].applicability.terms[0].value, "Test_Value")
i.specifications[0].add_applicability(m)
self.assertEqual(i.specifications[0].applicability.terms[1].value, "Test_Value")
i.specifications[0].add_requirement(m)
self.assertEqual(i.specifications[0].requirements.terms[0].value, "Test_Value")
i.specifications[0].add_requirement(m)
self.assertEqual(i.specifications[0].requirements.terms[1].value, "Test_Value")
def test_entity_create(self): def test_entity_create(self):
e = ids.entity.create(name="Test_Name", predefinedType="Test_PredefinedType") e = ids.entity.create(name="Test_Name", predefinedType="Test_PredefinedType")
@@ -229,24 +298,6 @@ class TestIdsAuthoring(unittest.TestCase):
self.assertEqual(m.location, "any") self.assertEqual(m.location, "any")
self.assertEqual(m.value, "Test_Value") self.assertEqual(m.value, "Test_Value")
def test_specification_create(self):
s = ids.specification(name="Test_Specification")
self.assertEqual(s.name, "Test_Specification")
def test_ids_add_content(self):
i = ids.ids(title="My IDS")
i.specifications.append(ids.specification(name="Test_Specification"))
self.assertEqual(i.specifications[0].name, "Test_Specification")
m = ids.material.create(location="any", value="Test_Value")
i.specifications[0].add_applicability(m)
self.assertEqual(i.specifications[0].applicability.terms[0].value, "Test_Value")
i.specifications[0].add_applicability(m)
self.assertEqual(i.specifications[0].applicability.terms[1].value, "Test_Value")
i.specifications[0].add_requirement(m)
self.assertEqual(i.specifications[0].requirements.terms[0].value, "Test_Value")
i.specifications[0].add_requirement(m)
self.assertEqual(i.specifications[0].requirements.terms[1].value, "Test_Value")
""" Creating IDS with restrictions """ """ Creating IDS with restrictions """
def test_create_restrictions_enumeration(self): def test_create_restrictions_enumeration(self):