Skip to main content

A powerful Python toolkit for multi-instance Archicad automation, supporting the official JSON API and the Tapir Add-On.

Project description

MultiConn Archicad is a Python-based connection object for Archicad's JSON API and its Python wrapper. It is designed to manage multiple open instances of Archicad simultaneously, making it easier to execute commands across multiple instances.

Latest Release License Issues Forks Stars

Features

  • Multi-connection Support: Connect to one, multiple, or all open instances of Archicad.
  • Seamless Integration: Utilizes Archicad's official Python package.
  • Tapir Add-On Integration: Run commands using the Tapir Archicad Add-On framework
  • Efficient I/O Operations: Handles connection management using concurrent or asynchronous code.
  • Project Management: Find and open Archicad projects programmatically.

Installation

You can install the latest version of the package from the following link using pip:

pip install https://github.com/SzamosiMate/multiconn_archicad/releases/download/v0.4.1/multiconn_archicad-0.4.1-py3-none-any.whl
# To include optional Windows dialog handling support:
pip install pywinauto

Prerequisites: Tapir Add-On is Required

This package critically depends on the Tapir Archicad Add-On. You must install the Tapir Add-On in your Archicad application for full functionality.

Specifically, the Tapir Add-On is required for:

  • All commands executed via the core.post_tapir_command() method.
  • Internal commands used by multiconn_archicad to identify running Archicad instances and projects (GetProjectInfo, GetArchicadLocation).

Without the Tapir Add-On installed, key functionalities like discovering Archicad instances, identifying projects, and running any Tapir-specific commands will fail. Please install the latest version of Tapir before using this package.

Usage

⚠️Disclaimer: MultiConn ArchiCAD is functional, stable in practice, and ready for use — it has been successfully used in several recent projects. That said, the library is still under active development: its interfaces may evolve in future releases, and it hasn’t yet undergone extensive formal testing. It’s well-suited for quick scripts and one-off automation tasks. If you’re building something long-term or mission-critical, we recommend pinning the version you’re using and keeping an eye on future updates.

Actions - managing the connection

Actions allow you to manage the state of the connection object. You can connect to or disconnect from Archicad instances, quit instances, or refresh ports. All actions can have multiple types of inputs. For each type of input you have to call the corresponding method of the action. To connect to all available ArchiCAD instances, you have to call the .all() method on .connect ( e.g. conn.connect.all()). The aim of this method is to provide better autocompletion.

Example: Connection Management

from multiconn_archicad import MultiConn, Port

conn = MultiConn()

# connect all ArchiCAD instances that were running at instantiation / the last refresh
conn.connect.all()

# disconnect from the instance at port 19723   
conn.disconnect.from_ports(Port(19723))

# refresh all closed ports - ports with no running archicad instance   
conn.refresh.closed_ports()

# close, and remove from the dict of open port headers the archicad instance specified by ConnHeader
conn.quit.from_headers(conn.open_port_headers[Port(19735)])

Project Management

The MultiConn object provides actions to find and open ArchiCAD projects programmatically.

Finding ArchiCAD Instances

You can use the find_archicad action to locate a specific ArchiCAD instance from a ConnHeader.

from multiconn_archicad import MultiConn, ConnHeader

conn = MultiConn()
conn_header = ConnHeader(Port(19723))

# Find the port for a specific connection header
port = conn.find_archicad.from_header(conn_header)
if port:
    print(f"Found ArchiCAD instance at port: {port}")

Opening Projects

The open_project action allows you to programmatically open ArchiCAD projects.

from multiconn_archicad import MultiConn, ConnHeader, TeamworkCredentials

conn = MultiConn()

# Open a project using a connection header
conn_header = ConnHeader.from_dict(saved_header_data)
port = conn.open_project.from_header(conn_header)
# Optionally, open in demo mode:
port = conn.open_project.from_header(conn_header, demo=True) 

# For teamwork projects, you can provide credentials
credentials = TeamworkCredentials("username", "password")
port = conn.open_project.with_teamwork_credentials(conn_header, credentials)

Switching Projects (Solo Only)

The switch_project action allows you to open a different solo project (.pln) within an already running Archicad instance, without needing to quit and restart. This is useful for quickly changing between solo project files managed by the same Archicad process.

from multiconn_archicad import MultiConn, ConnHeader, Port

conn = MultiConn()
# Assume Archicad is running on port 19723 and port 19725

