-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #21 from 2Fake/development
Prepare release
- Loading branch information
Showing
39 changed files
with
909 additions
and
934 deletions.
There are no files selected for viewing
This file contains 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 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 |
---|---|---|
|
@@ -17,4 +17,4 @@ jobs: | |
TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
LABEL: "# TODO:" | ||
COMMENT_MARKER: "#" | ||
id: "todo" | ||
id: "todo" |
This file contains 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 |
---|---|---|
|
@@ -3,36 +3,95 @@ name: Python package | |
on: [push] | ||
|
||
jobs: | ||
build: | ||
|
||
format: | ||
name: Check formatting | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Checkout sources | ||
uses: actions/checkout@v2 | ||
- name: Set up Python | ||
uses: actions/setup-python@v2 | ||
with: | ||
python-version: 3.8 | ||
- name: Check formatting | ||
uses: pre-commit/[email protected] | ||
|
||
lint: | ||
name: Lint | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Checkout sources | ||
uses: actions/checkout@v2 | ||
- name: Set up Python | ||
uses: actions/setup-python@v2 | ||
with: | ||
python-version: 3.8 | ||
- name: Lint with flake8 | ||
run: | | ||
python -m pip install --upgrade pip | ||
pip install flake8 | ||
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics | ||
flake8 . --count --exit-zero --statistics | ||
- name: Lint with pylint | ||
run: | | ||
pip install pylint | ||
pip install -e . | ||
pylint --errors-only --score=n devolo_plc_api | ||
pylint --exit-zero --score=n --disable=C,E,R --enable=useless-suppression --ignore-patterns=.*_pb2.py devolo_plc_api devolo_plc_api | ||
- name: Lint with mypy | ||
run: | | ||
pip install mypy | ||
mypy devolo_plc_api | ||
test: | ||
name: Test with Python ${{ matrix.python-version }} | ||
runs-on: ubuntu-latest | ||
strategy: | ||
matrix: | ||
python-version: [3.7, 3.8] | ||
|
||
python-version: [3.7, 3.8, 3.9] | ||
steps: | ||
- uses: actions/checkout@v2 | ||
- name: Checkout sources | ||
uses: actions/checkout@v2 | ||
- name: Set up Python ${{ matrix.python-version }} | ||
uses: actions/setup-python@v1 | ||
uses: actions/setup-python@v2 | ||
with: | ||
python-version: ${{ matrix.python-version }} | ||
- name: Install dependencies | ||
run: | | ||
python -m pip install --upgrade pip | ||
- name: Lint with flake8 | ||
run: | | ||
pip install flake8 | ||
# stop the build if there are Python syntax errors or undefined names | ||
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics | ||
# exit-zero treats all errors as warnings. | ||
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --ignore=E303,W503 --statistics --exclude=.*,devolo_plc_api/*/devolo_idl_*.py | ||
pip install -e .[test] | ||
- name: Test with pytest | ||
run: | | ||
python setup.py test --addopts --cov=devolo_plc_api | ||
pytest --cov=devolo_plc_api | ||
- name: Preserve coverage | ||
uses: actions/upload-artifact@v2 | ||
with: | ||
name: coverage | ||
path: .coverage | ||
|
||
coverage: | ||
name: Upload coverage | ||
runs-on: ubuntu-latest | ||
needs: test | ||
steps: | ||
- name: Checkout sources | ||
uses: actions/checkout@v2 | ||
- name: Set up Python | ||
uses: actions/setup-python@v2 | ||
with: | ||
python-version: 3.8 | ||
- name: Download coverage | ||
uses: actions/download-artifact@v2 | ||
with: | ||
name: coverage | ||
- name: Coveralls | ||
run: | | ||
pip install coveralls==1.10.0 | ||
python -m pip install --upgrade pip | ||
pip install wheel coveralls==1.10.0 | ||
export COVERALLS_REPO_TOKEN=${{ secrets.COVERALLS_TOKEN }} | ||
coveralls | ||
- name: Clean up coverage | ||
uses: geekyeggo/delete-artifact@v1 | ||
with: | ||
name: coverage |
This file contains 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 |
---|---|---|
|
@@ -138,6 +138,5 @@ dmypy.json | |
### PyCharm ### | ||
.idea | ||
|
||
|
||
### Testfile ### | ||
test.py | ||
test.py |
This file contains 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 @@ | ||
repos: | ||
- repo: https://github.com/pre-commit/mirrors-yapf | ||
rev: '' | ||
hooks: | ||
- id: yapf | ||
- repo: https://github.com/pycqa/isort | ||
rev: '' | ||
hooks: | ||
- id: isort | ||
- repo: https://github.com/pre-commit/pre-commit-hooks | ||
rev: '' | ||
hooks: | ||
- id: end-of-file-fixer | ||
- id: trailing-whitespace |
This file contains 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 @@ | ||
devolo_plc_api/*/devolo_idl_*.py |
This file contains 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 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 +1 @@ | ||
__version__ = "0.2.0" | ||
__version__ = "0.3.0" |
This file contains 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,62 +1,70 @@ | ||
from logging import Logger | ||
import asyncio | ||
import logging | ||
from abc import ABC, abstractclassmethod | ||
from typing import Callable | ||
|
||
from google.protobuf.json_format import MessageToDict | ||
from httpx import DigestAuth, Response | ||
from httpx import AsyncClient, DigestAuth, Response | ||
|
||
from ..exceptions.device import DevicePasswordProtected | ||
|
||
TIMEOUT = 3.0 | ||
|
||
|
||
class Protobuf: | ||
class Protobuf(ABC): | ||
""" | ||
Google Protobuf client. This client is not usable stand alone but needs to be derived. | ||
Google Protobuf client. | ||
""" | ||
_logger: Logger | ||
|
||
@abstractclassmethod | ||
def __init__(self): | ||
self._loop = asyncio.get_running_loop() | ||
self._logger = logging.getLogger(self.__class__.__name__) | ||
|
||
self.password: str | ||
|
||
self._ip: str | ||
self._path: str | ||
self._port: int | ||
self._session: AsyncClient | ||
self._user: str | ||
self._version: str | ||
|
||
def __getattr__(self, attr: str) -> Callable: | ||
""" Catch attempts to call methods synchronously. """ | ||
|
||
def method(*args, **kwargs): | ||
return self._loop.run_until_complete(getattr(self, async_method)(*args, **kwargs)) | ||
|
||
async_method = f"async_{attr}" | ||
if hasattr(self.__class__, async_method): | ||
return method | ||
raise AttributeError(f"{self.__class__.__name__} object has no attribute {attr}") | ||
|
||
@property | ||
def url(self) -> str: | ||
""" The base URL to query. """ | ||
return f"http://{self._ip}:{self._port}/{self._path}/{self._version}/" # type: ignore | ||
|
||
return f"http://{self._ip}:{self._port}/{self._path}/{self._version}/" | ||
|
||
async def _async_get(self, sub_url: str, timeout: float = TIMEOUT) -> Response: | ||
""" Query URL asynchronously. """ | ||
url = f"{self.url}{sub_url}" | ||
self._logger.debug(f"Getting from {url}") | ||
self._logger.debug("Getting from %s", url) | ||
try: | ||
return await self._session.get(url, auth=DigestAuth(self._user, self._password), timeout=timeout) # type: ignore | ||
return await self._session.get(url, auth=DigestAuth(self._user, self.password), timeout=timeout) | ||
except TypeError: | ||
raise DevicePasswordProtected("The used password is wrong.") from None | ||
|
||
def _get(self, sub_url: str, timeout: float = TIMEOUT) -> Response: | ||
""" Query URL synchronously. """ | ||
async def _async_post(self, sub_url: str, content: bytes, timeout: float = TIMEOUT) -> Response: | ||
""" Post data asynchronously. """ | ||
url = f"{self.url}{sub_url}" | ||
self._logger.debug(f"Getting from {url}") | ||
self._logger.debug("Posting to %s", url) | ||
try: | ||
return self._session.get(url, auth=DigestAuth(self._user, self._password), timeout=timeout) # type: ignore | ||
return await self._session.post(url, auth=DigestAuth(self._user, self.password), content=content, timeout=timeout) | ||
except TypeError: | ||
raise DevicePasswordProtected("The used password is wrong.") from None | ||
|
||
def _message_to_dict(self, message) -> dict: | ||
@staticmethod | ||
def _message_to_dict(message) -> dict: | ||
""" Convert message to dict with certain settings. """ | ||
return MessageToDict(message=message, including_default_value_fields=True, preserving_proto_field_name=True) | ||
|
||
async def _async_post(self, sub_url: str, data: str, timeout: float = TIMEOUT) -> Response: | ||
""" Post data asynchronously. """ | ||
url = f"{self.url}{sub_url}" | ||
self._logger.debug(f"Posting to {url}") | ||
try: | ||
return await self._session.post(url, auth=DigestAuth(self._user, self._password), data=data, timeout=timeout) # type: ignore | ||
except TypeError: | ||
raise DevicePasswordProtected("The used password is wrong.") from None | ||
|
||
def _post(self, sub_url: str, data: str, timeout: float = TIMEOUT) -> Response: | ||
""" Post data synchronously. """ | ||
url = f"{self.url}{sub_url}" | ||
self._logger.debug(f"Posting to {url}") | ||
try: | ||
return self._session.post(url, auth=DigestAuth(self._user, self._password), data=data, timeout=timeout) # type: ignore | ||
except TypeError: | ||
raise DevicePasswordProtected("The used password is wrong.") from None |
Oops, something went wrong.