Skip to content

Commit

Permalink
Xml mdib (#401)
Browse files Browse the repository at this point in the history
<!--- Provide a general summary of your changes in the title above -->
<!--- Link the corresponding issues after you created the pull request
-->

## Types of changes
<!--- What types of changes does your code introduce? Put an `x` in all
the boxes that apply: -->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)

## Checklist:
<!--- Go over all the following points, and put an `x` in all the boxes
that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're
here to help! -->
- [ ] I have updated the [changelog](../CHANGELOG.md) accordingly.
- [ ] I have added tests to cover my changes.
  • Loading branch information
deichmab-draeger authored Feb 14, 2025
1 parent 5291b9e commit 5196779
Show file tree
Hide file tree
Showing 48 changed files with 6,560 additions and 1,139 deletions.
2 changes: 1 addition & 1 deletion codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ coverage:
default:
target: auto # https://docs.codecov.com/docs/commit-status#target
# test coverage may change a bit depending on the computer executed
threshold: 1% # https://docs.codecov.com/docs/commit-status#threshold
threshold: 2% # https://docs.codecov.com/docs/commit-status#threshold
17 changes: 16 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,11 @@ extend-ignore = [# https://docs.astral.sh/ruff/settings/#extend-ignore
"S311", # https://docs.astral.sh/ruff/rules/suspicious-non-cryptographic-random-usage/
"SIM102", # collapsible-if
"T201", # https://docs.astral.sh/ruff/rules/print/
"TRY003", #https://docs.astral.sh/ruff/rules/raise-vanilla-args/
"TRY003", # https://docs.astral.sh/ruff/rules/raise-vanilla-args/
"FBT001", # https://docs.astral.sh/ruff/rules/boolean-type-hint-positional-argument/
"FBT002", # https://docs.astral.sh/ruff/rules/boolean-default-value-positional-argument/
"FBT003", # https://docs.astral.sh/ruff/rules/boolean-positional-value-in-call/
"S320", # https://docs.astral.sh/ruff/rules/suspicious-xmle-tree-usage/
]

[tool.ruff.format]
Expand All @@ -145,6 +149,17 @@ max-doc-length = 120 # https://docs.astral.sh/ruff/settings/#max-doc-length

[tool.ruff.lint.per-file-ignores]
"__init__.py" = ["D104"]
"tests/*" = [
"SLF001", # Private member accessed
"D101", # Missing docstring in public class
"D102", # Missing docstring in public method
"D103", # Missing docstring in public function
"PLR0915", # Too many statements
"PLR2004", # Magic value used in comparison
"E722", # Do not use bare `except`
"PT009", # Use a regular `assert` instead of unittest-style `assertEqual`
"PT027", # Use `pytest.raises` instead of unittest-style `assertRaises`
]