# Get the header for the project you want to switch *to* (e.g., loaded from a file)
target_header = ConnHeader.from_dict(saved_header_data_for_another_project)

# Specify the port of the *running instance* you want to load the new project into
running_instance_port = Port(19723)

# Switch the project on the running instance
# This will close the current project on port 19723 and open the one defined by target_header
new_header_state = conn.switch_project.from_header(original_port=running_instance_port, new_header=target_header)

# Alternatively, switch using a file path directly
new_path = "C:/path/to/another/project.pln"
new_header_state_from_path = conn.switch_project.from_path(original_port=running_instance_port, new_path=new_path)

Dialog Handling

MultiConn can automatically handle most dialog windows that appear when opening ArchiCAD projects. This is particularly useful for batch operations and automation scripts.

from multiconn_archicad import MultiConn, WinDialogHandler, win_int_handler_factory

# Create a MultiConn instance with a dialog handler
conn = MultiConn(dialog_handler=WinDialogHandler(win_int_handler_factory))

# Dialog windows will be automatically handled when opening projects
conn.open_project.from_header(conn_header)

The current implementation includes:

  • EmptyDialogHandler: Does nothing (default)
  • WinDialogHandler: Waits for ArchiCAD to start, and monitors appearing dialogs. If dialog appears, searches for appropriate handler in win_int_handler factory. Only works on windows.
  • win_int_handler_factory: Provides dialog handleing logic on a dialog by dialog basis for the INT language version. It is an example you should customize for your specific project needs. Even if you end up not modifying it, you should definitely know what it does for what dialog.

Serialization

The MultiConn package allows you to save and load connection configurations, making it easier to work with specific projects across multiple sessions.

Saving Connection Headers

from multiconn_archicad import MultiConn, Port

conn = MultiConn()
conn.connect.all()

# Get a connection header
conn_header = conn.open_port_headers[Port(19723)]

# Convert to dictionary for serialization
header_dict = conn_header.to_dict()

# Save to file using your preferred method
import json
with open('conn_header.json', 'w') as f:
    json.dump(header_dict, f)

Loading Connection Headers

from multiconn_archicad import ConnHeader, TeamworkCredentials

# Load from file
import json
with open('conn_header.json', 'r') as f:
    header_dict = json.load(f)

# Create a header from the dictionary
conn_header = ConnHeader.from_dict(header_dict)

# For teamwork projects, you need to provide credentials
if isinstance(conn_header.archicad_id, TeamworkProjectID):
    credentials = TeamworkCredentials("username", "password")
    # Use the credentials when opening the project
    port = conn.open_project.with_teamwork_credentials(conn_header, credentials)

Note: Passwords are not stored in serialized connection headers for security reasons. You must provide them when loading teamwork projects.

Running Commands

Single Archicad Instance

To run commands on one chosen ArchiCAD instance the MultiConn object has a connection called primary. Calling a command directly from the MultiConn object will send it to the primary instance. The primary connection can be changed by assigning any valid Port, or ConnHeader object to MultiConn.primary.

Example: Running Commands on a Single Archicad Instance

from multiconn_archicad import MultiConn, Port

# After instantiation the primary connection will be the instance with the lowest port number (probably 19723)
conn = MultiConn()

# Set the primary connection to the instance running on port 19725
conn.primary = Port(19725)

# Prints project info from the instance on port 19725
print(conn.core.post_tapir_command("GetProjectInfo"))

Multiple Archicad Instances

The MultiConn object stores references to ConnHeaders for all open ports (ports, with a running ArchiCAD instance). The references are stored in a dictionary at .open_port_headers. This dictionary maps each port to its corresponding connection. Each ConnHeader object has its own command objects for each used command namespace. The MultiConn objects has properties to access 3 subsets of open ports based on the status of the ConnHeaders:

  • active: Successfully connected instances.
  • failed: Instances where the connection attempt failed.
  • pending: Instances with no connection attempt made or disconnected.

Example: Running Commands on Multiple Archicad Instances

from multiconn_archicad import MultiConn

conn = MultiConn()
conn.connect.all()

# Explicit loop to gather elements from all active connections
elements = {}
for port, conn_header in conn.active.items():
    elements[port] = conn_header.standard.commands.GetAllElements()

# Using dictionary comprehension
elements = {
    port: conn_header.standard.commands.GetAllElements()
    for port, conn_header in conn.active.items()
}

Namespaces

