Skip to content

Commit

Permalink
0.15.1
Browse files Browse the repository at this point in the history
- Parameters can be used in operations without having to access the value property
- Log info gets printed properly when changing thing parameters
- Changed example and readme (fixes #161)
  • Loading branch information
spacemanspiff2007 authored Aug 30, 2020
1 parent c087ebc commit 020578c
Show file tree
Hide file tree
Showing 10 changed files with 186 additions and 33 deletions.
2 changes: 1 addition & 1 deletion HABApp/__version__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '0.15.0'
__version__ = '0.15.1'
9 changes: 6 additions & 3 deletions HABApp/core/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,12 @@ def add(self, text: str, *args, **kwargs):
self.lines.append(text.format(*args, **kwargs))
return self

def add_exception(self, e: Exception):
for line in str(e).splitlines():
self.lines.append(line)
def add_exception(self, e: Exception, add_traceback: bool = False):
if not add_traceback:
for line in str(e).splitlines():
self.lines.append(line)
else:
self.lines.extend(HABApp.core.wrapper.format_exception(e))
return self

def dump(self) -> bool:
Expand Down
2 changes: 2 additions & 0 deletions HABApp/openhab/connection_handler/func_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,8 @@ async def async_set_thing_cfg(uid: str, cfg: typing.Dict[str, typing.Any]):
elif ret.status >= 300:
raise ValueError('Something went wrong')

return ret.status


# ---------------------------------------------------------------------------------------------------------------------
# Link handling is experimental
Expand Down
138 changes: 124 additions & 14 deletions HABApp/parameters/parameter.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import typing
from math import ceil, floor

from .parameters import add_parameter as _add_parameter
from .parameters import get_value as _get_value
Expand Down Expand Up @@ -29,35 +30,144 @@ def value(self) -> typing.Any:
"""
return _get_value(self.filename, *self.keys)

def __repr__(self):
return f'<Parameter file: {self.filename}, keys: {self.keys}, value: {self.value}'

def __bool__(self):
return bool(self.value)

def __eq__(self, other):
return self.value == other

def __lt__(self, other):
if not isinstance(other, (int, float)):
return NotImplemented

return self.value < other

def __le__(self, other):
if not isinstance(other, (int, float)):
return NotImplemented

return self.value <= other

def __ge__(self, other):
if not isinstance(other, (int, float)):
return NotImplemented

return self.value >= other

def __gt__(self, other):
if not isinstance(other, (int, float)):
return NotImplemented

return self.value > other

def __repr__(self):
return f'<Parameter file: {self.filename}, keys: {self.keys}, value: {self.value}'
# https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types
# These methods are called to implement the binary arithmetic operations
def __add__(self, other):
return self.value.__add__(other)

def __sub__(self, other):
return self.value.__sub__(other)

def __mul__(self, other):
return self.value.__mul__(other)

def __matmul__(self, other):
return self.value.__matmul__(other)

def __truediv__(self, other):
return self.value.__truediv__(other)

def __floordiv__(self, other):
return self.value.__floordiv__(other)

def __mod__(self, other):
return self.value.__mod__(other)

def __divmod__(self, other):
return self.value.__divmod__(other)

def __pow__(self, other):
return self.value.__pow__(other)

def __lshift__(self, other):
return self.value.__lshift__(other)

def __rshift__(self, other):
return self.value.__rshift__(other)

def __and__(self, other):
return self.value.__and__(other)

def __xor__(self, other):
return self.value.__xor__(other)

def __or__(self, other):
return self.value.__or__(other)

# Unary arithmetic operations (-, +, abs() and ~).
def __neg__(self):
return self.value.__neg__()

def __pos__(self):
return self.value.__pos__()

def __abs__(self):
return self.value.__abs__()

def __invert__(self):
return self.value.__invert__()

# built-in functions complex(), int() and float().
def __complex__(self):
return self.value.__complex__()

def __int__(self):
return self.value.__int__()

def __float__(self):
return self.value.__float__()

# built-in function round() and math functions trunc(), floor() and ceil().
def __round__(self, ndigits=None):
return self.value.__round__(ndigits)

def __trunc__(self):
return self.value.__trunc__()

def __floor__(self):
return floor(self.value)

def __ceil__(self):
return ceil(self.value)

# we don't support modification in place! We have to override this because otherwise
# python falls back to the methods above
def __iadd__(self, other):
return PermissionError('Parameter can not be changed!')

def __isub__(self, other):
return PermissionError('Parameter can not be changed!')

def __imul__(self, other):
return PermissionError('Parameter can not be changed!')

def __imatmul__(self, other):
return PermissionError('Parameter can not be changed!')

def __itruediv__(self, other):
return PermissionError('Parameter can not be changed!')

def __ifloordiv__(self, other):
return PermissionError('Parameter can not be changed!')

def __imod__(self, other):
return PermissionError('Parameter can not be changed!')

def __ipow__(self, other):
return PermissionError('Parameter can not be changed!')

def __ilshift__(self, other):
return PermissionError('Parameter can not be changed!')

def __irshift__(self, other):
return PermissionError('Parameter can not be changed!')

def __iand__(self, other):
return PermissionError('Parameter can not be changed!')

def __ixor__(self, other):
return PermissionError('Parameter can not be changed!')

def __ior__(self, other):
return PermissionError('Parameter can not be changed!')
19 changes: 10 additions & 9 deletions HABApp/parameters/parameter_files.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import logging
import threading
import traceback

import ruamel.yaml

Expand Down Expand Up @@ -54,10 +53,11 @@ def load_file(event: HABApp.core.events.habapp_events.RequestFileLoadEvent):
if data is None:
data = {}
set_parameter_file(path.stem, data)
except Exception:
log.error(f"Could not load params from {path.name}!")
for line in traceback.format_exc().splitlines():
log.error(line)
except Exception as exc:
e = HABApp.core.logger.HABAppError(log)
e.add(f"Could not load params from {path.name}!")
e.add_exception(exc, add_traceback=True)
e.dump()
return None

log.debug(f'Loaded params from {path.name}!')
Expand All @@ -69,10 +69,11 @@ def unload_file(event: HABApp.core.events.habapp_events.RequestFileUnloadEvent):
with LOCK: # serialize to get proper error messages
try:
remove_parameter_file(path.stem)
except Exception:
log.error(f"Could not remove parameters from {path.name}!")
for line in traceback.format_exc().splitlines():
log.error(line)
except Exception as exc:
e = HABApp.core.logger.HABAppError(log)
e.add(f"Could not remove parameters from {path.name}!")
e.add_exception(exc, add_traceback=True)
e.dump()
return None

log.debug(f'Removed params from {path.name}!')
Expand Down
12 changes: 8 additions & 4 deletions _doc/getting_started.rst
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,10 @@ This often comes in handy if there is some logic that shall be applied to differ

Interacting with items
------------------------------
Iterating with items is done through the Item factory methods.
Posting values will automatically create the corresponding events on the event bus.
Iterating with items is done through the corresponding Item factory methods.
Posting values will automatically create the events on the event bus.
This example will create an item in HABApp (locally) and post some updates to it.
To access items from openhab use the correct openhab item type (see :ref:`the openhab item description <OPENHAB_ITEM_TYPES>`).

.. execute_code::
:header_output: Output
Expand Down Expand Up @@ -166,10 +168,12 @@ It is possible to watch items for changes or updates.

# the function has 1 argument which is the event
def item_changed(self, event: ValueChangeEvent):
print(f'{event.name} changed from {event.old_value} to {event.value}')
print(f'{event.name} changed from "{event.old_value}" to "{event.value}"')
print(f'Last change of {self.my_item.name}: {self.my_item.last_change}')

def item_updated(self, event: ValueUpdateEvent):
print(f'{event.name} updated value: {event.value}')
print(f'{event.name} updated value: "{event.value}"')
print(f'Last update of {self.my_item.name}: {self.my_item.last_update}')

MyFirstRule()
# hide
Expand Down
7 changes: 6 additions & 1 deletion _doc/interface_openhab.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Function parameters
:imported-members:


.. _OPENHAB_ITEM_TYPES:

Openhab item types
------------------------------
Expand All @@ -37,6 +38,7 @@ Example:
HABApp.core.Items.set_item(ContactItem('MyContact', initial_value='OPEN'))
HABApp.core.Items.set_item(SwitchItem('MySwitch', initial_value='OFF'))
# hide
from HABApp.openhab.items import ContactItem, SwitchItem

my_contact = ContactItem.get_item('MyContact')
if my_contact.is_open():
Expand Down Expand Up @@ -225,6 +227,8 @@ and how to automatically link items to it.
.. tip::
Integer values can be specified either as integer (``20``) or hex (``0x14``)

The entries ``thing config``, ``create items`` and ``channels`` are optional and can be combined as desired.


.. code-block:: yaml
Expand All @@ -236,7 +240,8 @@ and how to automatically link items to it.
filter:
thing_type: zwave:philio_pst02a_00_000
# Set this configuration for all things.
# Set this configuration every matching thing. HABApp will automatically only
# change the values which are not already correct.
# Here it is the z-wave parameters which are responsible for the device behaviour
thing config:
4: 99 # Light Threshold
Expand Down
9 changes: 8 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@
[![Build Status](https://travis-ci.org/spacemanspiff2007/HABApp.svg?branch=master)](https://travis-ci.org/spacemanspiff2007/HABApp)
[![Documentation Status](https://readthedocs.org/projects/habapp/badge/?version=latest)](https://habapp.readthedocs.io/en/latest/?badge=latest)
[![Updates](https://pyup.io/repos/github/spacemanspiff2007/HABApp/shield.svg)](https://pyup.io/repos/github/spacemanspiff2007/HABApp/)
![PyPI - Python Version](https://img.shields.io/pypi/pyversions/habapp)

![PyPI](https://img.shields.io/pypi/v/HABapp)
[![Downloads](https://pepy.tech/badge/habapp/month)](https://pepy.tech/project/habapp/month)
![Docker Image Version (latest by date)](https://img.shields.io/docker/v/spacemanspiff2007/habapp?label=docker)
![Docker Pulls](https://img.shields.io/docker/pulls/spacemanspiff2007/habapp)


_Easy automation with MQTT and/or openHAB_

Expand Down Expand Up @@ -92,4 +99,4 @@ class MyOpenhabRule(HABApp.Rule):
self.oh.post_update('TestItemUpdate', 123)

MyOpenhabRule()
```
```
5 changes: 5 additions & 0 deletions tests/test_core/test_logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ def test_exception_multiline():
assert HABAppLogger(None).add_exception(e).lines == ['Line1', 'Line2', 'Line3']


def test_exception_traceback():
e = Exception('Line1\nLine2\nLine3')
assert HABAppLogger(None).add_exception(e, add_traceback=True).lines == ['Exception: Line1', 'Line2', 'Line3']


def test_bool():
for cls in (HABAppError, HABAppInfo, HABAppWarning):
i = cls(getLogger('test')).add('')
Expand Down
16 changes: 16 additions & 0 deletions tests/test_rule/test_rule_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,22 @@ def test_float_operators(params):
assert p > 4


def test_arithmetic(params):
Parameters.set_parameter_file('file', {'key': 1})
p = Parameter('file', 'key')

assert int(p) == 1
assert p + 1 == 2
assert p - 1 == 0
assert p * 3 == 3
assert p / 2 == 0.5
assert p // 2 == 0
assert p << 1 == 2
assert p >> 1 == 0
assert p | 2 == 3
assert p & 2 == 0


def test_simple_key_creation(params):

Parameter('file', 'key')
Expand Down

0 comments on commit 020578c

Please sign in to comment.