Removed circular dependency.

Workaround for the circular dependency between
`platypush.entities.bluetooth` and `platypush.plugins.bluetooth.model`.

Unentangling the circular dependency would require way too much work,
since the entity model provides several helpers and properties that
depend on the plugin's model.

The workaround in this commit is to simply push those imports down in
the methods that use them, so they won't be imported until those methods
are called, as well as removing some type annotations that depended on
those objects.
This commit is contained in:
Fabio Manganiello 2023-03-26 15:30:57 +02:00
parent 3bb2336b3a
commit 276aff757b
Signed by untrusted user: blacklight
GPG key ID: D90FBA7F76362774
2 changed files with 31 additions and 28 deletions

View file

@ -1,4 +1,4 @@
from typing import Dict, Iterable, List
from typing import Iterable, List
from typing_extensions import override
from sqlalchemy import (
@ -11,12 +11,6 @@ from sqlalchemy import (
)
from platypush.common.db import Base
from platypush.plugins.bluetooth.model import (
MajorDeviceClass,
MajorServiceClass,
MinorDeviceClass,
ServiceClass,
)
from ..devices import Device
from ._service import BluetoothService
@ -80,7 +74,9 @@ if 'bluetooth_device' not in Base.metadata:
}
@property
def major_device_class(self) -> MajorDeviceClass:
def major_device_class(self):
from platypush.plugins.bluetooth.model import MajorDeviceClass
ret = MajorDeviceClass.UNKNOWN
if self._major_device_class:
matches = [
@ -95,11 +91,13 @@ if 'bluetooth_device' not in Base.metadata:
return ret
@major_device_class.setter
def major_device_class(self, value: MajorDeviceClass):
def major_device_class(self, value):
self._major_device_class = value.value.name
@property
def minor_device_classes(self) -> List[MinorDeviceClass]:
def minor_device_classes(self) -> list:
from platypush.plugins.bluetooth.model import MinorDeviceClass
ret = []
for dev_cls in self._minor_device_classes or []:
matches = [cls for cls in MinorDeviceClass if cls.value.name == dev_cls]
@ -110,11 +108,13 @@ if 'bluetooth_device' not in Base.metadata:
return ret
@minor_device_classes.setter
def minor_device_classes(self, value: Iterable[MinorDeviceClass]):
def minor_device_classes(self, value: Iterable):
self._minor_device_classes = [cls.value.name for cls in (value or [])]
@property
def major_service_classes(self) -> List[MajorServiceClass]:
def major_service_classes(self) -> list:
from platypush.plugins.bluetooth.model import MajorServiceClass
ret = []
for dev_cls in self._major_service_classes or []:
matches = [
@ -127,7 +127,7 @@ if 'bluetooth_device' not in Base.metadata:
return ret
@major_service_classes.setter
def major_service_classes(self, value: Iterable[MajorServiceClass]):
def major_service_classes(self, value: Iterable):
self._major_service_classes = [cls.value.name for cls in (value or [])]
@property
@ -142,11 +142,13 @@ if 'bluetooth_device' not in Base.metadata:
]
@property
def known_services(self) -> Dict[ServiceClass, "BluetoothService"]:
def known_services(self) -> dict:
"""
Known services exposed by the device, indexed by
:class:`platypush.plugins.bluetooth.model.ServiceClass` enum value.
"""
from platypush.plugins.bluetooth.model import ServiceClass
return {
child.service_class: child
for child in self.children

View file

@ -1,7 +1,7 @@
from typing import Union
from typing_extensions import override
from uuid import UUID
from typing_extensions import override
from sqlalchemy import (
Boolean,
Column,
@ -12,11 +12,6 @@ from sqlalchemy import (
from platypush.common.db import Base
from platypush.entities import Entity
from platypush.plugins.bluetooth.model import (
Protocol,
RawServiceClass,
ServiceClass,
)
if 'bluetooth_service' not in Base.metadata:
@ -56,7 +51,7 @@ if 'bluetooth_service' not in Base.metadata:
}
@staticmethod
def to_uuid(value: Union[str, RawServiceClass]) -> RawServiceClass:
def to_uuid(value):
"""
Convert a raw UUID string to a service class UUID.
"""
@ -72,18 +67,18 @@ if 'bluetooth_service' not in Base.metadata:
return int(value, 16)
@property
def uuid(self) -> RawServiceClass:
def uuid(self):
"""
Getter for the service class UUID.
"""
return self.to_uuid(self._uuid)
@uuid.setter
def uuid(self, value: Union[RawServiceClass, str]):
def uuid(self, value):
"""
Setter for the service class UUID.
"""
uuid: Union[RawServiceClass, str] = self.to_uuid(value)
uuid = self.to_uuid(value)
if isinstance(uuid, int):
# Hex-encoded 16-bit UUID case
uuid = f'{uuid:04X}'
@ -91,20 +86,24 @@ if 'bluetooth_service' not in Base.metadata:
self._uuid = str(uuid)
@property
def protocol(self) -> Protocol:
def protocol(self):
"""
Getter for the protocol used by the service.
"""
from platypush.plugins.bluetooth.model import Protocol
try:
return Protocol(self._protocol)
except ValueError:
return Protocol.UNKNOWN
@protocol.setter
def protocol(self, value: Union[str, Protocol]):
def protocol(self, value):
"""
Setter for the protocol used by the service.
"""
from platypush.plugins.bluetooth.model import Protocol
protocol = Protocol.UNKNOWN
if isinstance(value, Protocol):
protocol = value
@ -117,11 +116,13 @@ if 'bluetooth_service' not in Base.metadata:
self._protocol = protocol.value
@property
def service_class(self) -> ServiceClass:
def service_class(self):
"""
The :class:`platypush.plugins.bluetooth.model.ServiceClass` enum
value.
"""
from platypush.plugins.bluetooth.model import ServiceClass
try:
return ServiceClass.get(self.uuid)
except (TypeError, ValueError):