Merge pull request #154 from fronzbot/dev

0.12.1
This commit is contained in:
Kevin Fronczak
2019-01-31 18:22:09 -08:00
committed by GitHub
6 changed files with 37 additions and 93 deletions
+12
View File
@@ -3,6 +3,18 @@ Changelog
A list of changes between each release
0.12.1 (2019-01-31)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Remove logging improvements since they were incompatible with home-assistant logging
0.12.0 (2019-01-31)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fix video api endpoint, re-enables motion detection
- Add improved logging capability
- Add download video method
- Prevent blinkpy from failing at setup due to api error
0.11.2 (2019-01-23)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Hotfix to prevent platform from stalling due to API change
-17
View File
@@ -51,23 +51,6 @@ The simplest way to use this package from a terminal is to call ``Blink.start()`
If you would like to log in without setting up the cameras or system, you can simply call the ``Blink.login()`` function which will prompt for a username and password and then authenticate with the server. This is useful if you want to avoid use of the ``start()`` function which simply acts as a wrapper for more targeted API methods.
At initialization, you may also set the logging level of the ``blinkpy`` library like so (default is ``INFO``:
.. code:: python
import logging
from blinkpy import blinkpy
blink = blinkpy.Blink(..., loglevel=logging.<LEVEL>)
blink.start()
You can also disable logging of duplicate entries via the ``allow_duplicate_logs`` flag (default is ``True``):
.. code:: python
from blinkpy import blinkpy
blink = blinkpy.Blink(..., allow_duplicate_logs=False)
blink.start()
Cameras are instantiated as individual ``BlinkCamera`` classes within a ``BlinkSyncModule`` instance. All of your sync modules are stored within the ``Blink.sync`` dictionary and can be accessed using the name of the sync module as the key (this is the name of your sync module in the Blink App).
The below code will display cameras and their available attributes:
+3 -30
View File
@@ -25,7 +25,6 @@ from dateutil.parser import parse
from blinkpy import api
from blinkpy.sync_module import BlinkSyncModule
from blinkpy.helpers import errors as ERROR
from blinkpy.helpers import log
from blinkpy.helpers.util import (
create_session, merge_dicts, get_time, BlinkURLHandler,
BlinkAuthenticationException)
@@ -35,15 +34,14 @@ from blinkpy.helpers.constants import __version__
REFRESH_RATE = 30
_LOGGER = log.create_logger('blinkpy')
_LOGGER = logging.getLogger(__name__)
class Blink():
"""Class to initialize communication."""
def __init__(self, username=None, password=None,
refresh_rate=REFRESH_RATE, loglevel=logging.INFO,
allow_duplicate_logs=True):
refresh_rate=REFRESH_RATE):
"""
Initialize Blink system.
@@ -51,9 +49,6 @@ class Blink():
:param password: Blink password
:param refresh_rate: Refresh rate of blink information.
Defaults to 15 (seconds)
:param loglevel: Sets the log level for the logger.
:param allow_duplicate_logs: Set to 'False' to only allow a log
message to be logged once.
"""
self._username = username
self._password = password
@@ -74,10 +69,6 @@ class Blink():
self.video_list = CaseInsensitiveDict({})
self._login_url = LOGIN_URL
self.version = __version__
self.allow_duplicate_logs = allow_duplicate_logs
self.loglevel = loglevel
self._reset_logger()
@property
def auth_header(self):
@@ -91,8 +82,6 @@ class Blink():
Method logs in and sets auth token, urls, and ids for future requests.
Essentially this is just a wrapper function for ease of use.
"""
self._reset_logger()
if self._username is None or self._password is None:
if not self.login():
return
@@ -111,7 +100,7 @@ class Blink():
self._username = input("Username:")
self._password = getpass.getpass("Password:")
if self.get_auth_token():
_LOGGER.info("Login successful!")
_LOGGER.debug("Login successful!")
return True
_LOGGER.warning("Unable to login with %s.", self._username)
return False
@@ -285,19 +274,3 @@ class Blink():
copyfileobj(response.raw, vidfile)
_LOGGER.info("Downloaded video to %s", filename)
# pylint: disable=no-self-use
def _reset_logger(self):
"""Reset the log handler."""
for handler in _LOGGER.handlers:
_LOGGER.removeHandler(handler)
handler.close()
_LOGGER.setLevel(self.loglevel)
if self.allow_duplicate_logs:
handler = logging.StreamHandler()
handler.setFormatter(log.log_formatter())
else:
handler = log.RepeatLogHandler()
handler.setFormatter(log.log_formatter())
_LOGGER.addHandler(handler)
+1 -1
View File
@@ -4,7 +4,7 @@ import os
MAJOR_VERSION = 0
MINOR_VERSION = 12
PATCH_VERSION = 0
PATCH_VERSION = 1
__version__ = '{}.{}.{}'.format(MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION)
-33
View File
@@ -1,33 +0,0 @@
"""Module for blinkpy logging."""
import logging
def create_logger(name):
"""Create a logger instance."""
handler = RepeatLogHandler()
handler.setFormatter(log_formatter())
logger = logging.getLogger(name)
logger.setLevel(logging.DEBUG)
logger.addHandler(handler)
return logger
def log_formatter():
"""Create log formatter."""
fmt = "%(asctime)s %(levelname)s [%(name)s] %(message)s"
return logging.Formatter(fmt)
class RepeatLogHandler(logging.StreamHandler):
"""Log handler for repeat entries."""
def __init__(self):
"""Initialize repeat log handler."""
super().__init__()
self.log_record = set()
def emit(self, record):
"""Ensure we only log a message once."""
if record.msg not in self.log_record:
self.log_record.add(record.msg)
super().emit(record)
+21 -12
View File
@@ -90,14 +90,17 @@ class TestBlinkFunctions(unittest.TestCase):
@mock.patch('blinkpy.blinkpy.api.request_videos')
def test_download_video_exit(self, mock_req, mock_sess):
"""Test we exit method when provided bad response."""
blink = blinkpy.Blink(loglevel=logging.DEBUG)
blink = blinkpy.Blink()
# pylint: disable=protected-access
blinkpy._LOGGER.setLevel(logging.DEBUG)
blink.last_refresh = 0
mock_req.return_value = {}
formatted_date = get_time(blink.last_refresh)
expected_log = [
"INFO:blinkpy:Retrieving videos since {}".format(formatted_date),
"DEBUG:blinkpy:Processing page 1",
"INFO:blinkpy:No videos found on page 1. Exiting."
"INFO:blinkpy.blinkpy:Retrieving videos since {}".format(
formatted_date),
"DEBUG:blinkpy.blinkpy:Processing page 1",
"INFO:blinkpy.blinkpy:No videos found on page 1. Exiting."
]
with self.assertLogs() as dl_log:
blink.download_videos('/tmp')
@@ -106,7 +109,9 @@ class TestBlinkFunctions(unittest.TestCase):
@mock.patch('blinkpy.blinkpy.api.request_videos')
def test_parse_downloaded_items(self, mock_req, mock_sess):
"""Test ability to parse downloaded items list."""
blink = blinkpy.Blink(loglevel=logging.DEBUG)
blink = blinkpy.Blink()
# pylint: disable=protected-access
blinkpy._LOGGER.setLevel(logging.DEBUG)
generic_entry = {
'created_at': '1970',
'camera_name': 'foo',
@@ -118,9 +123,10 @@ class TestBlinkFunctions(unittest.TestCase):
blink.last_refresh = 0
formatted_date = get_time(blink.last_refresh)
expected_log = [
"INFO:blinkpy:Retrieving videos since {}".format(formatted_date),
"DEBUG:blinkpy:Processing page 1",
"DEBUG:blinkpy:foo: /bar.mp4 is marked as deleted."
"INFO:blinkpy.blinkpy:Retrieving videos since {}".format(
formatted_date),
"DEBUG:blinkpy.blinkpy:Processing page 1",
"DEBUG:blinkpy.blinkpy:foo: /bar.mp4 is marked as deleted."
]
with self.assertLogs() as dl_log:
blink.download_videos('/tmp', stop=2)
@@ -129,7 +135,9 @@ class TestBlinkFunctions(unittest.TestCase):
@mock.patch('blinkpy.blinkpy.api.request_videos')
def test_parse_camera_not_in_list(self, mock_req, mock_sess):
"""Test ability to parse downloaded items list."""
blink = blinkpy.Blink(loglevel=logging.DEBUG)
blink = blinkpy.Blink()
# pylint: disable=protected-access
blinkpy._LOGGER.setLevel(logging.DEBUG)
generic_entry = {
'created_at': '1970',
'camera_name': 'foo',
@@ -141,9 +149,10 @@ class TestBlinkFunctions(unittest.TestCase):
blink.last_refresh = 0
formatted_date = get_time(blink.last_refresh)
expected_log = [
"INFO:blinkpy:Retrieving videos since {}".format(formatted_date),
"DEBUG:blinkpy:Processing page 1",
"DEBUG:blinkpy:Skipping videos for foo."
"INFO:blinkpy.blinkpy:Retrieving videos since {}".format(
formatted_date),
"DEBUG:blinkpy.blinkpy:Processing page 1",
"DEBUG:blinkpy.blinkpy:Skipping videos for foo."
]
with self.assertLogs() as dl_log:
blink.download_videos('/tmp', camera='bar', stop=2)