etm.wccoa.msa.base

Protocol-neutral part of MSA — everything that does not know the payload type.

Importing this package must work without WinCC OA. Applications normally import etm.wccoa.msa.vrpc instead, which re-exports these names.

Package Contents

Classes

AsyncUnaryCall Handle for a running unary RPC — waitable and awaitable at the same time.
PayloadEncryptionMode How a service treats encrypted payloads.
Responder Answers a call that the handler chose not to answer by returning (S3).
ServerContext What a handler can learn about the call it is serving.
ServiceBase Common state of a service: its name and its method table.
ServiceContainer Registers services, starts them, and shuts their threads down again.
ServiceHostingReplica Which half of a redundant system hosts the service.
ServiceHostingType Whether a service is offered once per system or once per manager.
ServiceOptions Options for a service that this manager offers.
ServiceStatus What the manager knows about the addressed service.
Status The outcome of an RPC together with its message text.
StatusCode Outcome of an RPC. Values and names match msa::StatusCode (C++).
StubOptions Options for addressing a service that another manager offers.
StubStatus Where a stub stands between construction and being ready to call.

API

class etm.wccoa.msa.base.AsyncUnaryCall(dispatcher: etm.wccoa.msa.base._dispatcher.OaDispatcher, context: Any, decode: collections.abc.Callable[, etm.wccoa.datatypes.OaVariant], send: collections.abc.Callable[[collections.abc.Callable], None])

Handle for a running unary RPC — waitable and awaitable at the same time.

This is deliberately not a concurrent.futures.Future: cancel() aborts an RPC that is already running, not merely one that has not started yet. Internally the handle does hold such a future, served by the callback executor, so that no continuation ever runs on the OA thread.

Example

>>> call = stub.call_function_async("SayHello", "Bob")
>>> call.result(timeout=2.0)          # blocking, from any thread
>>> await call                        # or, from any event loop

Initialization

Start the RPC by handing send the callback that ends it.

send runs on the OA thread and is expected to return at once; the response arrives later, on that same thread.

result(timeout: float | None = None) → etm.wccoa.datatypes.OaVariant

Wait for the response and return it.

timeout is purely local: on expiry this raises TimeoutError while the RPC keeps running. To limit the RPC itself, pass a deadline when starting the call.

  • Returns: The response value.
  • Raises:
    • RpcError – if the call failed.
    • TimeoutError – if timeout elapsed.

cancel() → None

Abort the RPC. The server learns about it and stops working on it.

property status : etm.wccoa.msa.base._status.Status | None

The final status, or None while the call is still running.

property response_headers : etm.wccoa.datatypes.Metadata | None

Headers sent ahead of the response, or None while the call is running.

They only become readable once the call has finished, because the layer below hands out all four values of a response at the same moment.

This can be found at: etm.wccoa.datatypes.Metadata

property trailing_headers : etm.wccoa.datatypes.Metadata | None

Trailers sent by the service, or None while the call is running.

This can be found at: etm.wccoa.datatypes.Metadata

add_done_callback(fn: collections.abc.Callable[[etm.wccoa.msa.base._client._call.AsyncUnaryCall], None]) → None

Register fn, called with this handle once the call finishes.

The callback runs on the callback executor — never on the OA thread and never on an event loop.

class etm.wccoa.msa.base.PayloadEncryptionMode

Bases: enum.IntEnum

How a service treats encrypted payloads.

Initialization

Initialize self. See help(type(self)) for accurate signature.

DEACTIVATED

0

Payload encryption is off.

OPTIONAL

1

Payload encryption is on but a client may do without it.

MANDATORY

2

Payload encryption is on and a client without it cannot connect.

as_integer_ratio()

bit_count()

bit_length()

conjugate()

class denominator

class imag

class numerator

class real

to_bytes()

name()

value()

class etm.wccoa.msa.base.Responder

Bases: typing.Protocol

Answers a call that the handler chose not to answer by returning (S3).

send(response: etm.wccoa.datatypes.OaValueLike) → None

Send the response. May be called from any thread, exactly once.

send_error(error: Exception) → None

Fail the call. May be called from any thread, exactly once.

exception etm.wccoa.msa.base.RpcError(status: etm.wccoa.msa.base._status.Status, trailing_headers: etm.wccoa.datatypes.Metadata | None = None)

Bases: Exception

Raised when an RPC fails, and raised by a handler to fail it deliberately.