The aim of the module is to incorporate all solutions that let users automate ArchiCAD from python. The different solutions are separated into namespaces, accessed from properties of the connection object. One of the planned features is letting users supply a list of namespaces they want to use when creating the connections. At the moment there are only two namespaces:

  • standard: The official ArchiCAD python wrapper.
  • core: Provides simplified methods for interacting with the Archicad API: core.post_command() sends official JSON API commands, while core.post_tapir_command() sends commands specific to the Tapir Add-On.
    • Success Response: Returns only the essential result data (e.g., the content of the "result" or "addOnCommandResponse" field).
    • Error Handling: All errors (network, timeout, API failures, Tapir command issues) are now reported by raising specific exceptions (defined in multiconn_archicad.errors). Calls to post_command and post_tapir_command must be wrapped in try...except blocks.
    • Inspired by Tapir's "aclib".

Example: Using two namespaces together

def run(conn: MultiConn | ConnHeader) -> dict[str, Any]:
    elements = conn.standard.commands.GetAllElements()
    command_parameters = {
        "elements": [element.to_dict() for element in elements],
        "highlightedColors": [[50, 255, 100, 100] for _ in range(len(elements))],
        "wireframe3D": True,
        "nonHighlightedColor": [0, 0, 255, 128],
    }
    return conn.core.post_tapir_command('HighlightElements', command_parameters)

Error Handling

MultiConn Archicad uses a structured exception hierarchy for reporting errors, particularly those originating from the core namespace API calls. This makes error handling more explicit and robust.

  • All library-specific exceptions inherit from MulticonnArchicadError.
  • API Communication Errors: Inherit from APIErrorBase.
    • RequestError: Problems during the request itself (network, connection, timeout, invalid response).
      • Examples: APIConnectionError, CommandTimeoutError, InvalidResponseFormatError.
    • ArchicadAPIError: Errors reported by Archicad or the Tapir Add-On in the response body.
      • Examples: StandardAPIError (from official API), TapirCommandError (from Tapir Add-On).
  • Other Errors: Include issues like ProjectAlreadyOpenError, ProjectNotFoundError, NotFullyInitializedError.

You must wrap calls to core.post_command and core.post_tapir_command in try...except blocks to handle these potential exceptions gracefully.

Example: Handling Core Command Exceptions

from multiconn_archicad.errors import TapirCommandError, RequestError, ArchicadAPIError, APIErrorBase 

try:
    # Attempt to execute a Tapir command
    result = conn.core.post_tapir_command('YourTapirCommandName', command_parameters)
    print(f"Command successful! Result: {result}")

# Handle specific error reported by the Tapir Add-On
except TapirCommandError as e:
    print(f"Tapir command failed: Code={e.code}, Message='{e.message}'")

# Handle broader Archicad API errors (includes StandardAPIError)
except ArchicadAPIError as e:
    print(f"Archicad API error: Code={e.code}, Message='{e.message}'")

# Handle connection/request related errors (timeout, network issues, etc.)
except RequestError as e:
    print(f"Request failed: Message='{e.message}' (Code={e.code})")

# Catch any other potential API-related error (Catches all above errors as well.
# Only this shoud be used if you do not need to handle failiures differently
except APIErrorBase as e:
     print(f"An API error occurred: Code={e.code}, Message='{e.message}'")

New in v0.4: Type-Safe API Models for Tapir and Official JSON APIs

This version introduces a comprehensive set of auto-generated Python models for both the Tapir Add-On and the Official Archicad JSON API. This feature is the result of a sophisticated new pipeline designed to provide a vastly improved developer experience when interacting with Archicad.

Directly working with the JSON APIs often requires manually creating dictionaries for command parameters and parsing raw dictionary responses, which can be error-prone and lacks IDE support. These new models solve this by offering two powerful, complementary solutions:

  1. TypedDicts: Lightweight types for static analysis and IDE autocompletion.
  2. Pydantic Models: Robust models for runtime data validation and parsing.

TypedDicts for Enhanced core Commands

The generated TypedDicts are designed to be used with core.post_command() and core.post_tapir_command() to provide full type hinting for your parameters. By defining the expected structure of the command's dictionary, your IDE can offer autocompletion, and a static type checker (like MyPy or Pyright) can catch structural mistakes before you run your code.

This is especially useful for catching common errors, like forgetting a required wrapper key that the Archicad API expects.

Before (Without TypedDicts):

