Compare commits
23
Commits
v0.16.0-rc11
...
v0.16.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1b66eddfb4 | ||
|
|
22d3fa9565 | ||
|
|
9d81973b3a | ||
|
|
fe8eac3dc6 | ||
|
|
5fc315201a | ||
|
|
a9d3d5568b | ||
|
|
f88dbdaeba | ||
|
|
48028914de | ||
|
|
fcdb70d246 | ||
|
|
e8589bfa05 | ||
|
|
854ffbf26a | ||
|
|
ca109f703c | ||
|
|
82d5a7ea51 | ||
|
|
79ead7b826 | ||
|
|
6e360b2bb1 | ||
|
|
1aaa5b649f | ||
|
|
435f3b9831 | ||
|
|
bcf0bb5525 | ||
|
|
322aae37dc | ||
|
|
45cb4028b8 | ||
|
|
151d9b7375 | ||
|
|
d393c861d7 | ||
|
|
02c4b2e7e1 |
+29
@@ -4,6 +4,35 @@ Changelog
|
||||
|
||||
A list of changes between each release
|
||||
|
||||
0.16.0 (2020-07-20)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
**Breaking Changes:**
|
||||
|
||||
- Add arm property to camera, deprecate motion enable method (`#273 <https://github.com/fronzbot/blinkpy/pull/273>`__)
|
||||
- Complete refactoring of auth logic (breaks all pre-0.16.0 setups!) (`#261 <https://github.com/fronzbot/blinkpy/pull/261>`__)
|
||||
|
||||
**New Features:**
|
||||
|
||||
- Add is_errored property to Auth class (`#275 <https://github.com/fronzbot/blinkpy/pull/275>`__)
|
||||
- Add new endpoint to get user infor (`#280 <https://github.com/fronzbot/blinkpy/pull/280>`__)
|
||||
- Add get_liveview command to camera module (`#289 <https://github.com/fronzbot/blinkpy/pull/289>`__)
|
||||
- Add blink Mini Camera support (`#290 <https://github.com/fronzbot/blinkpy/pull/290>`__)
|
||||
- Add option to skip homescreen check (`#305 <https://github.com/fronzbot/blinkpy/pull/305>`__)
|
||||
- Add different timeout for video and image retrieval (`#323 <https://github.com/fronzbot/blinkpy/pull/323>`__)
|
||||
- Modifiy session to use HTTPAdapter and handle retries (`#324 <https://github.com/fronzbot/blinkpy/pull/324>`__)
|
||||
- Add retry option overrides (`#339 <https://github.com/fronzbot/blinkpy/pull/339>`__)
|
||||
|
||||
**All changes:**
|
||||
|
||||
Please see the change list in the (`Release Notes <https://github.com/fronzbot/releases/tag/v0.16.0>`__)
|
||||
|
||||
|
||||
0.15.1 (2020-07-11)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
- Bugfix: remove "Host" from auth header (`#330 <https://github.com/fronzbot/blinkpy/pull/330>`__)
|
||||
|
||||
|
||||
0.15.0 (2020-05-08)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
**Breaking Changes:**
|
||||
|
||||
+17
-5
@@ -53,17 +53,22 @@ class Auth:
|
||||
"""Return authorization header."""
|
||||
if self.token is None:
|
||||
return None
|
||||
return {"Host": self.host, "TOKEN_AUTH": self.token}
|
||||
return {"TOKEN_AUTH": self.token}
|
||||
|
||||
def create_session(self):
|
||||
def create_session(self, opts=None):
|
||||
"""Create a session for blink communication."""
|
||||
if opts is None:
|
||||
opts = {}
|
||||
backoff = opts.get("backoff", 1)
|
||||
retries = opts.get("retries", 3)
|
||||
retry_list = opts.get("retry_list", [429, 500, 502, 503, 504])
|
||||
sess = Session()
|
||||
assert_status_hook = [
|
||||
lambda response, *args, **kwargs: response.raise_for_status()
|
||||
]
|
||||
sess.hooks["response"] = assert_status_hook
|
||||
retry = Retry(
|
||||
total=3, backoff_factor=1, status_forcelist=[429, 500, 502, 503, 504]
|
||||
total=retries, backoff_factor=backoff, status_forcelist=retry_list
|
||||
)
|
||||
adapter = HTTPAdapter(max_retries=retry)
|
||||
sess.mount("https://", adapter)
|
||||
@@ -174,11 +179,18 @@ class Auth:
|
||||
"Connection error. Endpoint %s possibly down or throttled.", url,
|
||||
)
|
||||
except BlinkBadResponse:
|
||||
code = None
|
||||
reason = None
|
||||
try:
|
||||
code = response.status_code
|
||||
reason = response.reason
|
||||
except AttributeError:
|
||||
pass
|
||||
_LOGGER.error(
|
||||
"Expected json response from %s, but received: %s: %s",
|
||||
url,
|
||||
response.status_code,
|
||||
response.reason,
|
||||
code,
|
||||
reason,
|
||||
)
|
||||
except UnauthorizedError:
|
||||
try:
|
||||
|
||||
+1
-3
@@ -151,9 +151,7 @@ class BlinkCamera:
|
||||
if config.get("thumbnail", False):
|
||||
thumb_addr = config["thumbnail"]
|
||||
else:
|
||||
_LOGGER.warning(
|
||||
"Could not find thumbnail for camera %s", self.name, exc_info=True
|
||||
)
|
||||
_LOGGER.warning("Could not find thumbnail for camera %s", self.name)
|
||||
|
||||
if thumb_addr is not None:
|
||||
new_thumbnail = f"{self.sync.urls.base_url}{thumb_addr}.jpg"
|
||||
|
||||
@@ -4,7 +4,7 @@ import os
|
||||
|
||||
MAJOR_VERSION = 0
|
||||
MINOR_VERSION = 16
|
||||
PATCH_VERSION = "0-rc11"
|
||||
PATCH_VERSION = 0
|
||||
|
||||
__version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}.{PATCH_VERSION}"
|
||||
|
||||
|
||||
@@ -93,9 +93,7 @@ class BlinkSyncModule:
|
||||
self.serial = self.summary["serial"]
|
||||
self.status = self.summary["status"]
|
||||
except KeyError:
|
||||
_LOGGER.error(
|
||||
"Could not extract some sync module info: %s", response, exc_info=True
|
||||
)
|
||||
_LOGGER.error("Could not extract some sync module info: %s", response)
|
||||
|
||||
is_ok = self.get_network_info()
|
||||
self.check_new_videos()
|
||||
@@ -158,7 +156,7 @@ class BlinkSyncModule:
|
||||
try:
|
||||
return response["event"]
|
||||
except (TypeError, KeyError):
|
||||
_LOGGER.error("Could not extract events: %s", response, exc_info=True)
|
||||
_LOGGER.error("Could not extract events: %s", response)
|
||||
return False
|
||||
|
||||
def get_camera_info(self, camera_id, **kwargs):
|
||||
@@ -170,7 +168,7 @@ class BlinkSyncModule:
|
||||
try:
|
||||
return response["camera"][0]
|
||||
except (TypeError, KeyError):
|
||||
_LOGGER.error("Could not extract camera info: %s", response, exc_info=True)
|
||||
_LOGGER.error("Could not extract camera info: %s", response)
|
||||
return {}
|
||||
|
||||
def get_network_info(self):
|
||||
|
||||
@@ -30,6 +30,29 @@ By default, the ``blink.auth.Auth`` class creates its own websession via its ``c
|
||||
blink.auth = Auth()
|
||||
blink.auth.session = YourCustomSession
|
||||
|
||||
|
||||
Custom Retry Logic
|
||||
--------------------
|
||||
The built-in auth session via the ``create_session`` method allows for customizable retry intervals and conditions. These parameters are:
|
||||
|
||||
- retries
|
||||
- backoff
|
||||
- retry_list
|
||||
|
||||
``retries`` is the total number of retry attempts that each http request can do before timing out. ``backoff`` is a parameter that allows for non-linear retry times such that the time between retries is backoff*(2^(retries) - 1). ``retry_list`` is simply a list of status codes to force a retry. By default ``retries=3``, ``backoff=1``, and ``retry_list=[429, 500, 502, 503, 504]``. To override them, you need to add you overrides to a dictionary and use that to create a new session with the ``opts`` variable in the ``create_session`` method. The following example can serve as a guide where only the number of retries and backoff factor are overridden:
|
||||
|
||||
.. code:: python
|
||||
|
||||
from blinkpy.blinkpy import Blink
|
||||
from blinkpy.auth import Auth
|
||||
|
||||
blink = Blink()
|
||||
blink.auth = Auth()
|
||||
|
||||
opts = {"retries": 10, "backoff": 2}
|
||||
blink.auth.session = blink.auth.create_session(opts=opts)
|
||||
|
||||
|
||||
Custom HTTP requests
|
||||
---------------------
|
||||
In addition to custom sessions, custom blink server requests can be performed. This give you the ability to bypass the built-in ``Auth.query`` method. It also allows flexibility by giving you the option to pass your own url, rather than be limited to what is currently implemented in the ``blinkpy.api`` module.
|
||||
|
||||
@@ -8,6 +8,6 @@ pydocstyle==5.0.2
|
||||
pytest==5.4.3
|
||||
pytest-cov==2.10.0
|
||||
pytest-sugar==0.9.4
|
||||
pytest-timeout==1.4.1
|
||||
pytest-timeout==1.4.2
|
||||
restructuredtext-lint==1.3.1
|
||||
pygments==2.6.1
|
||||
|
||||
+45
-3
@@ -128,8 +128,7 @@ class TestAuth(unittest.TestCase):
|
||||
def test_header(self):
|
||||
"""Test header data."""
|
||||
self.auth.token = "bar"
|
||||
self.auth.host = "foo"
|
||||
expected_header = {"Host": "foo", "TOKEN_AUTH": "bar"}
|
||||
expected_header = {"TOKEN_AUTH": "bar"}
|
||||
self.assertDictEqual(self.auth.header, expected_header)
|
||||
|
||||
def test_header_no_token(self):
|
||||
@@ -231,7 +230,7 @@ class TestAuth(unittest.TestCase):
|
||||
@mock.patch("blinkpy.auth.Auth.refresh_token")
|
||||
def test_query_retry_failed(self, mock_refresh, mock_validate):
|
||||
"""Check handling of failed retry request."""
|
||||
self.auth.seession = MockSession()
|
||||
self.auth.session = MockSession()
|
||||
mock_validate.side_effect = [UnauthorizedError, BlinkBadResponse]
|
||||
mock_refresh.return_value = True
|
||||
self.assertEqual(self.auth.query(url="http://example.com"), None)
|
||||
@@ -239,6 +238,49 @@ class TestAuth(unittest.TestCase):
|
||||
mock_validate.side_effect = [UnauthorizedError, TokenRefreshFailed]
|
||||
self.assertEqual(self.auth.query(url="http://example.com"), None)
|
||||
|
||||
def test_default_session(self):
|
||||
"""Test default session creation."""
|
||||
sess = self.auth.create_session()
|
||||
adapter = sess.adapters["https://"]
|
||||
self.assertEqual(adapter.max_retries.total, 3)
|
||||
self.assertEqual(adapter.max_retries.backoff_factor, 1)
|
||||
self.assertEqual(
|
||||
adapter.max_retries.status_forcelist, [429, 500, 502, 503, 504]
|
||||
)
|
||||
|
||||
def test_custom_session_full(self):
|
||||
"""Test full custom session creation."""
|
||||
opts = {"backoff": 2, "retries": 10, "retry_list": [404]}
|
||||
sess = self.auth.create_session(opts=opts)
|
||||
adapter = sess.adapters["https://"]
|
||||
self.assertEqual(adapter.max_retries.total, 10)
|
||||
self.assertEqual(adapter.max_retries.backoff_factor, 2)
|
||||
self.assertEqual(adapter.max_retries.status_forcelist, [404])
|
||||
|
||||
def test_custom_session_partial(self):
|
||||
"""Test partial custom session creation."""
|
||||
opts1 = {"backoff": 2}
|
||||
opts2 = {"retries": 5}
|
||||
opts3 = {"retry_list": [101, 202]}
|
||||
sess1 = self.auth.create_session(opts=opts1)
|
||||
sess2 = self.auth.create_session(opts=opts2)
|
||||
sess3 = self.auth.create_session(opts=opts3)
|
||||
adapt1 = sess1.adapters["https://"]
|
||||
adapt2 = sess2.adapters["https://"]
|
||||
adapt3 = sess3.adapters["https://"]
|
||||
|
||||
self.assertEqual(adapt1.max_retries.total, 3)
|
||||
self.assertEqual(adapt1.max_retries.backoff_factor, 2)
|
||||
self.assertEqual(adapt1.max_retries.status_forcelist, [429, 500, 502, 503, 504])
|
||||
|
||||
self.assertEqual(adapt2.max_retries.total, 5)
|
||||
self.assertEqual(adapt2.max_retries.backoff_factor, 1)
|
||||
self.assertEqual(adapt2.max_retries.status_forcelist, [429, 500, 502, 503, 504])
|
||||
|
||||
self.assertEqual(adapt3.max_retries.total, 3)
|
||||
self.assertEqual(adapt3.max_retries.backoff_factor, 1)
|
||||
self.assertEqual(adapt3.max_retries.status_forcelist, [101, 202])
|
||||
|
||||
|
||||
class MockSession:
|
||||
"""Object to mock a session."""
|
||||
|
||||
@@ -117,10 +117,7 @@ class TestBlinkCameraSetup(unittest.TestCase):
|
||||
"WARNING:blinkpy.camera:Could not retrieve calibrated "
|
||||
"temperature."
|
||||
),
|
||||
(
|
||||
"WARNING:blinkpy.camera:Could not find thumbnail for camera new"
|
||||
"\nNoneType: None"
|
||||
),
|
||||
("WARNING:blinkpy.camera:Could not find thumbnail for camera new"),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user