icon

[Frage] Useability of PythonParts for automatisation tasks


Hello,

I have some general questions/observations regarding the useability of PythonParts. In my experience developing with PythonParts, I’ve noticed that they are often far less dynamic than expected. In most of my applications, I modify their representation at the placement stage, but once the PythonPart is finalised, no further modifications are possible. I’ve identified two main issues behind this limitation:

1. ElementResult as a PythonPart vs ArchitecturalElement: If I define the ElementResult as a PythonPart (rather than a subclass of ArchitecturalElement), the resulting object remains parametrised and editable later. However, it loses many key functionalities that normal architectural elements have, such as the addition of recesses, openings, and reporting. Thus, generating a PythonPart object rather than actual architectural elements remain impractical in real workflows, as re-implementing all these functionalities (openings, joints, niches, etc.) feels redundant and it is misaligned with the practices of engineers in our office.

2. Automation limitations: When a PythonPart defines a unique and complex object in the model, manual editing works fine (utilising the parametric nature of the PythonPart). However, in my applications that aim to automate tasks requiring hundreds of actions, it’s unfortunate that PythonParts can only be updated manually, and they cannot automatically respond to changes in associated ArchitecturalElements. For example, if I create a PythonPart that annotates a wall, I would expect it to update automatically when the wall changes. As far as I understand, this is currently unachievable, which significantly limits the useability of PythonParts. Additionally, it seems that only one PythonPart can be defined per ScriptObject, so generating multiple PythonParts is unfeasible.
Because of these two main issues, I find that the practical utility of PythonParts in my applications is much more limited than it ideally should be.

My question is: have others encountered these limitations, and if so, how have you worked around them?

Thanks in advance for your help!

Hi,

1) Native elements vs PythonParts
Native Allplan elements (walls, slabs, etc.) can be created by script, and the result behaves like any standard architectural element, with support for openings, joints, and so on.
These native elements can then be modified with the usual Allplan tools, and also by script again if needed.
source

The PythonPart, as a single parametric object with a palette and stored parameters, is a different approach.

2) Linking native elements to a PythonPart
A PythonPart can be linked to one or several native elements.
When creating this connection, you can define which kinds of changes in the native elements will or will not trigger an update of the PythonPart.
source

Finally, you mention the notion of a transaction.
With an Interactor PythonPart, it is possible to create several transactions, and therefore several PythonParts.
There is also a concept of hierarchy, which may be useful for your use case.

In summary, PythonParts can be used in many different ways (for creating and modifying objects), with several levels of complexity, ranging from no‑code (Visual Scripting) up to Interactor‑based solutions.

Best
Christophe

Thank you for the very informative response.
I've experimented with the functionalities you suggested and would appreciate some further clarification on a few points:

1. Native elements vs. PythonParts
If I create a slab by passing an AllplanArchElements.SlabElement directly into the ModelEleList of CreateElementResult, the result is a native Allplan element. In this case, I can add recesses to it just as I would with a manually created slab.
However, if I wrap the same slab inside a PythonPart as:

model_ele_list = []
model_ele_list.append(slab_element)
pyp_util = PythonPartUtil()
pyp_util.add_pythonpart_view_2d3d(model_ele_list)
pythonpart = pyp_util.create_pythonpart(self.build_ele)
return CreateElementResult(
    elements=pythonpart,
    placement_point=AllplanGeometry.Point2D()
)

Then I can no longer insert a recess into the slab via the Allplan GUI. Could you clarify what I do incorrectly in this case?

A related question: Suppose I have two scripts: one that generates architectural elements, and another that performs additional modifications on those elements. In the second script, previously, I filtered selections using MultiElementSelectInteractor with something like WallTier_TypeUUID. If the architectural elements are instead wrapped inside PythonParts, what would be the correct filtering approach? Is the intended workflow to select PythonParts first and then inspect their child elements to check whether they include a WallTier_TypeUUID element?

2. Linking native elements to a PythonPart
I am trying to establish an association between architectural elements and custom annotations created via Python. The approach you suggested seems very promissing, but I am still unclear on how the connection is actually implemented.
The API reference mentions the ConnectToElements class, while the example script uses ElementGeometryConnection; however, it is not entirely clear how either of these establishes a link between the architectural element and the PythonPart.
Additionally, I would like to understand what part of the PythonPart is re-executed when an associated architectural element is modified. Is it only the execute() method, or are other parts of the script re-run as well?

Finally, is there a way to convert an existing PythonPart into standard architectural or geometry elements?
For example, if I have a PythonPart composed of a slab and two lines, is it possible to “explode” it to expose and access those three underlying elements?

Thanks again for your kind help!