# A common mistake: providing a list of element GUIDs directly.
# The API actually expects a list of dictionaries, each with an "elementId" key.
# This error would only be caught at runtime, with an error from the Archicad API.
command_parameters = {
    "elements": [
        {"guid": "GUID_1"},
        {"guid": "GUID_2"}
    ],
    "highlightedColors": [[50, 255, 100, 100]],
}
# This call would fail when sent to the API.
conn.core.post_tapir_command('HighlightElements', command_parameters)

After (With TypedDicts for Static Checking):

By using TypedDict in a helper function, your tools can validate the dictionary structure instantly.

# Import the specific TypedDict for the command's parameters
from multiconn_archicad.tapir.dicts.commands import HighlightElementsParameters

def highlight_elements(conn: MultiConn, params: HighlightElementsParameters):
    """A type-safe wrapper for the HighlightElements command."""
    return conn.core.post_tapir_command('HighlightElements', params)

# --- Correct Usage ---
# The dictionary structure matches the TypedDict, so it passes static analysis.
# Note the required `{"elementId": ...}` wrapper.
correct_params = {
    "elements": [
        {"elementId": {"guid": "GUID_1"}},
        {"elementId": {"guid": "GUID_2"}}
    ],
    "highlightedColors": [[0, 255, 0, 128]]
}
highlight_elements(conn, correct_params) # This is valid.

# --- Incorrect Usage ---
# Here, we forget the "elementId" wrapper key.
incorrect_params = {
    "elements": [
        {"guid": "GUID_1"}, # Error is here!
        {"guid": "GUID_2"}
    ],
    "highlightedColors": [[255, 0, 0, 128]]
}

# Your IDE and type checker will immediately flag this line with an error:
# "Argument of type 'dict[str, list[dict[str, str]]]' cannot be assigned
# to parameter 'params' of type 'HighlightElementsParameters'.
# Key 'elementId' is missing from dictionary."
highlight_elements(conn, incorrect_params) # <-- STATIC ERROR!

Pydantic Models for Data Validation and Future Wrappers

Alongside the TypedDicts, the library now includes a complete set of Pydantic models. These are ideal for parsing and validating the JSON responses you receive from the API, ensuring the data conforms to the expected schema at runtime.

They form the foundation for a future high-level wrapper that will provide a more pythonic, object-oriented interface to the APIs.

Example: Parsing an API Response

from multiconn_archicad.tapir.models.commands import GetProjectInfoResult

# Raw dictionary response from the API
response_dict = conn.core.post_tapir_command("GetProjectInfo")

# Parse and validate the response using the Pydantic model
project_info = GetProjectInfoResult.model_validate(response_dict)

# Access data with dot notation and enjoy type safety
if not project_info.isUntitled and project_info.projectName:
    print(f"Connected to project: {project_info.projectName}")

Contributing

Contributions are welcome! Feel free to submit issues, feature requests, or pull requests to help improve MultiConn ArchiCAD.

License

This project is licensed under the MIT License. See the LICENSE file for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

multiconn_archicad-0.4.2.tar.gz (62.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

multiconn_archicad-0.4.2-py3-none-any.whl (75.5 kB view details)

Uploaded Python 3

File details

Details for the file multiconn_archicad-0.4.2.tar.gz.

File metadata

  • Download URL: multiconn_archicad-0.4.2.tar.gz
  • Upload date:
  • Size: 62.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.7.19

File hashes

Hashes for multiconn_archicad-0.4.2.tar.gz
Algorithm Hash digest
SHA256 d4fcc9675dfaa390435f64b22bea21ba006bc9d3a549a90a3576ed558697e558
MD5 88f964ac9dea3a9c286a370f3d9ef22d
BLAKE2b-256 4c732f0fa6a6ec2366a62e2ec1b10e12b144429b03997acaa76926201ca6ac81

See more details on using hashes here.

File details

Details for the file multiconn_archicad-0.4.2-py3-none-any.whl.

File metadata

File hashes

Hashes for multiconn_archicad-0.4.2-py3-none-any.whl
Algorithm Hash digest
SHA256 adb60bbe78a23812bea4765e0510f271949480de3dca57496bf40cc7c7389b70
MD5 c4572a9affb97a00bc95f521207d299d
BLAKE2b-256 9104afa23877e5492f9e38346b217bccdcb88bcc37fba2fbc068d946ef8bf1ad

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page