mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 17:31:45 +00:00
document.assign_document - support batching #4474
This commit is contained in:
@@ -109,7 +109,7 @@ def remove_document(ifc, document_tool, document=None):
|
||||
|
||||
|
||||
def assign_document(ifc, product=None, document=None):
|
||||
ifc.run("document.assign_document", product=product, document=document)
|
||||
ifc.run("document.assign_document", products=[product], document=document)
|
||||
|
||||
|
||||
def unassign_document(ifc, product=None, document=None):
|
||||
|
||||
@@ -241,7 +241,7 @@ def add_drawing(ifc, collector, drawing, target_view=None, location_hint=None):
|
||||
attributes = {"Identification": "X", "Name": drawing_name, "Scope": "DRAWING"}
|
||||
ifc.run("document.edit_information", information=information, attributes=attributes)
|
||||
ifc.run("document.edit_reference", reference=reference, attributes={"Location": uri})
|
||||
ifc.run("document.assign_document", product=element, document=reference)
|
||||
ifc.run("document.assign_document", products=[element], document=reference)
|
||||
drawing.import_drawings()
|
||||
|
||||
|
||||
@@ -276,7 +276,7 @@ def duplicate_drawing(ifc, drawing_tool, drawing=None, should_duplicate_annotati
|
||||
attributes = {"Identification": "X", "Name": drawing_name, "Scope": "DRAWING"}
|
||||
ifc.run("document.edit_information", information=information, attributes=attributes)
|
||||
ifc.run("document.edit_reference", reference=reference, attributes={"Location": uri})
|
||||
ifc.run("document.assign_document", product=new_drawing, document=reference)
|
||||
ifc.run("document.assign_document", products=[new_drawing], document=reference)
|
||||
|
||||
drawing_tool.import_drawings()
|
||||
return new_drawing
|
||||
|
||||
@@ -133,7 +133,7 @@ class TestRemoveDocument:
|
||||
|
||||
class TestAssignDocument:
|
||||
def test_run(self, ifc):
|
||||
ifc.run("document.assign_document", product="product", document="document").should_be_called()
|
||||
ifc.run("document.assign_document", products=["product"], document="document").should_be_called()
|
||||
subject.assign_document(ifc, product="product", document="document")
|
||||
|
||||
|
||||
|
||||
@@ -365,7 +365,7 @@ class TestAddDrawing:
|
||||
attributes={"Identification": "X", "Name": "name", "Scope": "DRAWING"},
|
||||
).should_be_called()
|
||||
ifc.run("document.edit_reference", reference="reference", attributes={"Location": "uri"}).should_be_called()
|
||||
ifc.run("document.assign_document", product="element", document="reference").should_be_called()
|
||||
ifc.run("document.assign_document", products=["element"], document="reference").should_be_called()
|
||||
drawing.import_drawings().should_be_called()
|
||||
subject.add_drawing(ifc, collector, drawing, target_view="target_view", location_hint="location_hint")
|
||||
|
||||
@@ -405,7 +405,7 @@ class TestDuplicateDrawing:
|
||||
ifc.run(
|
||||
"document.edit_reference", reference="reference", attributes={"Location": "drawing_path"}
|
||||
).should_be_called()
|
||||
ifc.run("document.assign_document", product="new_drawing", document="reference").should_be_called()
|
||||
ifc.run("document.assign_document", products=["new_drawing"], document="reference").should_be_called()
|
||||
|
||||
drawing.import_drawings().should_be_called()
|
||||
subject.duplicate_drawing(ifc, drawing, drawing="drawing", should_duplicate_annotations=True)
|
||||
|
||||
@@ -99,6 +99,9 @@ ARGUMENTS_DEPRECATION = {
|
||||
"library.unassign_reference": partial(
|
||||
batching_argument_deprecation, prev_argument="product", new_argument="products"
|
||||
),
|
||||
"document.assign_document": partial(
|
||||
batching_argument_deprecation, prev_argument="product", new_argument="products"
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -17,11 +17,19 @@
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.util.element
|
||||
from typing import Union
|
||||
|
||||
|
||||
class Usecase:
|
||||
def __init__(self, file, product=None, document=None):
|
||||
"""Assigns a document to a product
|
||||
def __init__(
|
||||
self,
|
||||
file: ifcopenshell.file,
|
||||
products: list[ifcopenshell.entity_instance],
|
||||
document: ifcopenshell.entity_instance,
|
||||
):
|
||||
"""Assigns a document to a list of products
|
||||
|
||||
An object may be assigned to zero, one, or multiple documents. Almost
|
||||
any object or property may be assigned to a document, though typically
|
||||
@@ -32,14 +40,16 @@ class Usecase:
|
||||
consistent with other external relationships (such as classification
|
||||
systems or libraries).
|
||||
|
||||
:param product: The object to associate the document to. This could be
|
||||
:param product: The list of objects to associate the document to. This could be
|
||||
almost any sensible object in IFC.
|
||||
:type product: ifcopenshell.entity_instance.entity_instance
|
||||
:type product: list[ifcopenshell.entity_instance.entity_instance]
|
||||
:param document: The IfcDocumentReference to associate to, or
|
||||
alternatively an IfcDocumentInformation, though this is not
|
||||
recommended.
|
||||
:type document: ifcopenshell.entity_instance.entity_instance
|
||||
:return: The IfcRelAssociatesDocument relationship
|
||||
or `None` if `products` was an empty list or all products were
|
||||
already assigned to the `document`.
|
||||
:rtype: ifcopenshell.entity_instance.entity_instance
|
||||
|
||||
Example:
|
||||
@@ -54,42 +64,51 @@ class Usecase:
|
||||
reference = ifcopenshell.api.run("document.add_reference", model, information=document)
|
||||
|
||||
# Let's imagine storey represents an IfcBuildingStorey for the ground floor
|
||||
ifcopenshell.api.run("document.assign_document", model, product=storey, document=reference)
|
||||
ifcopenshell.api.run("document.assign_document", model, products=[storey], document=reference)
|
||||
"""
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"product": product,
|
||||
"products": products,
|
||||
"document": document,
|
||||
}
|
||||
|
||||
def execute(self):
|
||||
rel = self.get_document_rel()
|
||||
related_objects = set(rel.RelatedObjects) if rel.RelatedObjects else set()
|
||||
related_objects.add(self.settings["product"])
|
||||
rel.RelatedObjects = list(related_objects)
|
||||
def execute(self) -> Union[ifcopenshell.entity_instance, None]:
|
||||
# TODO: do we need to support non-ifcroot elements like we do in classification.add_reference?
|
||||
# NOTE: reuses code from `library.assign_reference`
|
||||
|
||||
referenced_elements = ifcopenshell.util.element.get_referenced_elements(self.settings["document"])
|
||||
products: set[ifcopenshell.entity_instance] = set(self.settings["products"])
|
||||
products = products - referenced_elements
|
||||
|
||||
if not products:
|
||||
return
|
||||
|
||||
def get_document_rel(self):
|
||||
if self.file.schema == "IFC2X3":
|
||||
for rel in self.file.by_type("IfcRelAssociatesDocument"):
|
||||
if rel.RelatingDocument == self.settings["document"]:
|
||||
return rel
|
||||
rel = next(
|
||||
(
|
||||
r
|
||||
for r in self.file.by_type("IfcRelAssociatesDocument")
|
||||
if r.RelatingDocument == self.settings["document"]
|
||||
),
|
||||
None,
|
||||
)
|
||||
else:
|
||||
if (
|
||||
hasattr(self.settings["document"], "DocumentRefForObjects")
|
||||
and self.settings["document"].DocumentRefForObjects
|
||||
):
|
||||
return self.settings["document"].DocumentRefForObjects[0]
|
||||
elif (
|
||||
hasattr(self.settings["document"], "DocumentInfoForObjects")
|
||||
and self.settings["document"].DocumentInfoForObjects
|
||||
):
|
||||
return self.settings["document"].DocumentInfoForObjects[0]
|
||||
ifc_class = self.settings["document"].is_a()
|
||||
if ifc_class == "IfcDocumentReference":
|
||||
rel = next(iter(self.settings["document"].DocumentRefForObjects), None)
|
||||
elif ifc_class == "IfcDocumentInformation":
|
||||
rel = next(iter(self.settings["document"].DocumentInfoForObjects), None)
|
||||
|
||||
return self.file.create_entity(
|
||||
"IfcRelAssociatesDocument",
|
||||
**{
|
||||
"GlobalId": ifcopenshell.guid.new(),
|
||||
"OwnerHistory": ifcopenshell.api.run("owner.create_owner_history", self.file),
|
||||
"RelatingDocument": self.settings["document"],
|
||||
}
|
||||
)
|
||||
if not rel:
|
||||
return self.file.create_entity(
|
||||
"IfcRelAssociatesDocument",
|
||||
GlobalId=ifcopenshell.guid.new(),
|
||||
OwnerHistory=ifcopenshell.api.run("owner.create_owner_history", self.file),
|
||||
RelatedObjects=list(products),
|
||||
RelatingDocument=self.settings["document"],
|
||||
)
|
||||
|
||||
related_objects = set(rel.RelatedObjects) | products
|
||||
rel.RelatedObjects = list(related_objects)
|
||||
ifcopenshell.api.run("owner.update_owner_history", self.file, element=rel)
|
||||
return rel
|
||||
|
||||
@@ -45,7 +45,7 @@ class Usecase:
|
||||
reference = ifcopenshell.api.run("document.add_reference", model, information=document)
|
||||
|
||||
# Let's imagine storey represents an IfcBuildingStorey for the ground floor
|
||||
ifcopenshell.api.run("document.assign_document", model, product=storey, document=reference)
|
||||
ifcopenshell.api.run("document.assign_document", model, products=[storey], document=reference)
|
||||
|
||||
# Now let's change our mind and remove the association
|
||||
ifcopenshell.api.run("document.unassign_document", model, product=storey, document=reference)
|
||||
|
||||
@@ -18,22 +18,25 @@
|
||||
|
||||
import test.bootstrap
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.util.element
|
||||
|
||||
|
||||
class TestAssignDocument(test.bootstrap.IFC4):
|
||||
def test_assigning_a_document(self):
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
reference = ifcopenshell.api.run("document.add_reference", self.file, information=None)
|
||||
ifcopenshell.api.run("document.assign_document", self.file, product=element, document=reference)
|
||||
ifcopenshell.api.run("document.assign_document", self.file, products=[element], document=reference)
|
||||
assert element.HasAssociations[0].RelatingDocument == reference
|
||||
assert ifcopenshell.util.element.get_referenced_elements(reference) == {element}
|
||||
|
||||
def test_assigning_multiple_documents(self):
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
reference = ifcopenshell.api.run("document.add_reference", self.file, information=None)
|
||||
ifcopenshell.api.run("document.assign_document", self.file, product=element, document=reference)
|
||||
ifcopenshell.api.run("document.assign_document", self.file, product=element2, document=reference)
|
||||
ifcopenshell.api.run("document.assign_document", self.file, products=[element, element2], document=reference)
|
||||
assert len(self.file.by_type("IfcRelAssociatesDocument")) == 1
|
||||
assert element.HasAssociations[0].RelatingDocument == reference
|
||||
assert element2.HasAssociations[0].RelatingDocument == reference
|
||||
assert element.HasAssociations[0] == element.HasAssociations[0]
|
||||
assert ifcopenshell.util.element.get_referenced_elements(reference) == {element, element2}
|
||||
|
||||
|
||||
class TestAssignDocumentIFC2X3(test.bootstrap.IFC2X3, TestAssignDocument):
|
||||
pass
|
||||
|
||||
@@ -35,7 +35,7 @@ class TestRemoveReference(test.bootstrap.IFC4):
|
||||
wall = self.file.createIfcWall()
|
||||
information = ifcopenshell.api.run("document.add_information", self.file, parent=None)
|
||||
reference = ifcopenshell.api.run("document.add_reference", self.file, information=information)
|
||||
ifcopenshell.api.run("document.assign_document", self.file, product=wall, document=reference)
|
||||
ifcopenshell.api.run("document.assign_document", self.file, products=[wall], document=reference)
|
||||
assert len(self.file.by_type("IfcRelAssociatesDocument")) == 2
|
||||
ifcopenshell.api.run("document.remove_reference", self.file, reference=reference)
|
||||
assert len(self.file.by_type("IfcDocumentReference")) == 0
|
||||
|
||||
@@ -24,7 +24,7 @@ class TestUnassignDocument(test.bootstrap.IFC4):
|
||||
def test_unassigning_a_document(self):
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
reference = ifcopenshell.api.run("document.add_reference", self.file, information=None)
|
||||
ifcopenshell.api.run("document.assign_document", self.file, product=element, document=reference)
|
||||
ifcopenshell.api.run("document.assign_document", self.file, products=[element], document=reference)
|
||||
ifcopenshell.api.run("document.unassign_document", self.file, product=element, document=reference)
|
||||
assert not element.HasAssociations
|
||||
assert not len(self.file.by_type("IfcRelAssociatesDocument"))
|
||||
@@ -33,8 +33,8 @@ class TestUnassignDocument(test.bootstrap.IFC4):
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
reference = ifcopenshell.api.run("document.add_reference", self.file, information=None)
|
||||
ifcopenshell.api.run("document.assign_document", self.file, product=element, document=reference)
|
||||
ifcopenshell.api.run("document.assign_document", self.file, product=element2, document=reference)
|
||||
ifcopenshell.api.run("document.assign_document", self.file, products=[element], document=reference)
|
||||
ifcopenshell.api.run("document.assign_document", self.file, products=[element2], document=reference)
|
||||
ifcopenshell.api.run("document.unassign_document", self.file, product=element, document=reference)
|
||||
assert not element.HasAssociations
|
||||
assert element2.HasAssociations[0].RelatingDocument == reference
|
||||
|
||||
@@ -254,3 +254,10 @@ class TestTemporarySupportForDeprecatedAPIArguments(test.bootstrap.IFC4):
|
||||
ifcopenshell.api.run("library.assign_reference", self.file, products=[product], reference=reference)
|
||||
ifcopenshell.api.run("library.unassign_reference", self.file, product=product, reference=reference)
|
||||
assert len(self.file.by_type("IfcRelAssociatesLibrary")) == 0
|
||||
|
||||
@deprecation_check
|
||||
def test_assigning_a_document(self):
|
||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||
reference = ifcopenshell.api.run("document.add_reference", self.file, information=None)
|
||||
ifcopenshell.api.run("document.assign_document", self.file, product=element, document=reference)
|
||||
assert element.HasAssociations[0].RelatingDocument == reference
|
||||
|
||||
@@ -787,7 +787,6 @@ class TestGetNestIFC2X3(test.bootstrap.IFC2X3, TestGetNestIFC4):
|
||||
|
||||
class TestGetReferencedElements(test.bootstrap.IFC4):
|
||||
# TODO: test other references:
|
||||
# IfcDocumentReference
|
||||
# IfcExternallyDefinedHatchStyle
|
||||
# IfcExternallyDefinedSurfaceStyle
|
||||
# IfcExternallyDefinedTextFont
|
||||
@@ -816,6 +815,15 @@ class TestGetReferencedElements(test.bootstrap.IFC4):
|
||||
ifcopenshell.api.run("library.assign_reference", self.file, reference=reference, products=elements)
|
||||
assert subject.get_referenced_elements(reference) == set(elements)
|
||||
|
||||
def test_get_elements_referenced_by_document_reference(self):
|
||||
reference = ifcopenshell.api.run("document.add_reference", self.file, information=None)
|
||||
elements = [
|
||||
ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall"),
|
||||
ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall"),
|
||||
]
|
||||
ifcopenshell.api.run("document.assign_document", self.file, document=reference, products=elements)
|
||||
assert subject.get_referenced_elements(reference) == set(elements)
|
||||
|
||||
|
||||
class TestGetReferencedElementsIFC2X3(test.bootstrap.IFC2X3, TestGetReferencedElements):
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user