-
Notifications
You must be signed in to change notification settings - Fork 0
Introduce HttpProvider #15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
43668b8
extract resources Provider from Lockable and support Http resources
jupe b2bd8b3
update tests and create pip freezed requirements.txt
jupe d5a40b0
pylint cleanup
jupe c0192c4
reverse pylint rule for subprocess.Popen
jupe 0b9bf39
create coveragerc with abstract ignore
jupe bda191d
more coverage tuning
jupe 0cb998e
add pragma statement
jupe c1b637d
use typing
jupe 9d0bef5
Update provider.py
jupe a4ebaa9
Update provider.py
jupe 18850fe
Split Providers to own files
jupe 6f519e9
reload provider only when initialize lockable or when calling lock() api
jupe eb4c03d
fix unit tests against latest changes
jupe 888f076
add missing docstring
jupe 686ca33
update documentation
jupe File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
[report] | ||
exclude_lines = | ||
# Have to re-enable the standard pragma | ||
pragma: no cover | ||
|
||
@abstractmethod |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
""" Lockable module """ | ||
from lockable.lockable import Lockable, ResourceNotFound, Allocation | ||
from lockable.lockable import Lockable, ResourceNotFound, Allocation, MODULE_LOGGER | ||
from lockable.provider import Provider, ProviderError |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
""" Provider library """ | ||
from abc import ABC, abstractmethod | ||
import json | ||
import typing | ||
from typing import List | ||
import logging | ||
|
||
from urllib.parse import urlparse | ||
from pydash import filter_, count_by | ||
|
||
MODULE_LOGGER = logging.getLogger('lockable') | ||
|
||
|
||
class ProviderError(Exception): | ||
""" Provider error """ | ||
|
||
|
||
class Provider(ABC): | ||
jupe marked this conversation as resolved.
Show resolved
Hide resolved
|
||
""" Abstract Provider """ | ||
def __init__(self, uri: typing.Union[str, list]): | ||
""" Provider constructor """ | ||
self._uri = uri | ||
self._resources = list() | ||
self.reload() | ||
|
||
@property | ||
def data(self) -> list: | ||
""" Get resources list """ | ||
return self._resources | ||
|
||
@staticmethod | ||
def is_http_url(uri: str) -> bool: | ||
""" Check if argument is url format""" | ||
try: | ||
result = urlparse(uri) | ||
return all([result.scheme, result.netloc]) | ||
except: # pylint: disable=bare-except | ||
return False | ||
|
||
@abstractmethod | ||
def reload(self) -> None: # pragma: no cover | ||
""" Reload resources data""" | ||
|
||
def set_resources_list(self, resources_list: list): | ||
""" Load resources list """ | ||
assert isinstance(resources_list, list), 'resources_list is not an list' | ||
Provider._validate_json(resources_list) | ||
self._resources = resources_list | ||
MODULE_LOGGER.debug('Resources loaded: ') | ||
for resource in self._resources: | ||
MODULE_LOGGER.debug(json.dumps(resource)) | ||
|
||
@staticmethod | ||
def _validate_json(data: List[dict]): | ||
""" Internal method to validate resources.json content """ | ||
counts = count_by(data, lambda obj: obj.get('id')) | ||
no_ids = filter_(counts.keys(), lambda key: key is None) | ||
if no_ids: | ||
raise ValueError('Invalid json, id property is missing') | ||
|
||
duplicates = filter_(counts.keys(), lambda key: counts[key] > 1) | ||
if duplicates: | ||
MODULE_LOGGER.warning('Duplicates: %s', duplicates) | ||
raise ValueError(f"Invalid json, duplicate ids in {duplicates}") |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
""" resources Provider for file """ | ||
import json | ||
import os | ||
from typing import List | ||
|
||
from lockable.provider import Provider, MODULE_LOGGER | ||
|
||
|
||
class ProviderFile(Provider): | ||
""" ProviderFile interface """ | ||
|
||
def __init__(self, uri: str): | ||
""" | ||
ProviderFile constructor | ||
:param uri: file path | ||
""" | ||
self._resource_list_file_mtime = None | ||
super().__init__(uri) | ||
|
||
def reload(self): | ||
""" Load resources list file""" | ||
self.reload_resource_list_file() | ||
MODULE_LOGGER.warning('Use resources from %s file', self._uri) | ||
|
||
def reload_resource_list_file(self): | ||
""" Reload resources from file if file has been modified """ | ||
mtime = os.path.getmtime(self._uri) | ||
if self._resource_list_file_mtime != mtime: | ||
self._resource_list_file_mtime = mtime | ||
data = self._read_resources_list_file(self._uri) | ||
self.set_resources_list(data) | ||
|
||
@staticmethod | ||
def _read_resources_list_file(filename: str) -> List[dict]: | ||
""" Read resources json file """ | ||
MODULE_LOGGER.debug('Read resource list file: %s', filename) | ||
with open(filename) as json_file: | ||
try: | ||
data = json.load(json_file) | ||
assert isinstance(data, list), 'data is not an list' | ||
except (json.decoder.JSONDecodeError, AssertionError) as error: | ||
raise ValueError(f'invalid resources json file: {error}') from error | ||
return data |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
""" resources Provider helper """ | ||
from lockable.provider import Provider | ||
from lockable.provider_list import ProviderList | ||
from lockable.provider_file import ProviderFile | ||
from lockable.provider_http import ProviderHttp | ||
|
||
|
||
def create(uri): | ||
""" | ||
Create provider instance from uri | ||
:param uri: list of string for provider | ||
:return: Provider object | ||
:rtype: Provider | ||
""" | ||
if Provider.is_http_url(uri): | ||
return ProviderHttp(uri) | ||
if isinstance(uri, str): | ||
return ProviderFile(uri) | ||
if isinstance(uri, list): | ||
return ProviderList(uri) | ||
raise AssertionError('uri should be list or string') |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
""" resources Provider for HTTP """ | ||
import logging | ||
import requests | ||
from requests import HTTPError | ||
|
||
from lockable.provider import Provider, ProviderError | ||
|
||
MODULE_LOGGER = logging.getLogger('lockable') | ||
|
||
|
||
class ProviderHttp(Provider): | ||
""" ProviderHttp interface""" | ||
|
||
def __init__(self, uri: str): | ||
""" ProviderHttp constructor """ | ||
super().__init__(uri) | ||
|
||
def reload(self) -> None: | ||
""" Reload resources list from web server """ | ||
self.set_resources_list(self._get_http(self._uri)) | ||
|
||
@staticmethod | ||
def _get_http(uri: str) -> list: | ||
""" Internal method to get http json data""" | ||
try: | ||
response = requests.get(uri) | ||
response.raise_for_status() | ||
|
||
# could utilise ETag or Last-Modified headers to optimize performance | ||
# etag = response.headers.get("ETag") | ||
# last_modified = response.headers.get("Last-Modified") | ||
|
||
# access JSON content | ||
return response.json() | ||
except HTTPError as http_err: | ||
jupe marked this conversation as resolved.
Show resolved
Hide resolved
|
||
MODULE_LOGGER.error('HTTP error occurred %s', http_err) | ||
raise ProviderError(http_err.response.reason) from http_err | ||
except Exception as err: | ||
MODULE_LOGGER.error('Other error occurred: %s', err) | ||
raise ProviderError(err) from err |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
""" resources Provider for static list """ | ||
from lockable.provider import Provider | ||
|
||
|
||
class ProviderList(Provider): | ||
""" ProviderList implementation """ | ||
|
||
def __init__(self, uri: list): | ||
""" ProviderList constructor """ | ||
super().__init__(uri) | ||
self.set_resources_list(self._uri) | ||
|
||
def reload(self): | ||
""" Nothing to do """ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
[ | ||
{ | ||
"id": "2", | ||
"online": false, | ||
"hostname": "localhost", | ||
"test": true | ||
}, | ||
{ | ||
"id": "1", | ||
"online": true, | ||
"hostname": "localhost", | ||
"test": false | ||
}, | ||
{ | ||
"id": "3", | ||
"online": true, | ||
"hostname": "localhost2", | ||
"test": true | ||
} | ||
] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
certifi==2021.5.30 | ||
jupe marked this conversation as resolved.
Show resolved
Hide resolved
|
||
charset-normalizer==2.0.4 | ||
coverage==5.5 | ||
httptest==0.0.17 | ||
idna==3.2 | ||
mock==4.0.3 | ||
pid==3.0.4 | ||
pydash==5.0.0 | ||
requests==2.26.0 | ||
setuptools-scm==6.0.1 | ||
urllib3==1.26.6 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.