Compare commits

...
32 Commits
Author SHA1 Message Date
Kevin FronczakandGitHub 3a97a928de Merge pull request #348 from fronzbot/0.16.1-changelog
Updated versions and changelog for 0.16.1
2020-07-29 11:27:26 -04:00
Kevin Fronczak 0322414de1 Updated versions and changelog for 0.16.1 2020-07-29 15:23:59 +00:00
Kevin FronczakandGitHub 1c75e86863 Merge pull request #347 from fronzbot/unpin-reqs
Set min version for reqs instead of pinning
2020-07-29 11:23:11 -04:00
Kevin FronczakandGitHub 0ae71f6367 Merge pull request #345 from fronzbot/dependabot/pip/pytest-6.0.0
Bump pytest from 5.4.3 to 6.0.0
2020-07-29 11:19:38 -04:00
Kevin FronczakandGitHub af7c38695a Merge pull request #344 from fronzbot/dependabot/pip/coverage-5.2.1
Bump coverage from 5.2 to 5.2.1
2020-07-29 11:19:21 -04:00
Kevin Fronczak c741c22876 Set min version for reqs instead of pinning 2020-07-29 15:15:19 +00:00
dependabot-preview[bot]andGitHub 06b9b12eeb Bump pytest from 5.4.3 to 6.0.0
Bumps [pytest](https://github.com/pytest-dev/pytest) from 5.4.3 to 6.0.0.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/5.4.3...6.0.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-07-29 08:05:56 +00:00
dependabot-preview[bot]andGitHub daf7078f98 Bump coverage from 5.2 to 5.2.1
Bumps [coverage](https://github.com/nedbat/coveragepy) from 5.2 to 5.2.1.
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](https://github.com/nedbat/coveragepy/compare/coverage-5.2...coverage-5.2.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-07-27 08:17:40 +00:00
Kevin FronczakandGitHub c2db57ecb3 Merge pull request #341 from fronzbot/dev-bump
Dev version bump
2020-07-20 23:01:51 -04:00
Kevin Fronczak 0336c6a8f8 Dev version bump 2020-07-20 02:24:28 +00:00
Kevin Fronczak 22d3fa9565 Merge remote-tracking branch 'origin/master' into dev 2020-07-20 02:19:27 +00:00
Kevin FronczakandGitHub 9d81973b3a Merge pull request #339 from fronzbot/retry-options
Retry options
2020-07-19 21:47:40 -04:00
Kevin Fronczak fe8eac3dc6 Update documentation 2020-07-20 01:42:07 +00:00
Kevin Fronczak 5fc315201a Add tests for retry options 2020-07-20 01:33:11 +00:00
Kevin Fronczak a9d3d5568b Adding retry options to auth class 2020-07-20 01:25:09 +00:00
Kevin FronczakandGitHub f88dbdaeba Merge pull request #338 from fronzbot/fix-auth-tests
Fix broken test and missing try/except
2020-07-19 21:24:50 -04:00
Kevin Fronczak 48028914de Fix broken test and missing try/except 2020-07-20 01:18:41 +00:00
Kevin FronczakandGitHub fcdb70d246 Merge pull request #337 from fronzbot/remove-exec-info
Removed all exc_info parameters during logging
2020-07-19 20:51:38 -04:00
Kevin Fronczak e8589bfa05 Fix test 2020-07-20 00:48:40 +00:00
Kevin Fronczak 854ffbf26a Removed all exc_info parameters during logging 2020-07-20 00:37:30 +00:00
Kevin FronczakandGitHub ca109f703c Merge pull request #336 from fronzbot/dev-bump
Dev version bump
2020-07-19 20:37:22 -04:00
Kevin Fronczak 82d5a7ea51 Dev version bump 2020-07-20 00:34:06 +00:00
Kevin FronczakandGitHub 79ead7b826 Merge pull request #333 from fronzbot/dependabot/pip/pytest-timeout-1.4.2
Bump pytest-timeout from 1.4.1 to 1.4.2
2020-07-16 13:03:03 -04:00
dependabot-preview[bot]andGitHub 6e360b2bb1 Bump pytest-timeout from 1.4.1 to 1.4.2
Bumps [pytest-timeout](https://github.com/pytest-dev/pytest-timeout) from 1.4.1 to 1.4.2.
- [Release notes](https://github.com/pytest-dev/pytest-timeout/releases)
- [Commits](https://github.com/pytest-dev/pytest-timeout/compare/1.4.1...1.4.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-07-16 08:06:30 +00:00
Kevin FronczakandGitHub 1aaa5b649f Merge pull request #331 from fronzbot/remove-host
Remove host from auth header
2020-07-11 11:24:47 -04:00
Kevin FronczakandGitHub 435f3b9831 Update CHANGES.rst 2020-07-11 10:44:37 -04:00
Kevin FronczakandGitHub bcf0bb5525 Merge pull request #330 from fronzbot/bugfix
Bugfix: remove Host from auth header
2020-07-11 10:42:44 -04:00
Kevin Fronczak 322aae37dc fix test (remove host) 2020-07-11 14:41:44 +00:00
Kevin Fronczak 45cb4028b8 Remove host from auth header 2020-07-11 14:39:45 +00:00
Kevin Fronczak 151d9b7375 Version bump 2020-07-11 14:37:04 +00:00
Kevin Fronczak d393c861d7 bugfix: remove host from auth header 2020-07-11 14:36:37 +00:00
Kevin Fronczak 02c4b2e7e1 Add rst linter to pre-commit and fix flake8 2020-07-11 14:36:06 +00:00
10 changed files with 135 additions and 28 deletions
+37
View File
@@ -4,6 +4,43 @@ Changelog
A list of changes between each release A list of changes between each release
0.16.1 (2020-07-29)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Unpin requeirements, set minimum version instead
- Bump coverage to 5.2.1
- Bump pytest to 6.0.0
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) 0.15.0 (2020-05-08)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**Breaking Changes:** **Breaking Changes:**
+17 -5
View File
@@ -53,17 +53,22 @@ class Auth:
"""Return authorization header.""" """Return authorization header."""
if self.token is None: if self.token is None:
return 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.""" """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() sess = Session()
assert_status_hook = [ assert_status_hook = [
lambda response, *args, **kwargs: response.raise_for_status() lambda response, *args, **kwargs: response.raise_for_status()
] ]
sess.hooks["response"] = assert_status_hook sess.hooks["response"] = assert_status_hook
retry = Retry( 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) adapter = HTTPAdapter(max_retries=retry)
sess.mount("https://", adapter) sess.mount("https://", adapter)
@@ -174,11 +179,18 @@ class Auth:
"Connection error. Endpoint %s possibly down or throttled.", url, "Connection error. Endpoint %s possibly down or throttled.", url,
) )
except BlinkBadResponse: except BlinkBadResponse:
code = None
reason = None
try:
code = response.status_code
reason = response.reason
except AttributeError:
pass
_LOGGER.error( _LOGGER.error(
"Expected json response from %s, but received: %s: %s", "Expected json response from %s, but received: %s: %s",
url, url,
response.status_code, code,
response.reason, reason,
) )
except UnauthorizedError: except UnauthorizedError:
try: try:
+1 -3
View File
@@ -151,9 +151,7 @@ class BlinkCamera:
if config.get("thumbnail", False): if config.get("thumbnail", False):
thumb_addr = config["thumbnail"] thumb_addr = config["thumbnail"]
else: else:
_LOGGER.warning( _LOGGER.warning("Could not find thumbnail for camera %s", self.name)
"Could not find thumbnail for camera %s", self.name, exc_info=True
)
if thumb_addr is not None: if thumb_addr is not None:
new_thumbnail = f"{self.sync.urls.base_url}{thumb_addr}.jpg" new_thumbnail = f"{self.sync.urls.base_url}{thumb_addr}.jpg"
+1 -1
View File
@@ -4,7 +4,7 @@ import os
MAJOR_VERSION = 0 MAJOR_VERSION = 0
MINOR_VERSION = 16 MINOR_VERSION = 16
PATCH_VERSION = "0-rc11" PATCH_VERSION = 1
__version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}.{PATCH_VERSION}" __version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}.{PATCH_VERSION}"
+3 -5
View File
@@ -93,9 +93,7 @@ class BlinkSyncModule:
self.serial = self.summary["serial"] self.serial = self.summary["serial"]
self.status = self.summary["status"] self.status = self.summary["status"]
except KeyError: except KeyError:
_LOGGER.error( _LOGGER.error("Could not extract some sync module info: %s", response)
"Could not extract some sync module info: %s", response, exc_info=True
)
is_ok = self.get_network_info() is_ok = self.get_network_info()
self.check_new_videos() self.check_new_videos()
@@ -158,7 +156,7 @@ class BlinkSyncModule:
try: try:
return response["event"] return response["event"]
except (TypeError, KeyError): except (TypeError, KeyError):
_LOGGER.error("Could not extract events: %s", response, exc_info=True) _LOGGER.error("Could not extract events: %s", response)
return False return False
def get_camera_info(self, camera_id, **kwargs): def get_camera_info(self, camera_id, **kwargs):
@@ -170,7 +168,7 @@ class BlinkSyncModule:
try: try:
return response["camera"][0] return response["camera"][0]
except (TypeError, KeyError): 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 {} return {}
def get_network_info(self): def get_network_info(self):
+23
View File
@@ -30,6 +30,29 @@ By default, the ``blink.auth.Auth`` class creates its own websession via its ``c
blink.auth = Auth() blink.auth = Auth()
blink.auth.session = YourCustomSession 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 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. 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.
+4 -4
View File
@@ -1,4 +1,4 @@
python-dateutil~=2.8.1 python-dateutil>=2.8.1
requests~=2.24.0 requests>=2.24.0
python-slugify~=4.0.1 python-slugify>=4.0.1
testtools==2.4.0 testtools>=2.4.0
+3 -3
View File
@@ -1,13 +1,13 @@
black==19.10b0 black==19.10b0
coverage==5.2 coverage==5.2.1
flake8==3.8.3 flake8==3.8.3
flake8-docstrings==1.5.0 flake8-docstrings==1.5.0
pre-commit==2.6.0 pre-commit==2.6.0
pylint==2.5.3 pylint==2.5.3
pydocstyle==5.0.2 pydocstyle==5.0.2
pytest==5.4.3 pytest==6.0.0
pytest-cov==2.10.0 pytest-cov==2.10.0
pytest-sugar==0.9.4 pytest-sugar==0.9.4
pytest-timeout==1.4.1 pytest-timeout==1.4.2
restructuredtext-lint==1.3.1 restructuredtext-lint==1.3.1
pygments==2.6.1 pygments==2.6.1
+45 -3
View File
@@ -128,8 +128,7 @@ class TestAuth(unittest.TestCase):
def test_header(self): def test_header(self):
"""Test header data.""" """Test header data."""
self.auth.token = "bar" self.auth.token = "bar"
self.auth.host = "foo" expected_header = {"TOKEN_AUTH": "bar"}
expected_header = {"Host": "foo", "TOKEN_AUTH": "bar"}
self.assertDictEqual(self.auth.header, expected_header) self.assertDictEqual(self.auth.header, expected_header)
def test_header_no_token(self): def test_header_no_token(self):
@@ -231,7 +230,7 @@ class TestAuth(unittest.TestCase):
@mock.patch("blinkpy.auth.Auth.refresh_token") @mock.patch("blinkpy.auth.Auth.refresh_token")
def test_query_retry_failed(self, mock_refresh, mock_validate): def test_query_retry_failed(self, mock_refresh, mock_validate):
"""Check handling of failed retry request.""" """Check handling of failed retry request."""
self.auth.seession = MockSession() self.auth.session = MockSession()
mock_validate.side_effect = [UnauthorizedError, BlinkBadResponse] mock_validate.side_effect = [UnauthorizedError, BlinkBadResponse]
mock_refresh.return_value = True mock_refresh.return_value = True
self.assertEqual(self.auth.query(url="http://example.com"), None) self.assertEqual(self.auth.query(url="http://example.com"), None)
@@ -239,6 +238,49 @@ class TestAuth(unittest.TestCase):
mock_validate.side_effect = [UnauthorizedError, TokenRefreshFailed] mock_validate.side_effect = [UnauthorizedError, TokenRefreshFailed]
self.assertEqual(self.auth.query(url="http://example.com"), None) 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: class MockSession:
"""Object to mock a session.""" """Object to mock a session."""
+1 -4
View File
@@ -117,10 +117,7 @@ class TestBlinkCameraSetup(unittest.TestCase):
"WARNING:blinkpy.camera:Could not retrieve calibrated " "WARNING:blinkpy.camera:Could not retrieve calibrated "
"temperature." "temperature."
), ),
( ("WARNING:blinkpy.camera:Could not find thumbnail for camera new"),
"WARNING:blinkpy.camera:Could not find thumbnail for camera new"
"\nNoneType: None"
),
], ],
) )