Raising this from a service handler transports both status and trailing_headers to the caller. Any other exception is reported as StatusCode.UNKNOWN carrying str(exc); the traceback stays local.

Initialization

Initialize self. See help(type(self)) for accurate signature.

add_note()

class args

with_traceback()

class etm.wccoa.msa.base.ServerContext

Bases: typing.Protocol

What a handler can learn about the call it is serving.

The manager fills the Oa-Request-… headers itself, so a handler can read the caller’s identity from request_headers and answer with StatusCode.PERMISSION_DENIED if it does not like it.

property method : str

The wire name of the called method.

property deadline : datetime.datetime | None

When the caller stops waiting, or None if unlimited.

property request_headers : etm.wccoa.datatypes.Metadata

Headers sent by the caller, including the Oa-Request-… set.

This can be found at: etm.wccoa.datatypes.Metadata

property response_headers : etm.wccoa.datatypes.Metadata

Headers to send ahead of the response; a handler may add to these.

This can be found at: etm.wccoa.datatypes.Metadata

property trailing_headers : etm.wccoa.datatypes.Metadata

Trailers to send after the response; a handler may add to these.

This can be found at: etm.wccoa.datatypes.Metadata

property cancellation : threading.Event

Set once the caller canceled or the deadline expired.

A handler may check it with is_set() or sleep on it with wait() instead of blocking outright.

class etm.wccoa.msa.base.ServiceBase(service_name: str, protocol_type: str, protocol_version: int)

Common state of a service: its name and its method table.

The method table maps wire names to handlers that work on serialized payloads; adding a payload type is the job of the protocol layer.

Initialization

Build the native service; the protocol layer supplies its identity.

property service_name : str

The name this service is registered under.

class etm.wccoa.msa.base.ServiceContainer(manager: etm.wccoa.manager.Manager)

Registers services, starts them, and shuts their threads down again.

MSA itself has no stop; a container ends by being closed or by the process ending. Because every service owns a thread, Python is the first binding that has to join something, which is what the context manager is for.

Example

>>> with ServiceContainer(mgr) as container:
...     container.register_service(GreeterService())
...     container.start_all_services()

Initialization

register_service(service: etm.wccoa.msa.base._server._service.ServiceBase, options: etm.wccoa.msa.base._options.ServiceOptions | None = None) → None

Add a service.

This must happen before start_all_services().

The options are read here, so the same object may be configured further and used again for the next registration.

  • Raises:
    • RuntimeError – if the services have already been started.
    • ValueError – if the service name is invalid, or if a service of the same name and options is already registered.

start_all_services() → None

Announce all registered services and start their threads.

close() → None

Stop the service threads and release the native server.

Requests that are still waiting are answered as canceled. Idempotent.

class etm.wccoa.msa.base.ServiceHostingReplica

Bases: enum.IntEnum

Which half of a redundant system hosts the service.

Initialization

Initialize self. See help(type(self)) for accurate signature.

NONE

0

Not a redundant system, or the replica does not matter.

LEFT

1

The first replica.

as_integer_ratio()

bit_count()

bit_length()

conjugate()

class denominator

class imag

class numerator

class real

to_bytes()

name()

value()

class etm.wccoa.msa.base.ServiceHostingType

Bases: enum.IntEnum

Whether a service is offered once per system or once per manager.

Initialization

Initialize self. See help(type(self)) for accurate signature.

GLOBAL

0

One service for the whole system; the client does not address a manager.

MANAGER_SPECIFIC

1

One service per manager; the client addresses type, number and replica.

as_integer_ratio()

bit_count()

bit_length()

conjugate()

class denominator

class imag

class numerator

class real

to_bytes()

name()

value()

class etm.wccoa.msa.base.ServiceOptions

Options for a service that this manager offers.

Example

>>> ServiceOptions().with_manager_specific_service()
ServiceOptions(hosting=<ServiceHostingType.MANAGER_SPECIFIC: 1>, ...)

hosting : etm.wccoa.msa.base._options.ServiceHostingType

None

Whether the service is global or manager specific.

service_name_suffix : str = <Multiline-String>

payload_encryption : etm.wccoa.msa.base._options.PayloadEncryptionMode | None

None

None falls back to the project setting, mirroring std::optional.

with_global_service() → etm.wccoa.msa.base._options.ServiceOptions

Switch to global hosting and return self.

  • Returns: These options, for chaining.
with_manager_specific_service() → etm.wccoa.msa.base._options.ServiceOptions