[tool.mypy]
python_version = "3.9" # https://mypy.readthedocs.io/en/stable/config_file.html#confval-python_version
Expand Down
42 changes: 23 additions & 19 deletions src/sdc11073/consumer/consumerimpl.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
from sdc11073.consumer.subscription import ConsumerSubscriptionManagerProtocol
from sdc11073.definitions_base import AbstractDataModel, BaseDefinitions
from sdc11073.dispatch.request import RequestData
from sdc11073.entity_mdib.entity_consumermdib import EntityConsumerMdib
from sdc11073.mdib.consumermdib import ConsumerMdib
from sdc11073.pysoap.msgfactory import MessageFactory
from sdc11073.pysoap.msgreader import MessageReader, ReceivedMessage
Expand Down Expand Up @@ -101,7 +102,7 @@ def _read_wsdl(self, soap_client: SoapClientProtocol, wsdl_url: str):
self.wsdl_string = self.wsdl_bytes.decode(encoding)
logging.getLogger(commlog.WSDL).debug(self.wsdl_string)
except etree.XMLSyntaxError as ex:
self._logger.error( # noqa: PLE1205
self._logger.error( # noqa: PLE1205 TRY400
'could not read wsdl from {}: error={}, data=\n{}', actual_path, ex, self.wsdl_bytes)

def __repr__(self) -> str:
Expand All @@ -128,8 +129,9 @@ def __init__(self, sdc_consumer: SdcConsumer):

def on_notification(self, message_data: ReceivedMessage):
observable_name = self._lookup.get(message_data.action)
if observable_name is None:
raise ValueError(f'unknown message {message_data.action}')
if observable_name is None: # pragma: no cover
how_i_hate_this = f'unknown message {message_data.action}'
raise ValueError(how_i_hate_this)
setattr(self._sdc_consumer, observable_name, message_data)

def _mk_lookup(self) -> dict[str, str]:
Expand Down Expand Up @@ -162,7 +164,7 @@ class SdcConsumer:

subscription_status = properties.ObservableProperty({})
# indicates whether all subscriptions have been subscribed to and are renewed successfully
is_connected = properties.ObservableProperty(False)
is_connected = properties.ObservableProperty(default_value=False)

# observable properties for all notifications
# all incoming Notifications can be observed in state_event_report ( as soap envelope)
Expand All @@ -188,7 +190,7 @@ class SdcConsumer:

SSL_CIPHERS = None # None : use SSL default

def __init__(self, device_location: str, # noqa: PLR0913
def __init__(self, device_location: str, # noqa: PLR0913 PLR0915
sdc_definitions: type[BaseDefinitions],
ssl_context_container: sdc11073.certloader.SSLContextContainer | None,
epr: str | uuid.UUID | None = None,
Expand All @@ -199,7 +201,7 @@ def __init__(self, device_location: str, # noqa: PLR0913
request_chunk_size: int = 0,
socket_timeout: int = 5,
force_ssl_connect: bool = False,
alternative_hostname: str | None = None
alternative_hostname: str | None = None,
):
"""Construct a SdcConsumer.
Expand Down Expand Up @@ -306,7 +308,7 @@ def __init__(self, device_location: str, # noqa: PLR0913
self._shared_http_server_param: Any | None = None
self._check_get_service_param: bool | None = None

def set_mdib(self, mdib: ConsumerMdib | None):
def set_mdib(self, mdib: ConsumerMdib | EntityConsumerMdib | None):
"""SdcConsumer sometimes must know the mdib data (e.g. Set service, activate method)."""
if mdib is not None and self._mdib is not None:
raise ApiUsageError('SdcConsumer has already an registered mdib')
Expand Down Expand Up @@ -353,8 +355,7 @@ def base_url(self) -> str:
p = urlparse(self._http_server.base_url)
tmp = f'{p.scheme}://{self._alternative_hostname or self._network_adapter.ip}:{p.port}{p.path}'
sep = '' if tmp.endswith('/') else '/'
tmp = f'{tmp}{sep}{self.path_prefix}/'
return tmp
return f'{tmp}{sep}{self.path_prefix}/'

def mk_subscription(self, dpws_hosted: HostedServiceType,
filter_type: eventing_types.FilterType,
Expand Down Expand Up @@ -468,7 +469,7 @@ def subscription_mgr(self) -> ConsumerSubscriptionManagerProtocol:
"""Return the subscription manager."""
return self._subscription_mgr

def start_all(self, not_subscribed_actions: Iterable[str] | None = None,
def start_all(self, not_subscribed_actions: Iterable[str] | None = None, #noqa: C901 PLR0915
fixed_renew_interval: float | None = None,
shared_http_server: Any | None = None,
check_get_service: bool = True) -> None:
Expand Down Expand Up @@ -503,8 +504,9 @@ def start_all(self, not_subscribed_actions: Iterable[str] | None = None,
self._network_adapter)

# only GetService is mandatory!!!
if check_get_service and self.get_service_client is None:
raise RuntimeError(f'GetService not detected! found services = {list(self._service_clients.keys())}')
if check_get_service and self.get_service_client is None: # pragma: no cover
msg = f'GetService not detected! found services = {list(self._service_clients.keys())}'
raise RuntimeError(msg)

self._start_event_sink(shared_http_server)

Expand Down Expand Up @@ -555,7 +557,7 @@ def start_all(self, not_subscribed_actions: Iterable[str] | None = None,
self.do_subscribe(dpws_hosted, filter_type, subscribe_actions)
except Exception: # noqa: BLE001
self.all_subscribed = False # => don't log errors when mdib versions are missing
self._logger.error('start_all: could not subscribe: error = {}, actions= {}', # noqa: PLE1205
self._logger.error('start_all: could not subscribe: error = {}, actions= {}', # noqa: PLE1205 TRY400
traceback.format_exc(), subscribe_actions)

def _update_is_connected(subscription_status: dict[str, bool]):
Expand Down Expand Up @@ -584,7 +586,7 @@ def stop_all(self, unsubscribe: bool = True):
self._stop_event_sink()

def restart(self):
"""forget existing data and restart from the beginning."""
"""Forget existing data and restart from the beginning."""
mdib = self._mdib # keep existing mdib connection
self.stop_all() # with unsubscribe
# start with the same parameters as initially
Expand Down Expand Up @@ -718,7 +720,7 @@ def _start_event_sink(self, shared_http_server: Any):
self._http_server.start()
self._http_server.started_evt.wait(timeout=5)
# it sometimes still happens that http server is not completely started without waiting.
# TODO: find better solution, see issue #320
# find better solution, see issue #320
time.sleep(1)
self._logger.info('serving EventSink on {}', self._http_server.base_url) # noqa: PLE1205
else:
Expand All @@ -740,15 +742,16 @@ def _on_subscription_end(self, request_data: RequestData) -> EmptyResponse:
return EmptyResponse()

def __str__(self) -> str:
return f'SdcConsumer to {self.host_description.this_device} {self.host_description.this_model} on {self._device_location}'
return (f'SdcConsumer to {self.host_description.this_device} {self.host_description.this_model} '
f'on {self._device_location}')

@classmethod
def from_wsd_service(cls, wsd_service: Service, # noqa: PLR0913
ssl_context_container: sdc11073.certloader.SSLContextContainer | None,
validate: bool = True,
log_prefix: str = '',
default_components: SdcConsumerComponents | None = None,
specific_components: SdcConsumerComponents | None = None):
specific_components: SdcConsumerComponents | None = None) -> SdcConsumer:
"""Construct a SdcConsumer from a Service.
:param wsd_service: a wsdiscovery.Service instance
Expand All @@ -760,8 +763,9 @@ def from_wsd_service(cls, wsd_service: Service, # noqa: PLR0913
:return:
"""
device_locations = wsd_service.x_addrs
if not device_locations:
raise RuntimeError(f'discovered Service has no address!{wsd_service}')
if not device_locations: # pragma: no cover
msg = f'discovered Service has no address!{wsd_service}'
raise RuntimeError(msg)
device_location = device_locations[0]
for sdc_definition in ProtocolsRegistry.protocols:
if sdc_definition.types_match(wsd_service.types):
Expand Down
9 changes: 5 additions & 4 deletions src/sdc11073/consumer/serviceclients/contextservice.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
"""The module contains the implementation of the BICEPS context service."""
from __future__ import annotations

from typing import TYPE_CHECKING
Expand Down Expand Up @@ -41,13 +42,13 @@ def mk_proposed_context_object(self, descriptor_handle: str,
mdib = self._mdib_wref()
if mdib is None:
raise ApiUsageError('no mdib information')
context_descriptor_container = mdib.descriptions.handle.get_one(descriptor_handle)
context_entity = mdib.entities.by_handle(descriptor_handle)
if handle is None:
cls = data_model.get_state_container_class(context_descriptor_container.STATE_QNAME)
obj = cls(descriptor_container=context_descriptor_container)
cls = data_model.get_state_container_class(context_entity.descriptor.STATE_QNAME)
obj = cls(descriptor_container=context_entity.descriptor)
obj.Handle = descriptor_handle # this indicates that this is a new context state
else:
_obj = mdib.context_states.handle.get_one(handle)
_obj = context_entity.states[handle]
obj = _obj.mk_copy()
return obj

Expand Down
Empty file.
Loading

0 comments on commit 5196779

Please sign in to comment.