Skip to content

Commit

Permalink
Merge pull request #87 from s-kostyuk/finalized_capabilities
Browse files Browse the repository at this point in the history
Finalized capabilities (2/n)

This pull request added `_capability_name` field for public Capabilities and adds a `capabilities` property for all Things
  • Loading branch information
s-kostyuk committed Mar 20, 2018
2 parents a20aeee + f0fe6f8 commit e39bd19
Show file tree
Hide file tree
Showing 9 changed files with 79 additions and 4 deletions.
7 changes: 5 additions & 2 deletions dpl/dtos/thing_dto.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ class and a corresponding builder to be used to
"is_available": True,
# UNIX timestamp in float in UTC timezone, the time when
# the Thing properties was last updated (changed)
"last_updated": 1517232368.30256
"last_updated": 1517232368.30256,
# indicates a list of supported Capabilities
"capabilities": ["actuator", "has_state", "is_active"]
}
```
Expand All @@ -43,7 +45,8 @@ def build_thing_dto(thing: Thing) -> ThingDto:
'id': thing.domain_id,
'is_enabled': thing.is_enabled,
'is_available': thing.is_available,
'last_updated': thing.last_updated
'last_updated': thing.last_updated,
'capabilities': thing.capabilities
}

result.update(thing.metadata)
Expand Down
2 changes: 2 additions & 0 deletions dpl/things/capabilities/actuator.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ class Actuator(HasState):
music and changing tracks, turning power on and off,
turning light on and off and so on.
"""
_capability_name = 'actuator'

@property
def commands(self) -> Iterable[str]:
"""
Expand Down
2 changes: 2 additions & 0 deletions dpl/things/capabilities/has_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ class HasState(IsActive):
property, analyze an availability status in is_available property
and so on).
"""
_capability_name = 'has_state'

class States(Enum):
"""
Possible states of the thing. Must be overridden in derived
Expand Down
2 changes: 2 additions & 0 deletions dpl/things/capabilities/has_value.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ class HasValue(Generic[TValueType]):
like the current temperature, humidity or brightness
levels.
"""
_capability_name = 'has_value'

@property
def value(self) -> Optional[TValueType]:
"""
Expand Down
1 change: 1 addition & 0 deletions dpl/things/capabilities/is_active.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class IsActive(object):
property, analyze an availability status in is_available property
and so on).
"""
_capability_name = 'is_active'

@property
def is_active(self) -> bool:
Expand Down
2 changes: 2 additions & 0 deletions dpl/things/capabilities/on_off.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ class OnOff(object):
is mapped to false. on command is also mapped to the activate and off
command is mapped to the deactivate command.
"""
_capability_name = 'on_off'

@property
def is_powered_on(self) -> bool:
"""
Expand Down
2 changes: 2 additions & 0 deletions dpl/things/capabilities/open_closed.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ class OpenClosed(HasState):
opposite states (from ``open`` to ``closed``, from ``closed`` to ``open``,
from ``opening`` to ``closed``, from ``closing`` to ``opened``).
"""
_capability_name = 'open_closed'

class States(Enum):
"""
Possible states of the thing: 'open', 'closed' and 'unknown'.
Expand Down
47 changes: 47 additions & 0 deletions dpl/things/capability_filler_meta.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"""
This class contains a definition of the CapabilityFiller metaclass.
"""
import inspect
from typing import Iterable, Generator


class CapabilityFiller(type):
"""
CapabilityFiller is a metaclass which intercepts the class
creation process, discovers all Capabilities (parent classes)
of the class and fills the corresponding ``_capabilities``
private property of the class with the names of all Capabilities
which was implemented by the class
"""

def __new__(mcs, name, bases, class_dict):
cls = type.__new__(mcs, name, bases, class_dict)

mros = inspect.getmro(cls)

cls._capabilities = tuple(
mcs._capability_list_generator(source=mros)
)

return cls

@staticmethod
def _capability_list_generator(source: Iterable) -> Generator[str, None, None]:
"""
A generator which extracts capability names from the
specified list of Capabilities
:param source: a list of parent classes to be parsed
:return: a generator of Capability names
"""
attr = '_capability_name'

for i in source:
if attr not in i.__dict__:
continue

name = getattr(i, attr, None)

assert name is not None

yield name
18 changes: 16 additions & 2 deletions dpl/things/thing.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import time
from copy import deepcopy
from types import MappingProxyType
from collections import Mapping
from typing import Mapping, Sequence

# Include 3rd-party modules
# Include DPL modules
Expand All @@ -12,9 +12,11 @@
from dpl.things.capabilities.is_enabled import IsEnabled
from dpl.things.capabilities.is_available import Available
from dpl.things.capabilities.last_updated import LastUpdated
from .capability_filler_meta import CapabilityFiller


class Thing(BaseEntity, IsEnabled, Available, LastUpdated):
class Thing(BaseEntity, IsEnabled, Available, LastUpdated,
metaclass=CapabilityFiller):
"""
Thing is a base class for all connected devices in the system.
Expand Down Expand Up @@ -52,6 +54,8 @@ class Thing(BaseEntity, IsEnabled, Available, LastUpdated):
like 'current_track', 'play' and 'stop' for player. Or 'on'/'off' for
lighting, etc.
"""
# _capabilities field will be filled by the CapabilityFiller metaclass
_capabilities = None # type: Sequence[str]

def __init__(
self, domain_id: TDomainId,
Expand All @@ -76,6 +80,16 @@ def __init__(
self._last_updated = time.time()
self._is_enabled = False

@property
def capabilities(self) -> Sequence[str]: # -> Collection[str]:
"""
Returns a list of Capabilities supported by this Thing
:return: a collection of Capability names supported by
(implemented by) this Thing
"""
return self._capabilities

@property
def metadata(self) -> Mapping:
"""
Expand Down

0 comments on commit e39bd19

Please sign in to comment.