diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/add_actor.py b/src/ifcopenshell-python/ifcopenshell/api/owner/add_actor.py index eb413ca2c2..9df6234fa3 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/add_actor.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/add_actor.py @@ -22,11 +22,45 @@ import ifcopenshell.api class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, actor=None, ifc_class="IfcActor"): + """Adds a new actor + + An actor is a person or an organisation who has a responsibility or role + to play in a project. Actor roles include design consultants, + architects, engineers, cost planners, suppliers, manufacturers, + warrantors, owners, subcontractors, etc. + + Actors may either be project actors, who are responsible for the + delivery of the project, or occupants, who are responsible for the + consumption of the project. + + Identifying and managing actors is critical for asset management, and + identifying liability for legal submissions. + + :param actor: Most commonly, an IfcOrganization (in compliance with GDPR + requirements for non personally identifiable information), or an + IfcPerson if it is a sole individual, or an IfcPersonAndOrganization + if a specific person is liable within an organisation and must be + legally nominated. + :type actor: ifcopenshell.entity_instance.entity_instance + :param ifc_class: Either "IfcActor" or "IfcOccupant". + :type ifc_class: str, optional + :return: The newly created IfcActor or IfcOccupant + :rtype: ifcopenshell.entity_instance.entity_instance + + Example:: + + # Setup an organisation with a single role + organisation = ifcopenshell.api.run("owner.add_organisation", model, + identification="AWB", name="Architects Without Ballpens") + role = ifcopenshell.api.run("owner.add_role", model, assigned_object=organisation) + ifcopenshell.api.run("owner.edit_role", model, role=role, attributes={"Role": "ARCHITECT"}) + + # Assign that organisation to a newly created actor + actor = ifcopenshell.api.run("owner.add_actor", model, actor=organisation) + """ self.file = file - self.settings = {"actor": None, "ifc_class": "IfcActor"} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"actor": actor, "ifc_class": ifc_class or "IfcActor"} def execute(self): actor = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=self.settings["ifc_class"]) diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/add_address.py b/src/ifcopenshell-python/ifcopenshell/api/owner/add_address.py index c9d074c939..f9c65048eb 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/add_address.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/add_address.py @@ -18,11 +18,49 @@ class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, assigned_object=None, ifc_class="IfcPostalAddress"): + """Add a new telecom or postal address to an organisation or person + + A person or organisation may have associated contact details such as + phone numbers, mailing addresses, websites, email addresses, and instant + messaging handles. This information is critical in recording the contact + information of manufacturers and suppliers for facility management, or + liable actors. + + There are two types of addresses, postal addresses for physical snail + mail, and telecom addresses for telephone or internet contact numbers + and addresses. + + :param assigned_object: The IfcOrganization or IfcPerson the contact + address belongs to. + :type assigned_object: ifcopenshell.entity_instance.entity_instance + :param ifc_class: Either IfcPostalAddress or IfcTelecomAddress. Defaults + to IfcPostalAddress. + :type ifc_class: str, optional + :return: The new IfcPostalAddress or IfcTelecomAddress + :rtype: ifcopenshell.entity_instance.entity_instance + + Example:: + + organisation = ifcopenshell.api.run("owner.add_organisation", model) + + # A snail mail address + postal = ifcopenshell.api.run("owner.add_address", model, + assigned_object=organisation, ifc_class="IfcPostalAddress") + ifcopenshell.api.run("owner.edit_address", model, address=postal, + attributes={"Purpose": "OFFICE", "AddressLines": ["42 Wallaby Way"], + "Town": "Sydney", "Region": "NSW", "PostalCode": "2000"}) + + # A phone or internet address + telecom = ifcopenshell.api.run("owner.add_address", model, + assigned_object=organisation, ifc_class="IfcTelecomAddress") + ifcopenshell.api.run("owner.edit_address", model, address=telecom, + attributes={"Purpose": "OFFICE", "TelephoneNumbers": ["+61432466949"], + "ElectronicMailAddresses": ["bobthebuilder@example.com"], + "WWWHomePageURL": "https://thinkmoult.com"}) + """ self.file = file - self.settings = {"assigned_object": None, "ifc_class": "IfcPostalAddress"} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"assigned_object": assigned_object, "ifc_class": ifc_class} def execute(self): address = self.file.create_entity(self.settings["ifc_class"], "OFFICE") diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/add_application.py b/src/ifcopenshell-python/ifcopenshell/api/owner/add_application.py index fb8c90983d..7c7cc6691e 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/add_application.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/add_application.py @@ -20,16 +20,46 @@ import ifcopenshell.api class Usecase: - def __init__(self, file, **settings): + def __init__( + self, + file, + application_developer=None, + version=None, + application_full_name="IfcOpenShell", + application_identifier="IfcOpenShell", + ): + """Adds a new application + + IFC data may be associated with an authoring application to identify + which application was responsible for editing or authoring the data. An + application is defined by the developing organisation, as well as a full + name and identifier. This is akin to how web browsers have an + identification string. + + :param application_developer: The IfcOrganization responsible for + creating the application. Defaults to generating an IfcOpenShell + organisation if none is provided. + :type application_developer: ifcopenshell.entity_instance.entity_instance, optional + :param version: The version of the application. Defaults to the + ifcopenshell.version data if not specified. + :type version: str, optional + :param application_full_name: The name of the application + :type application_full_name: str, optional + :param application_identifier: An identification string for the + application intended for computers to read. + :type application_identifier: str, optional + + Example:: + + application = ifcopenshell.api.run("owner.add_application", model) + """ self.file = file self.settings = { - "application_developer": None, - "version": ifcopenshell.version, - "application_full_name": "IfcOpenShell", - "application_identifier": "IfcOpenShell", + "application_developer": application_developer, + "version": version or ifcopenshell.version, + "application_full_name": application_full_name, + "application_identifier": application_identifier, } - for key, value in settings.items(): - self.settings[key] = value def execute(self): if not self.settings["application_developer"]: diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/add_organisation.py b/src/ifcopenshell-python/ifcopenshell/api/owner/add_organisation.py index d3a8f3e09b..880a71cea3 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/add_organisation.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/add_organisation.py @@ -18,14 +18,30 @@ class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, identification="APTR", name="Aperture Science"): + """Adds a new organisation + + Organisations are the main way to identify manufacturers, suppliers, and + other actors who do not have a single representative or must not have + any personally identifiable information. + + :param identification: The short code identifying the organisation. + Sometimes used in drawing naming schemes. Otherise used as a + canonicalised way of computers to identify the organisation. Like + their stock name. + :type identification: str, optional + :param name: The legal name of the organisation + :type name: str, optional + :return: The newly created IfcOrganization + :rtype: ifcopenshell.entity_instance.entity_instance + + Example:: + + organisation = ifcopenshell.api.run("owner.add_organisation", model, + identification="AWB", name="Architects Without Ballpens") + """ self.file = file - self.settings = { - "identification": "APTR", - "name": "Aperture Science", - } - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"identification": identification, "name": name} def execute(self): data = {"Name": self.settings["name"]} diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/add_person.py b/src/ifcopenshell-python/ifcopenshell/api/owner/add_person.py index aa31ce75d0..8d1e7a3742 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/add_person.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/add_person.py @@ -18,15 +18,33 @@ class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, identification="HSeldon", family_name="Seldon", given_name="Hari"): + """Adds a new person + + Persons are used to identify a legal or liable representative of an + organisation or point of contact. + + :param identification: The computer readable unique identification of + the person. For example, their username in a CDE or alias. + :type identification: str, optional + :param family_name: The family name + :type family_name: str, optional + :param given_name: The given name + :type given_name: str, optional + :return: The newly created IfcPerson + :rtype: ifcopenshell.entity_instance.entity_instance + + Example:: + + ifcopenshell.api.run("owner.add_person", model, + identification="bobthebuilder", family_name="Thebuilder", given_name="Bob") + """ self.file = file self.settings = { - "identification": "HSeldon", - "family_name": "Seldon", - "given_name": "Hari", + "identification": identification, + "family_name": family_name, + "given_name": given_name, } - for key, value in settings.items(): - self.settings[key] = value def execute(self): data = {"FamilyName": self.settings["family_name"], "GivenName": self.settings["given_name"]} diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/add_person_and_organisation.py b/src/ifcopenshell-python/ifcopenshell/api/owner/add_person_and_organisation.py index 4c7f3971d2..18950d3dae 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/add_person_and_organisation.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/add_person_and_organisation.py @@ -18,11 +18,32 @@ class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, person=None, organisation=None): + """Adds a paired person and organisation + + A person and an organisation may be paired to create a representative + belonging to a company. + + :param person: The IfcPerson being the representative of the + organisation. + :type person: ifcopenshell.entity_instance.entity_instance + :param organisation: The IfcOrganization itself. + :type organisation: ifcopenshell.entity_instance.entity_instance + :return: The newly created IfcPersonAndOrganization + :rtype: ifcopenshell.entity_instance.entity_instance + + Example:: + + person = ifcopenshell.api.run("owner.add_person", model, + identification="lecorbycorbycorb", family_name="Curbosiar", given_name="Le") + organisation = ifcopenshell.api.run("owner.add_organisation", model, + identification="AWB", name="Architects Without Ballpens") + + ifcopenshell.api.run("owner.add_person_and_organisation", model, + person=person, organisation=organisation) + """ self.file = file - self.settings = {"person": None, "organisation": None} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"person": person, "organisation": organisation} def execute(self): return self.file.createIfcPersonAndOrganization(self.settings["person"], self.settings["organisation"]) diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/add_role.py b/src/ifcopenshell-python/ifcopenshell/api/owner/add_role.py index eb48cbe72e..417754cfb1 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/add_role.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/add_role.py @@ -18,14 +18,43 @@ class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, assigned_object=None, role="ARCHITECT"): + """Adds and assigns a new role + + People and organisations must play one or more roles on a project. Roles + include architects, engineers, subcontractors, clients, manufacturers, + etc. Typically these roles and their corresponding responsibilities will + be outlined in contractual documents. + + This function will both add and assign the role to the person or + organisation. + + :param assigned_object: The IfcPerson or IfcOrganization the role should + be assigned to. + :type assigned_object: ifcopenshell.entity_instance.entity_instance + :param role: The type of role, taken from the IFC documentation for + IfcActorRole, or a custom name. + :type role: str, optional + :return: The newly created IfcActorRole + :rtype: ifcopenshell.entity_instance.entity_instance + + Example:: + + organisation = ifcopenshell.api.run("owner.add_organisation", model, + identification="AWB", name="Architects Without Ballpens") + ifcopenshell.api.run("owner.add_role", model, assigned_object=organisation, role="ARCHITECT") + """ self.file = file - self.settings = {"assigned_object": None} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"assigned_object": assigned_object, "role": role} def execute(self): element = self.file.createIfcActorRole("ARCHITECT") + if self.settings["role"]: + try: + element.Role = self.settings["role"] + except: + element.Role = "USERDEFINED" + element.UserDefinedRole = self.settings["role"] roles = list(self.settings["assigned_object"].Roles) if self.settings["assigned_object"].Roles else [] roles.append(element) self.settings["assigned_object"].Roles = roles diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/assign_actor.py b/src/ifcopenshell-python/ifcopenshell/api/owner/assign_actor.py index eefe3d5142..99079af91f 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/assign_actor.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/assign_actor.py @@ -21,14 +21,57 @@ import ifcopenshell.api class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, relating_actor=None, related_object=None): + """Assigns an actor to an object + + An actor may be assigned to objects which implies that the actor is + responsible for. This is most commonly used in facility management for + indicating the manufacturers, suppliers, and warrantors for product + types. + + Here are a list of objects you may assign an actor to: + + - IfcControl: Indicates project directives issued by the actor. + - IfcGroup: Indicates groups for which the actor is responsible. + - IfcProduct: Indicates products for which the actor is responsible. + - IfcProcess: Indicates processes for which the actor is responsible. + - IfcResource: Indicates resources for which the actor is responsible. + + :param relating_actor: The IfcActor who is responsible for the object. + :type relating_actor: ifcopenshell.entity_instance.entity_instance + :param related_object: The object the actor is responsible for. + :type related_object: ifcopenshell.entity_instance.entity_instance + :return: The newly created IfcRelAssignsToActor relationship. + :rtype: ifcopenshell.entity_instance.entity_instance + + Example:: + + # We need to procure and install 2 of this particular pump type in our facility. + pump_type = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcPumpType") + + # Define who the manufacturer is + manufacturer = ifcopenshell.api.run("owner.add_organisation", model, + identification="PWP", name="Pumps With Power") + ifcopenshell.api.run("owner.add_role", model, assigned_object=manufacturer, role="MANUFACTURER") + + # To help our facility manager, it's nice to provide contact details + # of the manufacturer so they know how to call when the pump breaks. + telecom = ifcopenshell.api.run("owner.add_address", model, + assigned_object=organisation, ifc_class="IfcTelecomAddress") + ifcopenshell.api.run("owner.edit_address", model, address=telecom, + attributes={"Purpose": "OFFICE", "TelephoneNumbers": ["+61432466949"], + "ElectronicMailAddresses": ["contact@example.com"], + "WWWHomePageURL": "https://example.com"}) + + # Make the manufacturer responsible for that pump type. + ifcopenshell.api.run("owner.assign_actor", model, + relating_actor=manufacturer, related_object=pump_type) + """ self.file = file self.settings = { - "relating_actor": None, - "related_object": None, + "relating_actor": relating_actor, + "related_object": related_object, } - for key, value in settings.items(): - self.settings[key] = value def execute(self): if self.settings["related_object"].HasAssignments: diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/create_owner_history.py b/src/ifcopenshell-python/ifcopenshell/api/owner/create_owner_history.py index 6f72a9498c..0418c0cdc7 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/create_owner_history.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/create_owner_history.py @@ -22,11 +22,80 @@ import ifcopenshell.api.owner.settings class Usecase: - def __init__(self, file, **settings): + def __init__(self, file): + """Creates a new owner history indicating an element was added + + Any object in IFC with a unique ID and name (such as physical products, + tasks, calendars, etc) may have an owner associated with it. An owner is + a liable person and/or organisation which a bit of metadata indicating + whether they have created the object, edited the object, when the change + was made, and which application they used. + + IFC does not offer a comprehensive specification for version control and + change tracking, as this is completely out of scope. However this + similar ability allows IFC to satisfy legal requirements where object + ownership, responsibilities, and permissions must be specified. + Recording the owner is mandatory in IFC2X3 but optional in IFC4. It is + not recommended to store this ownership data in IFC4 unless a legal + requirement is in place. + + Because owner tracking is mandatory in IFC2X3, be aware that some + configuration may be required to work correctly. Read on. + + To track the owner, at a minimum we have to know the application that + the element was authored from, as well as the user (person and + organisation) that made the change. The IfcOpenShell API is a low level + software library and will not know what application the API is being + called from, and nor does it have the responsibility to manage the + "active user" making edits, which may be as simple as hardcoding it to + "Bob" or even be as complex as integrationg with a CDE's authentication + system. As a result, the developer responsible to integrate with + IfcOpenShell is expected to overload the + ifcopenshell.api.owner.settings.get_user and + ifcopenshell.api.owner.settings.get_application functions. + + It is not necessary to call this function directly if you are already + using other API calls. It is a low level function only available if you + are writing your own advanced scripts and want to take advantage of the + easier ownership tracking. + + :return: The newly created IfcOwnerHistory element. + :rtype: ifcopenshell.entity_instance.entity_instance + + Example:: + + # Let's imagine we're writing a small script, not large enough to be + # its own fully branded application. In this case, let's use the + # default application which is prepopulated with "IfcOpenShell" as + # the name and version. + application = ifcopenshell.api.run("owner.add_application", model) + + # Let's imagine we run this as an automated QA process in an + # architectural firm. However, the results must be signed off by the + # registered architect who is liable for the project. + person = ifcopenshell.api.run("owner.add_person", model, + identification="LPARTEE", family_name="Partee", given_name="Leeable") + organisation = ifcopenshell.api.run("owner.add_organisation", model, + identification="AWB", name="Architects Without Ballpens") + user = ifcopenshell.api.run("owner.add_person_and_organisation", model, + person=person, organisation=organisation) + + # Let's configure our owner settings to hardcode always returning + # the application and user. In theory, you could build complex user + # access control lookup functions here, but this is simple enough. + ifcopenshell.api.owner.settings.get_user = lambda x: user + ifcopenshell.api.owner.settings.get_application = lambda x: application + + # We've finished our ownership setup. Now let's start our script and + # create a space. Notice we don't actually call + # create_owner_history at all. This is already automatically handled + # by the API when necessary. Under the hood, the API is actually + # running this code on the IfcSpace element: + # element.OwnerHistory = ifcopenshell.api.run("owner.create_owner_history", model) + space = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcSpace") + """ self.file = file self.settings = {} - for key, value in settings.items(): - self.settings[key] = value def execute(self): user = ifcopenshell.api.owner.settings.get_user(self.file) diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/edit_actor.py b/src/ifcopenshell-python/ifcopenshell/api/owner/edit_actor.py index 9a854ca9e2..0260eb46c1 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/edit_actor.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/edit_actor.py @@ -18,11 +18,36 @@ class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, actor=None, attributes=None): + """Edits the attributes of an IfcActor + + For more information about the attributes and data types of an + IfcActor, consult the IFC documentation. + + :param actor: The IfcActor entity you want to edit + :type actor: ifcopenshell.entity_instance.entity_instance + :param attributes: a dictionary of attribute names and values. + :type attributes: dict, optional + :return: None + :rtype: None + + Example:: + + # Setup an organisation with a single role + organisation = ifcopenshell.api.run("owner.add_organisation", model, + identification="AWB", name="Architects Without Ballpens") + role = ifcopenshell.api.run("owner.add_role", model, assigned_object=organisation) + ifcopenshell.api.run("owner.edit_role", model, role=role, attributes={"Role": "ARCHITECT"}) + + # Assign that organisation to a newly created actor + actor = ifcopenshell.api.run("owner.add_actor", model, actor=organisation) + + # Edit the description of the attribute. + ifcopenshell.api.run("actor.edit_actor", model, + actor=actor, attributes={"Description": "Responsible for buildings A, B, and C."}) + """ self.file = file - self.settings = {"actor": None, "attributes": {}} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"actor": actor, "attributes": attributes or {}} def execute(self): for name, value in self.settings["attributes"].items(): diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/edit_address.py b/src/ifcopenshell-python/ifcopenshell/api/owner/edit_address.py index bb63c59d88..a608a8bfc7 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/edit_address.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/edit_address.py @@ -18,11 +18,38 @@ class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, address=None, attributes=None): + """Edits the attributes of an IfcAddress + + For more information about the attributes and data types of an + IfcAddress, consult the IFC documentation. + + :param address: The IfcAddress entity you want to edit + :type address: ifcopenshell.entity_instance.entity_instance + :param attributes: a dictionary of attribute names and values. + :type attributes: dict, optional + :return: None + :rtype: None + + Example:: + + # A snail mail address + postal = ifcopenshell.api.run("owner.add_address", model, + assigned_object=organisation, ifc_class="IfcPostalAddress") + ifcopenshell.api.run("owner.edit_address", model, address=postal, + attributes={"Purpose": "OFFICE", "AddressLines": ["42 Wallaby Way"], + "Town": "Sydney", "Region": "NSW", "PostalCode": "2000"}) + + # A phone or internet address + telecom = ifcopenshell.api.run("owner.add_address", model, + assigned_object=organisation, ifc_class="IfcTelecomAddress") + ifcopenshell.api.run("owner.edit_address", model, address=telecom, + attributes={"Purpose": "OFFICE", "TelephoneNumbers": ["+61432466949"], + "ElectronicMailAddresses": ["bobthebuilder@example.com"], + "WWWHomePageURL": "https://thinkmoult.com"}) + """ self.file = file - self.settings = {"address": None, "attributes": {}} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"address": address, "attributes": attributes or {}} def execute(self): for name, value in self.settings["attributes"].items(): diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/edit_organisation.py b/src/ifcopenshell-python/ifcopenshell/api/owner/edit_organisation.py index c097a0a147..715786bbda 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/edit_organisation.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/edit_organisation.py @@ -18,11 +18,28 @@ class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, organisation=None, attributes=None): + """Edits the attributes of an IfcOrganization + + For more information about the attributes and data types of an + IfcOrganization, consult the IFC documentation. + + :param organisation: The IfcOrganization entity you want to edit + :type organisation: ifcopenshell.entity_instance.entity_instance + :param attributes: a dictionary of attribute names and values. + :type attributes: dict, optional + :return: None + :rtype: None + + Example:: + + organisation = ifcopenshell.api.run("owner.add_organisation", model, + identification="AWB", name="Architects With Ballpens") + ifcopenshell.api.run("owner.edit_organisation", model, organisation=organisation, + attributes={"name": "Architects Without Ballpens"}) + """ self.file = file - self.settings = {"organisation": None, "attributes": {}} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"organisation": organisation, "attributes": attributes or {}} def execute(self): for name, value in self.settings["attributes"].items(): diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/edit_person.py b/src/ifcopenshell-python/ifcopenshell/api/owner/edit_person.py index 1b7f390a96..6235405e3c 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/edit_person.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/edit_person.py @@ -18,11 +18,28 @@ class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, person=None, attributes=None): + """Edits the attributes of an IfcPerson + + For more information about the attributes and data types of an + IfcPerson, consult the IFC documentation. + + :param person: The IfcPerson entity you want to edit + :type person: ifcopenshell.entity_instance.entity_instance + :param attributes: a dictionary of attribute names and values. + :type attributes: dict, optional + :return: None + :rtype: None + + Example:: + + person = ifcopenshell.api.run("owner.add_person", model, + identification="bobthebuilder", family_name="Thebuilder", given_name="Bob") + ifcopenshell.api.run("owner.edit_person", model, person=person, + attributes={"MiddleNames": ["The"], "FamilyName": "Builder"}) + """ self.file = file - self.settings = {"person": None, "attributes": {}} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"person": person, "attributes": attributes or {}} def execute(self): for name, value in self.settings["attributes"].items(): diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/edit_role.py b/src/ifcopenshell-python/ifcopenshell/api/owner/edit_role.py index 833e7ef955..69e44d5b41 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/edit_role.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/edit_role.py @@ -18,11 +18,32 @@ class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, role=None, attributes=None): + """Edits the attributes of an IfcActorRole + + For more information about the attributes and data types of an + IfcActorRole, consult the IFC documentation. + + :param role: The IfcActorRole entity you want to edit + :type role: ifcopenshell.entity_instance.entity_instance + :param attributes: a dictionary of attribute names and values. + :type attributes: dict, optional + :return: None + :rtype: None + + Example:: + + person = ifcopenshell.api.run("owner.add_person", model, + identification="bobthebuilder", family_name="Thebuilder", given_name="Bob") + + # By default, the role is an architect + role = ifcopenshell.api.run("owner.add_role", model, assigned_object=person) + + # But Bob is not an architect + ifcopenshell.api.run("owner.edit_role", model, role=role, attributes={"Role": "CONSTRUCTIONMANAGER"}) + """ self.file = file - self.settings = {"role": None, "attributes": {}} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"role": role, "attributes": attributes or {}} def execute(self): for name, value in self.settings["attributes"].items(): diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/remove_actor.py b/src/ifcopenshell-python/ifcopenshell/api/owner/remove_actor.py index bfa3c3642a..4bdc698358 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/remove_actor.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/remove_actor.py @@ -20,11 +20,30 @@ import ifcopenshell.api class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, actor=None): + """Removes an actor + + :param actor: The IfcActor to remove. + :type actor: ifcopenshell.entity_instance.entity_instance + :return: None + :rtype: None + + Example:: + + # Setup an organisation with a single role + organisation = ifcopenshell.api.run("owner.add_organisation", model, + identification="AWB", name="Architects Without Ballpens") + role = ifcopenshell.api.run("owner.add_role", model, assigned_object=organisation) + ifcopenshell.api.run("owner.edit_role", model, role=role, attributes={"Role": "ARCHITECT"}) + + # Assign that organisation to a newly created actor + actor = ifcopenshell.api.run("owner.add_actor", model, actor=organisation) + + # Actually we need ballpens on this project + ifcopenshell.api.run("owner.remove_actor", model, actor=actor) + """ self.file = file - self.settings = {"actor": None} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"actor": actor} def execute(self): self.file.remove(self.settings["actor"]) diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/remove_address.py b/src/ifcopenshell-python/ifcopenshell/api/owner/remove_address.py index 6f890a4eee..2afda679d7 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/remove_address.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/remove_address.py @@ -18,11 +18,28 @@ class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, address=None): + """Removes an address + + Naturally, any organisations or people using that address will have the + relationship removed. + + :param address: The IfcAddress to remove. + :type address: ifcopenshell.entity_instance.entity_instance + :return: None + :rtype: None + + Example:: + + organisation = ifcopenshell.api.run("owner.add_organisation", model) + address = ifcopenshell.api.run("owner.add_address", model, + assigned_object=organisation, ifc_class="IfcPostalAddress") + + # Change our mind and delete it + ifcopenshell.api.run("owner.remove_address", model, address=address) + """ self.file = file - self.settings = {"address": None} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"address": address} def execute(self): for inverse in self.file.get_inverse(self.settings["address"]): diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/remove_application.py b/src/ifcopenshell-python/ifcopenshell/api/owner/remove_application.py index 25736c5e85..88d1ff3705 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/remove_application.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/remove_application.py @@ -16,15 +16,26 @@ # You should have received a copy of the GNU Lesser General Public License # along with IfcOpenShell. If not, see . -import ifcopenshell.api - class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, application=None): + """Removes an application + + Warning: removing an application may invalidate ownership histories. + Check whether or not the application is used anywhere prior to removal. + + :param address: The IfcApplication to remove. + :type address: ifcopenshell.entity_instance.entity_instance + :return: None + :rtype: None + + Example:: + + application = ifcopenshell.api.run("owner.add_application", model) + ifcopenshell.api.run("owner.remove_address", model, application=application) + """ self.file = file - self.settings = {"application": None} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"application": application} def execute(self): self.file.remove(self.settings["application"]) diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/remove_organisation.py b/src/ifcopenshell-python/ifcopenshell/api/owner/remove_organisation.py index 94784a66d6..883028d0b2 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/remove_organisation.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/remove_organisation.py @@ -20,11 +20,25 @@ import ifcopenshell.api class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, organisation=None): + """Remove an organisation + + All roles and addresses assigned to the organisation will also be + removed. + + :param organisation: The IfcOrganization to remove + :type organisation: ifcopenshell.entity_instance.entity_instance + :return: None + :rtype: None + + Example:: + + organisation = ifcopenshell.api.run("owner.add_organisation", model, + identification="AWB", name="Architects Without Ballpens") + ifcopenshell.api.run("owner.remove_organisation", model, organisation=organisation) + """ self.file = file - self.settings = {"organisation": None} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"organisation": organisation} def execute(self): for role in self.settings["organisation"].Roles or []: diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/remove_person.py b/src/ifcopenshell-python/ifcopenshell/api/owner/remove_person.py index b97d7b5f91..9f2bad9e35 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/remove_person.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/remove_person.py @@ -20,11 +20,25 @@ import ifcopenshell.api class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, person=None): + """Remove an person + + All roles and addresses assigned to the person will also be + removed. + + :param person: The IfcPerson to remove + :type person: ifcopenshell.entity_instance.entity_instance + :return: None + :rtype: None + + Example:: + + ifcopenshell.api.run("owner.add_person", model, + identification="bobthebuilder", family_name="Thebuilder", given_name="Bob") + ifcopenshell.api.run("owner.remove_person", model, person=person) + """ self.file = file - self.settings = {"person": None} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"person": person} def execute(self): for role in self.settings["person"].Roles or []: diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/remove_person_and_organisation.py b/src/ifcopenshell-python/ifcopenshell/api/owner/remove_person_and_organisation.py index ee8b695c9b..71cef739c7 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/remove_person_and_organisation.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/remove_person_and_organisation.py @@ -20,11 +20,31 @@ import ifcopenshell.api class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, person_and_organisation=None): + """Removes a person and organisation + + Note that the underlying person and organisation is not removed, only + the "person and organisation" group. + + :param person_and_organisation: The IfcPersonAndOrganization to remove. + :type person_and_organisation: ifcopenshell.entity_instance.entity_instance + :return: None + :rtype: None + + Example:: + + person = ifcopenshell.api.run("owner.add_person", model, + identification="lecorbycorbycorb", family_name="Curbosiar", given_name="Le") + organisation = ifcopenshell.api.run("owner.add_organisation", model, + identification="AWB", name="Architects Without Ballpens") + + user = ifcopenshell.api.run("owner.add_person_and_organisation", model, + person=person, organisation=organisation) + + ifcopenshell.api.run("owner.remove_person_and_organisation", model, person_and_organisation=user) + """ self.file = file - self.settings = {"person_and_organisation": None} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"person_and_organisation": person_and_organisation} def execute(self): for inverse in self.file.get_inverse(self.settings["person_and_organisation"]): diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/remove_role.py b/src/ifcopenshell-python/ifcopenshell/api/owner/remove_role.py index becb12a5af..b77a695cc3 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/remove_role.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/remove_role.py @@ -18,11 +18,28 @@ class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, role=None): + """Removes a role + + People and organisations using the role will be untouched. This may + leave some of them without roles. + + :param role: The IfcActorRole to remove. + :type role: ifcopenshell.entity_instance.entity_instance + :return: None + :rtype: None + + Example:: + + organisation = ifcopenshell.api.run("owner.add_organisation", model, + identification="AWB", name="Architects Without Ballpens") + role = ifcopenshell.api.run("owner.add_role", model, assigned_object=organisation, role="ARCHITECT") + + # After running this, the organisation will have no role again + ifcopenshell.api.run("owner.remove_role", model, role=role) + """ self.file = file - self.settings = {"role": None} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"role": role} def execute(self): for inverse in self.file.get_inverse(self.settings["role"]): diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/settings.py b/src/ifcopenshell-python/ifcopenshell/api/owner/settings.py index 1071818026..9016cd12e9 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/settings.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/settings.py @@ -20,10 +20,30 @@ def get_application(ifc): + """Returns the application representing the authoring software + + It is expected for you to overload this function with your own + IfcApplication. See ifcopenshell.api.owner.create_owner_history for details. + + :param ifc: The IFC file object that is being edited. + :type ifc: ifcopenshell.file.file + :return: The IfcApplication with metadata of the authoring software. + :rtype: ifcopenshell.entity_instance.entity_instance + """ return (ifc.by_type("IfcApplication") or [None])[0] def get_user(ifc): + """Returns the active authoring user + + It is expected for you to overload this function with your own + IfcApplication. See ifcopenshell.api.owner.create_owner_history for details. + + :param ifc: The IFC file object that is being edited. + :type ifc: ifcopenshell.file.file + :return: The IfcPersonAndOrganization with metadata of the authoring user. + :rtype: ifcopenshell.entity_instance.entity_instance + """ return (ifc.by_type("IfcPersonAndOrganization") or [None])[0] diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/unassign_actor.py b/src/ifcopenshell-python/ifcopenshell/api/owner/unassign_actor.py index 9bd8b2f834..212dc88995 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/unassign_actor.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/unassign_actor.py @@ -21,14 +21,42 @@ import ifcopenshell.api class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, relating_actor=None, related_object=None): + """Unassigns an actor to an object + + This means that the actor is no longer responsible for the object. + + :param relating_actor: The IfcActor who is responsible for the object. + :type relating_actor: ifcopenshell.entity_instance.entity_instance + :param related_object: The object the actor is responsible for. + :type related_object: ifcopenshell.entity_instance.entity_instance + :return: The updated IfcRelAssignsToActor relationship or none if there + is no more valid relationship. + :rtype: None, ifcopenshell.entity_instance.entity_instance + + Example:: + + # We need to procure and install 2 of this particular pump type in our facility. + pump_type = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcPumpType") + + # Define who the manufacturer is + manufacturer = ifcopenshell.api.run("owner.add_organisation", model, + identification="PWP", name="Pumps With Power") + ifcopenshell.api.run("owner.add_role", model, assigned_object=manufacturer, role="MANUFACTURER") + + # Make the manufacturer responsible for that pump type. + ifcopenshell.api.run("owner.assign_actor", model, + relating_actor=manufacturer, related_object=pump_type) + + # Undo the assignment + ifcopenshell.api.run("owner.unassign_actor", model, + relating_actor=manufacturer, related_object=pump_type) + """ self.file = file self.settings = { - "relating_actor": None, - "related_object": None, + "relating_actor": relating_actor, + "related_object": related_object, } - for key, value in settings.items(): - self.settings[key] = value def execute(self): for rel in self.settings["related_object"].HasAssignments or []: diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/update_owner_history.py b/src/ifcopenshell-python/ifcopenshell/api/owner/update_owner_history.py index d19bf478db..47e37884d3 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/update_owner_history.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/update_owner_history.py @@ -24,11 +24,39 @@ import ifcopenshell.util.element class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, element=None): + """Updates the owner that is assigned to an object + + This ensures that the owner is tracked to have modified the object last, + including the time when the change occured. See + ifcopenshell.api.owner.create_owner_history for details. + + :param element: The IfcRoot element to update the ownership details on + when a change is made. + :type element: ifcopenshell.entity_instance.entity_instance + :return: The updated IfcOwnerHistory element. + :rtype: ifcopenshell.entity_instance.entity_instance + + Example:: + + # See ifcopenshell.api.owner.create_owner_history for setup + # [ ... example setup code ... ] + + # We've finished our ownership setup. Now let's start our script and + # create a space. Notice we don't actually call + # create_owner_history at all. This is already automatically handled + # by the API when necessary. Under the hood, the API is actually + # running this code on the IfcSpace element: + # element.OwnerHistory = ifcopenshell.api.run("owner.create_owner_history", model) + space = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcSpace") + + # Any edits we make will have ownership tracking automatically + # applied. There is no need to run any owner.update_owner_history + # API calls either. + ifcopenshell.api.run("attribute.edit_attributes", model, product=space, attributes={"Name": "Lobby"}) + """ self.file = file - self.settings = {} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"element": element} def execute(self): if not hasattr(self.settings["element"], "OwnerHistory"):