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