From 276aff757bb962b8411d4269588b2a9f87720655 Mon Sep 17 00:00:00 2001 From: Fabio Manganiello Date: Sun, 26 Mar 2023 15:30:57 +0200 Subject: [PATCH] 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. --- platypush/entities/bluetooth/_device.py | 30 +++++++++++++----------- platypush/entities/bluetooth/_service.py | 29 ++++++++++++----------- 2 files changed, 31 insertions(+), 28 deletions(-) diff --git a/platypush/entities/bluetooth/_device.py b/platypush/entities/bluetooth/_device.py index 1407bb7a..25694489 100644 --- a/platypush/entities/bluetooth/_device.py +++ b/platypush/entities/bluetooth/_device.py @@ -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 diff --git a/platypush/entities/bluetooth/_service.py b/platypush/entities/bluetooth/_service.py index d0a17798..65a9b43d 100644 --- a/platypush/entities/bluetooth/_service.py +++ b/platypush/entities/bluetooth/_service.py @@ -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):