declarative-opcua-server
declarative-opcua-server creates an opinionated synchronous OPC UA server from three flat dictionaries of annotated Python functions. It is intended for small
adapters that need a predictable Status, Parameters, and Methods address space without building nodes manually.
Installation
python -m pip install --upgrade pip
python -m pip install declarative-opcua-server
Python 3.8.3 and later are supported. The distribution selects a compatible asyncua release for the active Python version and caps the final cryptography
line that supports Python 3.8. Upgrade the old pip bundled with Python 3.8.3 before installing.
Example
import time
import typing
import declarative_opcua_server
state = {"height": 10.0}
def read_height() -> float:
return state["height"]
def write_height(height: float) -> None:
state["height"] = height
def load_program(program: str) -> str:
return "Loaded " + program
def list_programs() -> typing.List[str]:
return ["Main.urp", "Production/PickPart.urp"]
server = declarative_opcua_server.create_server(
status_interface={"ActualHeight": read_height},
parameter_interface={"TargetHeight": write_height},
method_interface={"LoadProgram": load_program, "ListPrograms": list_programs},
endpoint="opc.tcp://127.0.0.1:4840/",
namespace="urn:example:robot",
root_object="Robot",
)
with server:
while True:
time.sleep(1.0)
create_server() returns a plain, unstarted asyncua.sync.Server. Callers retain the normal start(), stop(), and context-manager lifecycle.
Refreshing methods
refresh_method(provider) can be used directly as one value in the method dictionary. The provider returns the complete dynamic portion of the interface.
Invoking the exposed refresh method calls it again, validates the result, adds and removes nodes, and returns the sorted dynamic method names:
import typing
dynamic_methods: typing.Dict[str, typing.Callable[..., typing.Any]] = {}
def run_main() -> None:
print("run Main.urp")
def provide_methods() -> typing.Mapping[str, typing.Callable[..., typing.Any]]:
return dynamic_methods
dynamic_methods["StartProgram_Main"] = run_main
server = declarative_opcua_server.create_server(
status_interface={},
parameter_interface={},
method_interface={"RefreshMethods": declarative_opcua_server.refresh_method(provide_methods)},
)
Method callbacks run on a worker thread, so RefreshMethods() completes only after the replacement is visible to subsequent OPC UA browsing. A provider mapping
is the complete dynamic interface, not a patch. Fixed methods remain in the original dictionary. If a refreshed callback keeps the same name and signature, its
existing node and NodeId are retained while the callable behind it is updated.
update_method_interface() remains available for callers that already own their own refresh lifecycle. It applies one validated complete replacement for the
whole Methods folder.
Address space
The example creates:
Objects/
Robot/
Status/
ActualHeight
Parameters/
TargetHeight
Methods/
LoadProgram(program) -> String
ListPrograms() -> String[]
The selected dictionary defines each callable's role:
- A status getter accepts no required arguments and declares a return type. It becomes a polled read-only variable.
- A parameter setter accepts one required annotated argument and returns no value. It becomes a writable variable whose accepted writes invoke the setter.
- A method exposes required annotated arguments as OPC UA inputs and an annotated return as an optional output.
Defaulted status, parameter, and method arguments are treated as bound application configuration rather than OPC UA inputs. This makes configured callables useful without adding wrapper functions.
Supported annotations
| Python annotation | OPC UA variant type |
|---|---|
bool |
Boolean |
int |
Int64 |
float |
Double |
str |
String |
bytes |
ByteString |
typing.List[T] |
One-dimensional T |
T must be one of the supported scalar annotations. Unsupported or unresolved signatures fail during server creation.
Scope and security
The package intentionally does not provide arbitrary folders, custom node classes, stable NodeId configuration, events, application schemas, or protocol
adapters. Applications requiring a general OPC UA framework should use asyncua directly.
The current server defaults to anonymous access and NoSecurity. It is suitable for controlled development and isolated industrial networks; certificate and
authentication configuration should be added before use on an untrusted network.
Development
From this package directory:
python -m pip install -e ".[dev]"
python -m pytest tests
python -m mypy
python -m build
python -m twine check dist/*
Tests use a real asyncua client to verify browsing, status polling, parameter writes, typed method calls, and lifecycle behavior.
Release history is recorded in the changelog. The gateway integration is
validated independently in ur_dashboard_to_opcua_gateway.
License
This project is licensed under the MIT License. See LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file declarative_opcua_server-0.4.0.tar.gz.
File metadata
- Download URL: declarative_opcua_server-0.4.0.tar.gz
- Upload date:
- Size: 17.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
32ff34a08b1d262cc50d6b1dff94c863c3d1c64f9b5b538baf03c9f6d1ae4a36
|
|
| MD5 |
a1dd3c728d17db68001e90b94fa3dd5f
|
|
| BLAKE2b-256 |
fec0c4d768f4b5d1059986536ee95ca1dd47b99e4af3f1282f17df441db097cf
|
Provenance
The following attestation bundles were made for declarative_opcua_server-0.4.0.tar.gz:
Publisher:
release.yml on CraigBuilds/declarative-opcua-server
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
declarative_opcua_server-0.4.0.tar.gz -
Subject digest:
32ff34a08b1d262cc50d6b1dff94c863c3d1c64f9b5b538baf03c9f6d1ae4a36 - Sigstore transparency entry: 2224975317
- Sigstore integration time:
-
Permalink:
CraigBuilds/declarative-opcua-server@878981fe24ed713ec880b23e9ba829f5beef1ab1 -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/CraigBuilds
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@878981fe24ed713ec880b23e9ba829f5beef1ab1 -
Trigger Event:
push
-
Statement type:
File details
Details for the file declarative_opcua_server-0.4.0-py3-none-any.whl.
File metadata
- Download URL: declarative_opcua_server-0.4.0-py3-none-any.whl
- Upload date:
- Size: 12.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8777ffdae18fb5d7e3944b44dda1ac12f7dd3adf8a81ebc13871ceeea1495d41
|
|
| MD5 |
44803ee8839861185261647edb71308c
|
|
| BLAKE2b-256 |
4d1bc05b814567e2bb9910c4e8d4359dbe4b60446a185807809e2638603679c4
|
Provenance
The following attestation bundles were made for declarative_opcua_server-0.4.0-py3-none-any.whl:
Publisher:
release.yml on CraigBuilds/declarative-opcua-server
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
declarative_opcua_server-0.4.0-py3-none-any.whl -
Subject digest:
8777ffdae18fb5d7e3944b44dda1ac12f7dd3adf8a81ebc13871ceeea1495d41 - Sigstore transparency entry: 2224975607
- Sigstore integration time:
-
Permalink:
CraigBuilds/declarative-opcua-server@878981fe24ed713ec880b23e9ba829f5beef1ab1 -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/CraigBuilds
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@878981fe24ed713ec880b23e9ba829f5beef1ab1 -
Trigger Event:
push
-
Statement type: