<filename>wotpy/wot/consumed/interaction_map.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Classes that represent Interaction instances accessed on a ConsumedThing.
"""

import six
import tornado.gen
from rx.concurrency import IOLoopScheduler
from six.moves import UserDict
from slugify import slugify


class ConsumedThingInteractionDict(UserDict):
    """A dictionary that provides lazy access to the objects that implement
    the Interaction interface for each interaction in a given ConsumedThing."""

    def __init__(self, *args, **kwargs):
        self._consumed_thing = kwargs.pop("consumed_thing")
        UserDict.__init__(self, *args, **kwargs)

    def _find_normalized_name(self, name):
        """Takes a case-insensitive URL-safe interaction name and returns
        the actual name in the interaction dict."""

        return next((key for key in six.iterkeys(self.interaction_dict) if slugify(key) == slugify(name)), None)

    def __getitem__(self, name):
        """Lazily build and return an object that implements the Interaction interface."""

        name_normalized = self._find_normalized_name(name)

        if name_normalized is None:
            raise KeyError("Unknown interaction: {}".format(name))

        return self.thing_interaction_class(self._consumed_thing, name_normalized)

    def __len__(self):
        return len(self.interaction_dict)

    def __contains__(self, item):
        return self._find_normalized_name(item) is not None

    def __iter__(self):
        return six.iterkeys(self.interaction_dict)

    @property
    def interaction_dict(self):
        """Returns an interactions dict by name.
        The dict values are the raw dict interactions as contained in a TD document."""

        raise NotImplementedError()

    @property
    def thing_interaction_class(self):
        """Returns the class that implements the
        Interaction interface for this type of interaction."""

        raise NotImplementedError()


class ConsumedThingPropertyDict(ConsumedThingInteractionDict):
    """A dictionary that provides lazy access to the objects that implement
    the ThingProperty interface for each property in a given ConsumedThing."""

    @property
    def interaction_dict(self):
        return self._consumed_thing.td.properties

    @property
    def thing_interaction_class(self):
        return ConsumedThingProperty


class ConsumedThingActionDict(ConsumedThingInteractionDict):
    """A dictionary that provides lazy access to the objects that implement
    the ThingAction interface for each action in a given ConsumedThing."""

    @property
    def interaction_dict(self):
        return self._consumed_thing.td.actions

    @property
    def thing_interaction_class(self):
        return ConsumedThingAction


class ConsumedThingEventDict(ConsumedThingInteractionDict):
    """A dictionary that provides lazy access to the objects that implement
    the ThingEvent interface for each event in a given ConsumedThing."""

    @property
    def interaction_dict(self):
        return self._consumed_thing.td.events

    @property
    def thing_interaction_class(self):
        return ConsumedThingEvent


class ConsumedThingProperty(object):
    """The ThingProperty interface implementation for ConsumedThing objects."""

    def __init__(self, consumed_thing, name):
        self._consumed_thing = consumed_thing
        self._name = name

    def __str__(self):
        return "<{}> ({}::{})".format(self.__class__.__name__, self._consumed_thing.id, self._name)

    def __getattr__(self, name):
        """Search for members that raised an AttributeError in
        the private init dict before propagating the exception."""

        return getattr(self._consumed_thing.td.properties[self._name], name)

    @tornado.gen.coroutine
    def read(self, timeout=None, client_kwargs=None):
        """The read() method will fetch the value of the Property.
        A coroutine that yields the value or raises an error."""

        value = yield self._consumed_thing.read_property(
            self._name,
            timeout=timeout,
            client_kwargs=client_kwargs)

        raise tornado.gen.Return(value)

    @tornado.gen.coroutine
    def write(self, value, timeout=None, client_kwargs=None):
        """The write() method will attempt to set the value of the
        Property specified in the value argument whose type SHOULD
        match the one specified by the type property.
        A coroutine that yields on success or raises an error."""

        yield self._consumed_thing.write_property(
            self._name, value,
            timeout=timeout,
            client_kwargs=client_kwargs)

    def subscribe(self, *args, **kwargs):
        """Subscribe to an stream of events emitted when the property value changes."""

        client_kwargs = kwargs.pop("client_kwargs", None)

        observable = self._consumed_thing.on_property_change(
            self._name,
            client_kwargs=client_kwargs)

        return observable.subscribe_on(IOLoopScheduler()).subscribe(*args, **kwargs)


class ConsumedThingAction(object):
    """The ThingAction interface implementation for ConsumedThing objects."""

    def __init__(self, consumed_thing, name):
        self._consumed_thing = consumed_thing
        self._name = name

    def __str__(self):
        return "<{}> ({}::{})".format(self.__class__.__name__, self._consumed_thing.id, self._name)

    def __getattr__(self, name):
        """Search for members that raised an AttributeError in
        the private init dict before propagating the exception."""

        return getattr(self._consumed_thing.td.actions[self._name], name)

    @tornado.gen.coroutine
    def invoke(self, *args, **kwargs):
        """The invoke() method when invoked, starts the Action interaction
        with the input value provided by the inputValue argument."""

        input_value = args[0] if len(args) else None
        client_kwargs = kwargs.pop("client_kwargs", None)
        timeout = kwargs.pop("timeout", None)

        result = yield self._consumed_thing.invoke_action(
            self._name, input_value,
            timeout=timeout,
            client_kwargs=client_kwargs)

        raise tornado.gen.Return(result)


class ConsumedThingEvent(object):
    """The ThingEvent interface implementation for ConsumedThing objects."""

    def __init__(self, consumed_thing, name):
        self._consumed_thing = consumed_thing
        self._name = name

    def __str__(self):
        return "<{}> ({}::{})".format(self.__class__.__name__, self._consumed_thing.id, self._name)

    def __getattr__(self, name):
        """Search for members that raised an AttributeError in
        the private init dict before propagating the exception."""

        return getattr(self._consumed_thing.td.events[self._name], name)

    def subscribe(self, *args, **kwargs):
        """Subscribe to an stream of emissions of this event."""

        client_kwargs = kwargs.pop("client_kwargs", None)

        observable = self._consumed_thing.on_event(
            self._name,
            client_kwargs=client_kwargs)

        return observable.subscribe_on(IOLoopScheduler()).subscribe(*args, **kwargs)

<filename>wotpy/wot/consumed/interaction_map.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Classes that represent Interaction instances accessed on a ConsumedThing.
"""

import six
import tornado.gen
from rx.concurrency import IOLoopScheduler
from six.moves import UserDict
from slugify import slugify


class ConsumedThingInteractionDict(UserDict):
    """A dictionary that provides lazy access to the objects that implement
    the Interaction interface for each interaction in a given ConsumedThing."""

    def __init__(self, *args, **kwargs):
        self._consumed_thing = kwargs.pop("consumed_thing")
        UserDict.__init__(self, *args, **kwargs)

    def _find_normalized_name(self, name):
        """Takes a case-insensitive URL-safe interaction name and returns
        the actual name in the interaction dict."""

        return next((key for key in six.iterkeys(self.interaction_dict) if slugify(key) == slugify(name)), None)

    def __getitem__(self, name):
        """Lazily build and return an object that implements the Interaction interface."""

        name_normalized = self._find_normalized_name(name)

        if name_normalized is None:
            raise KeyError("Unknown interaction: {}".format(name))

        return self.thing_interaction_class(self._consumed_thing, name_normalized)

    def __len__(self):
        return len(self.interaction_dict)

    def __contains__(self, item):
        return self._find_normalized_name(item) is not None

    def __iter__(self):
        return six.iterkeys(self.interaction_dict)

    @property
    def interaction_dict(self):
        """Returns an interactions dict by name.
        The dict values are the raw dict interactions as contained in a TD document."""

        raise NotImplementedError()

    @property
    def thing_interaction_class(self):
        """Returns the class that implements the
        Interaction interface for this type of interaction."""

        raise NotImplementedError()


class ConsumedThingPropertyDict(ConsumedThingInteractionDict):
    """A dictionary that provides lazy access to the objects that implement
    the ThingProperty interface for each property in a given ConsumedThing."""

    @property
    def interaction_dict(self):
        return self._consumed_thing.td.properties

    @property
    def thing_interaction_class(self):
        return ConsumedThingProperty


class ConsumedThingActionDict(ConsumedThingInteractionDict):
    """A dictionary that provides lazy access to the objects that implement
    the ThingAction interface for each action in a given ConsumedThing."""

    @property
    def interaction_dict(self):
        return self._consumed_thing.td.actions

    @property
    def thing_interaction_class(self):
        return ConsumedThingAction


class ConsumedThingEventDict(ConsumedThingInteractionDict):
    """A dictionary that provides lazy access to the objects that implement
    the ThingEvent interface for each event in a given ConsumedThing."""

    @property
    def interaction_dict(self):
        return self._consumed_thing.td.events

    @property
    def thing_interaction_class(self):
        return ConsumedThingEvent


