Metadata-Version: 2.5
Name: unitelabs-sila
Version: 0.11.0
Summary: An un-opinionated SiLA 2 library.
Project-URL: homepage, https://sila-standard.com
Project-URL: repository, https://gitlab.com/unitelabs/sila2/sila-python
Project-URL: documentation, https://gitlab.com/unitelabs/sila2/sila-python/-/README.md
Project-URL: Bug Tracker, https://gitlab.com/unitelabs/sila2/sila-python/-/issues
Author-email: UniteLabs <developers+sila@unitelabs.io>
License-Expression: MIT
License-File: LICENSE
Keywords: SiLA 2,automation,connectivity,laboratory
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Healthcare Industry
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development :: Libraries
Requires-Python: <4.0,>=3.10
Requires-Dist: grpcio>=1.75.1
Requires-Dist: jsonschema~=4.25
Requires-Dist: typing-extensions; python_version < '3.13'
Requires-Dist: xmlschema~=4.2
Provides-Extra: dev
Requires-Dist: commitizen; extra == 'dev'
Requires-Dist: cryptography>=43.0.3; extra == 'dev'
Requires-Dist: pre-commit; extra == 'dev'
Requires-Dist: ruff; extra == 'dev'
Provides-Extra: docs
Requires-Dist: unitelabs-jsondocs[clog]~=0.4.3; extra == 'docs'
Provides-Extra: test
Requires-Dist: pytest; extra == 'test'
Requires-Dist: pytest-asyncio; extra == 'test'
Requires-Dist: pytest-cov; extra == 'test'
Description-Content-Type: text/markdown

# Unitelabs SiLA Python Library

A Python library for creating SiLA 2 clients and servers. This flexible and unopinionated library gives you everything needed to create a SiLA 2 1.1 compliant Python application. It adheres to the [SiLA 2 specification](https://sila2.gitlab.io/sila_base/) and is used by the [UniteLabs CDK](https://gitlab.com/unitelabs/cdk/python-cdk) to enable rapid development of cloud-native SiLA Servers with a code-first approach.

## Getting Started

### Prerequisites

Ensure you have Python 3.10+ installed. You can install Python from [python.org](https://www.python.org/downloads/).

### Quickstart

To get started quickly with your first connector, we recommend to use our [UniteLabs CDK](https://gitlab.com/unitelabs/cdk/python-cdk). Use [Cookiecutter](https://www.cookiecutter.io) to create your project base on our [Connector Factory](https://gitlab.com/unitelabs/cdk/connector-factory) starter template:

```bash
cookiecutter git@gitlab.com:unitelabs/cdk/connector-factory.git
```

### Installation

Install the latest version of the library into your Python project:

```python
pip install unitelabs-sila
```

## Usage

### Client

To start using the SiLA Python library as a client:

1. Import and configure your SiLA client instance:

   ```python
   import asyncio

   from sila.client import Client, ClientConfig

   async def main():
      client = Client(ClientConfig(hostname="localhost", port=50052, tls=False))
      await client.open()

      print(await client.get_server_name())
      print(await client.get_server_uuid())

      await client.close()

   asyncio.run(main())
   ```

2. Run your server:

   ```bash
   python your_script.py
   ```

### Errors and timeouts

Every error the client raises while talking to a server is a `SiLAError`. Catch its subclasses to tell them apart:

- `SiLATimeoutError`: a timeout elapsed. It's a `SiLAConnectionError`, so catch it first.
- `SiLAConnectionError`: the server is unavailable or the connection failed. `status_code` holds the gRPC status code, if the error comes from a call.
- `ValidationError`: a command parameter is missing or invalid. `parameter` names it.
- `DefinedExecutionError`: an error the feature declares in its definition.
- `UndefinedExecutionError`: any other failure on the server, including a defined execution error the client doesn't know.
- `FrameworkError` and `BinaryTransferError`: the SiLA protocol was used incorrectly, or a large binary failed to transfer. Their subclasses, like `InvalidMetadata`, tell which. `CommandExecutionNotAccepted` means the command was not performed: the server refused it, or the client never sent it. In the second case, its `__cause__` is the connection error.

Timeouts are in milliseconds. A request without a `timeout` uses the client's `default_timeout`, and waits indefinitely when neither is set. A timeout on a subscription only bounds setting it up, not how long it runs. `ObservableProperty.read()` is the exception: its timeout also bounds the wait for the first value.

A command whose timeout runs out before it was sent raises `CommandExecutionNotAccepted` instead. So does a command on a connection that is already closed, or whose binary parameter failed to upload. The command was not performed, so running it again is safe. Once the client handed a command to gRPC, a `SiLAConnectionError` or `SiLATimeoutError` can't tell whether the server got it, so the server may have run it: check its state before running it again.

```python
from sila.client import SiLAConnectionError, SiLATimeoutError

try:
    await client.open(timeout=5000)
except SiLATimeoutError:
    print("The server didn't answer within 5 s.")
except SiLAConnectionError as error:
    print(f"The connection failed while loading the features: {error}")
```

### Server

To start using the SiLA Python library as a server:

1. Import and configure your SiLA server instance:

   ```python
   import asyncio

   from sila.server import Server
   from your_project.features import your_feature

   async def main():
       server = Server({"port": 50000})
       server.add_feature(your_feature)
       await server.start()

   asyncio.run(main())
   ```

2. To implement a custom SiLA Feature, create a feature definition following the SiLA2 specification:

   ```python
   from sila.server import Feature, UnobservableCommand

   your_feature = Feature(...)
   your_method = UnobservableCommand(...)
   your_method.add_to_feature(your_feature)
   ```

3. Run your server:

   ```bash
   python your_script.py
   ```

> Important: Without implementing the required SiLA Service Feature, your SiLA Server will not be fully compliant with the standard. For easier compliance, consider using the [UniteLabs CDK](https://gitlab.com/unitelabs/cdk/python-cdk), which handles this automatically.

## Contribute

Submit and share your work at <https://hub.unitelabs.io>.

We encourage you to submit feature requests and bug reports through the GitLab issue system. Please include a clear description of the issue or feature you are proposing. If you have further questions, issues, or suggestions for improvement, don't hesitate to reach out to us at [developers@unitelabs.io](mailto:developers+sila@unitelabs.io).

Join the conversation! Stay up to date with the latest developments by joining the Python channel in the [SiLA Slack](https://sila-standard.org/slack).

## License

Distributed under the MIT License. See [MIT license](LICENSE) for more information.
