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: 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 typing_extensions import override
from sqlalchemy import ( from sqlalchemy import (
@ -11,12 +11,6 @@ from sqlalchemy import (
) )
from platypush.common.db import Base from platypush.common.db import Base
from platypush.plugins.bluetooth.model import (
MajorDeviceClass,
MajorServiceClass,
MinorDeviceClass,
ServiceClass,
)
from ..devices import Device from ..devices import Device
from ._service import BluetoothService from ._service import BluetoothService
@ -80,7 +74,9 @@ if 'bluetooth_device' not in Base.metadata:
} }
@property @property
def major_device_class(self) -> MajorDeviceClass: def major_device_class(self):
from platypush.plugins.bluetooth.model import MajorDeviceClass
ret = MajorDeviceClass.UNKNOWN ret = MajorDeviceClass.UNKNOWN
if self._major_device_class: if self._major_device_class:
matches = [ matches = [
@ -95,11 +91,13 @@ if 'bluetooth_device' not in Base.metadata:
return ret return ret
@major_device_class.setter @major_device_class.setter
def major_device_class(self, value: MajorDeviceClass): def major_device_class(self, value):
self._major_device_class = value.value.name self._major_device_class = value.value.name
@property @property
def minor_device_classes(self) -> List[MinorDeviceClass]: def minor_device_classes(self) -> list:
from platypush.plugins.bluetooth.model import MinorDeviceClass
ret = [] ret = []
for dev_cls in self._minor_device_classes or []: for dev_cls in self._minor_device_classes or []:
matches = [cls for cls in MinorDeviceClass if cls.value.name == dev_cls] 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 return ret
@minor_device_classes.setter @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 [])] self._minor_device_classes = [cls.value.name for cls in (value or [])]
@property @property
def major_service_classes(self) -> List[MajorServiceClass]: def major_service_classes(self) -> list:
from platypush.plugins.bluetooth.model import MajorServiceClass
ret = [] ret = []
for dev_cls in self._major_service_classes or []: for dev_cls in self._major_service_classes or []:
matches = [ matches = [
@ -127,7 +127,7 @@ if 'bluetooth_device' not in Base.metadata:
return ret return ret
@major_service_classes.setter @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 [])] self._major_service_classes = [cls.value.name for cls in (value or [])]
@property @property
@ -142,11 +142,13 @@ if 'bluetooth_device' not in Base.metadata:
] ]
@property @property
def known_services(self) -> Dict[ServiceClass, "BluetoothService"]: def known_services(self) -> dict:
""" """
Known services exposed by the device, indexed by Known services exposed by the device, indexed by
:class:`platypush.plugins.bluetooth.model.ServiceClass` enum value. :class:`platypush.plugins.bluetooth.model.ServiceClass` enum value.
""" """
from platypush.plugins.bluetooth.model import ServiceClass
return { return {
child.service_class: child child.service_class: child
for child in self.children 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 uuid import UUID
from typing_extensions import override
from sqlalchemy import ( from sqlalchemy import (
Boolean, Boolean,
Column, Column,
@ -12,11 +12,6 @@ from sqlalchemy import (
from platypush.common.db import Base from platypush.common.db import Base
from platypush.entities import Entity from platypush.entities import Entity
from platypush.plugins.bluetooth.model import (
Protocol,
RawServiceClass,
ServiceClass,
)
if 'bluetooth_service' not in Base.metadata: if 'bluetooth_service' not in Base.metadata:
@ -56,7 +51,7 @@ if 'bluetooth_service' not in Base.metadata:
} }
@staticmethod @staticmethod
def to_uuid(value: Union[str, RawServiceClass]) -> RawServiceClass: def to_uuid(value):
""" """
Convert a raw UUID string to a service class UUID. 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) return int(value, 16)
@property @property
def uuid(self) -> RawServiceClass: def uuid(self):
""" """
Getter for the service class UUID. Getter for the service class UUID.
""" """
return self.to_uuid(self._uuid) return self.to_uuid(self._uuid)
@uuid.setter @uuid.setter
def uuid(self, value: Union[RawServiceClass, str]): def uuid(self, value):
""" """
Setter for the service class UUID. Setter for the service class UUID.
""" """
uuid: Union[RawServiceClass, str] = self.to_uuid(value) uuid = self.to_uuid(value)
if isinstance(uuid, int): if isinstance(uuid, int):
# Hex-encoded 16-bit UUID case # Hex-encoded 16-bit UUID case
uuid = f'{uuid:04X}' uuid = f'{uuid:04X}'
@ -91,20 +86,24 @@ if 'bluetooth_service' not in Base.metadata:
self._uuid = str(uuid) self._uuid = str(uuid)
@property @property
def protocol(self) -> Protocol: def protocol(self):
""" """
Getter for the protocol used by the service. Getter for the protocol used by the service.
""" """
from platypush.plugins.bluetooth.model import Protocol
try: try:
return Protocol(self._protocol) return Protocol(self._protocol)
except ValueError: except ValueError:
return Protocol.UNKNOWN return Protocol.UNKNOWN
@protocol.setter @protocol.setter
def protocol(self, value: Union[str, Protocol]): def protocol(self, value):
""" """
Setter for the protocol used by the service. Setter for the protocol used by the service.
""" """
from platypush.plugins.bluetooth.model import Protocol
protocol = Protocol.UNKNOWN protocol = Protocol.UNKNOWN
if isinstance(value, Protocol): if isinstance(value, Protocol):
protocol = value protocol = value
@ -117,11 +116,13 @@ if 'bluetooth_service' not in Base.metadata:
self._protocol = protocol.value self._protocol = protocol.value
@property @property
def service_class(self) -> ServiceClass: def service_class(self):
""" """
The :class:`platypush.plugins.bluetooth.model.ServiceClass` enum The :class:`platypush.plugins.bluetooth.model.ServiceClass` enum
value. value.
""" """
from platypush.plugins.bluetooth.model import ServiceClass
try: try:
return ServiceClass.get(self.uuid) return ServiceClass.get(self.uuid)
except (TypeError, ValueError): except (TypeError, ValueError):