class ConsumedThingProperty(object):
    """The ThingProperty interface implementation for ConsumedThing objects."""

    def __init__(self, consumed_thing, name):
        self._consumed_thing = consumed_thing
        self._name = name

    def __str__(self):
        return "<{}> ({}::{})".format(self.__class__.__name__, self._consumed_thing.id, self._name)

    def __getattr__(self, name):
        """Search for members that raised an AttributeError in
        the private init dict before propagating the exception."""

        return getattr(self._consumed_thing.td.properties[self._name], name)

    @tornado.gen.coroutine
    def read(self, timeout=None, client_kwargs=None):
        """The read() method will fetch the value of the Property.
        A coroutine that yields the value or raises an error."""

        value = yield self._consumed_thing.read_property(
            self._name,
            timeout=timeout,
            client_kwargs=client_kwargs)

        raise tornado.gen.Return(value)

    @tornado.gen.coroutine
    def write(self, value, timeout=None, client_kwargs=None):
        """The write() method will attempt to set the value of the
        Property specified in the value argument whose type SHOULD
        match the one specified by the type property.
        A coroutine that yields on success or raises an error."""

        yield self._consumed_thing.write_property(
            self._name, value,
            timeout=timeout,
            client_kwargs=client_kwargs)

    def subscribe(self, *args, **kwargs):
        """Subscribe to an stream of events emitted when the property value changes."""

        client_kwargs = kwargs.pop("client_kwargs", None)

        observable = self._consumed_thing.on_property_change(
            self._name,
            client_kwargs=client_kwargs)

        return observable.subscribe_on(IOLoopScheduler()).subscribe(*args, **kwargs)


class ConsumedThingAction(object):
    """The ThingAction interface implementation for ConsumedThing objects."""

    def __init__(self, consumed_thing, name):
        self._consumed_thing = consumed_thing
        self._name = name

    def __str__(self):
        return "<{}> ({}::{})".format(self.__class__.__name__, self._consumed_thing.id, self._name)

    def __getattr__(self, name):
        """Search for members that raised an AttributeError in
        the private init dict before propagating the exception."""

        return getattr(self._consumed_thing.td.actions[self._name], name)

    @tornado.gen.coroutine
    def invoke(self, *args, **kwargs):
        """The invoke() method when invoked, starts the Action interaction
        with the input value provided by the inputValue argument."""

        input_value = args[0] if len(args) else None
        client_kwargs = kwargs.pop("client_kwargs", None)
        timeout = kwargs.pop("timeout", None)

        result = yield self._consumed_thing.invoke_action(
            self._name, input_value,
            timeout=timeout,
            client_kwargs=client_kwargs)

        raise tornado.gen.Return(result)


class ConsumedThingEvent(object):
    """The ThingEvent interface implementation for ConsumedThing objects."""

    def __init__(self, consumed_thing, name):
        self._consumed_thing = consumed_thing
        self._name = name

    def __str__(self):
        return "<{}> ({}::{})".format(self.__class__.__name__, self._consumed_thing.id, self._name)

    def __getattr__(self, name):
        """Search for members that raised an AttributeError in
        the private init dict before propagating the exception."""

        return getattr(self._consumed_thing.td.events[self._name], name)

    def subscribe(self, *args, **kwargs):
        """Subscribe to an stream of emissions of this event."""

        client_kwargs = kwargs.pop("client_kwargs", None)

        observable = self._consumed_thing.on_event(
            self._name,
            client_kwargs=client_kwargs)

        return observable.subscribe_on(IOLoopScheduler()).subscribe(*args, **kwargs)

#!/usr/bin/env python # -*- coding: utf-8 -*- Classes that represent Interaction instances accessed on a ConsumedThing. A dictionary that provides lazy access to the objects that implement     the Interaction interface for each interaction in a given ConsumedThing. Takes a case-insensitive URL-safe interaction name and returns         the actual name in the interaction dict. Lazily build and return an object that implements the Interaction interface. Returns an interactions dict by name.         The dict values are the raw dict interactions as contained in a TD document. Returns the class that implements the         Interaction interface for this type of interaction. A dictionary that provides lazy access to the objects that implement     the ThingProperty interface for each property in a given ConsumedThing. A dictionary that provides lazy access to the objects that implement     the ThingAction interface for each action in a given ConsumedThing. A dictionary that provides lazy access to the objects that implement     the ThingEvent interface for each event in a given ConsumedThing. The ThingProperty interface implementation for ConsumedThing objects. Search for members that raised an AttributeError in         the private init dict before propagating the exception. The read() method will fetch the value of the Property.         A coroutine that yields the value or raises an error. The write() method will attempt to set the value of the         Property specified in the value argument whose type SHOULD         match the one specified by the type property.         A coroutine that yields on success or raises an error. Subscribe to an stream of events emitted when the property value changes. The ThingAction interface implementation for ConsumedThing objects. Search for members that raised an AttributeError in         the private init dict before propagating the exception. The invoke() method when invoked, starts the Action interaction         with the input value provided by the inputValue argument. The ThingEvent interface implementation for ConsumedThing objects. Search for members that raised an AttributeError in         the private init dict before propagating the exception. Subscribe to an stream of emissions of this event.