Switch to manager specific hosting and return self.

  • Returns: These options, for chaining.

class etm.wccoa.msa.base.ServiceStatus

Bases: enum.IntEnum

What the manager knows about the addressed service.

Initialization

Initialize self. See help(type(self)) for accurate signature.

UNKNOWN

None

The status could not be determined.

ERROR

0

The service is in an error state, or the service itself is unknown.

UNAVAILABLE

1

The service exists but is not reachable, for instance because its manager is down.

READY

2

The service accepts messages.

as_integer_ratio()
bit_count()
bit_length()
conjugate()
class denominator
class imag
class numerator
class real
to_bytes()
name()
value()

class etm.wccoa.msa.base.Status

The outcome of an RPC together with its message text.

OK : ClassVar[etm.wccoa.msa.base._status.Status]

None

Successful call without a text, matching msa::Status::OK.

CANCELED : ClassVar[etm.wccoa.msa.base._status.Status]

None

Canceled call without a text, matching msa::Status::CANCELED.

UNKNOWN : ClassVar[etm.wccoa.msa.base._status.Status]

None

Unknown failure without a text, matching msa::Status::UNKNOWN.

code : etm.wccoa.msa.base._status.StatusCode

None

text : str = <Multiline-String>
class etm.wccoa.msa.base.StatusCode

Bases: enum.IntEnum

Outcome of an RPC. Values and names match msa::StatusCode (C++).

Initialization

Initialize self. See help(type(self)) for accurate signature.

OK

0

The call succeeded.

CANCELED

1

The call was canceled, typically by the caller.

UNKNOWN

2

Unknown error — also the fallback for an unhandled handler exception.

INVALID_ARGUMENT

3

The client specified an invalid argument.

DEADLINE_EXCEEDED

4

The deadline expired before the call could complete.

NOT_FOUND

5

A requested entity was not found.

ALREADY_EXISTS

6

The entity a client attempted to create already exists.

PERMISSION_DENIED

7

The caller is not authorized to execute the operation.

RESOURCE_EXHAUSTED

8

A resource has been exhausted.

FAILED_PRECONDITION

9

The system is not in a state required for the operation.

ABORTED

10

The operation was aborted.

OUT_OF_RANGE

11

The operation was attempted past the valid range.

UNIMPLEMENTED

12

The method is not implemented or not registered by the service.

INTERNAL

13

Framework failure — serialization, deserialization or dispatch.

UNAVAILABLE

14

The service is currently unavailable, for example while shutting down.

DATA_LOSS

15

Unrecoverable data loss or corruption.

UNAUTHENTICATED

16

The caller could not be authenticated.

as_integer_ratio()
bit_count()
bit_length()
conjugate()
class denominator
class imag
class numerator
class real
to_bytes()
name()
value()
class etm.wccoa.msa.base.StubOptions

Options for addressing a service that another manager offers.

The manager fields are only read when hosting is ServiceHostingType.MANAGER_SPECIFIC; use with_manager_specific_service() to set them together.

hosting : etm.wccoa.msa.base._options.ServiceHostingType

None

Whether the addressed service is global or manager specific.

manager_number : int

0

Number of the hosting manager.

replica : etm.wccoa.msa.base._options.ServiceHostingReplica

None

Replica of the hosting manager in a redundant system.

dist_system_name : str = <Multiline-String>
service_name_suffix : str = <Multiline-String>
with_global_service() → etm.wccoa.msa.base._options.StubOptions

Switch to global hosting and return self.

  • Returns: These options, for chaining.
with_manager_specific_service(manager_type: etm.wccoa.datatypes.OaManagerType, manager_number: int, replica: etm.wccoa.msa.base._options.ServiceHostingReplica = ServiceHostingReplica.NONE) → etm.wccoa.msa.base._options.StubOptions

Switch to manager specific hosting, set the address, return self.

  • Returns: These options, for chaining.
class etm.wccoa.msa.base.StubStatus

Bases: enum.IntEnum

Where a stub stands between construction and being ready to call.

Initialization

Initialize self. See help(type(self)) for accurate signature.

CREATED

0

Constructed; the constructor does not communicate.

ON_INIT

1

Initialization is running.

INIT_FAILED

2

Initialization failed; calls will fail too.

INIT_DONE

3

Ready to call.

as_integer_ratio()
bit_count()
bit_length()
conjugate()
class denominator
class imag
class numerator
class real
to_bytes()
name()
value()