Skip to content

Commit

Permalink
python QA refresh with GitHub checks
Browse files Browse the repository at this point in the history
Signed-off-by: Nic Boet <[email protected]>
  • Loading branch information
nabbi committed Dec 31, 2023
1 parent aa44397 commit 9952d44
Show file tree
Hide file tree
Showing 12 changed files with 551 additions and 660 deletions.
6 changes: 6 additions & 0 deletions .github/workflows/.yamllint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---

extends: default

rules:
truthy: disable
26 changes: 26 additions & 0 deletions .github/workflows/python-qa.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
name: Python package

on:
- push
- pull_request

jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.11', '3.12']

steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install tox tox-gh-actions
- name: Test with tox
run: tox
2 changes: 0 additions & 2 deletions .hound.yml

This file was deleted.

39 changes: 0 additions & 39 deletions .travis.yml

This file was deleted.

1,029 changes: 458 additions & 571 deletions poetry.lock

Large diffs are not rendered by default.

2 changes: 0 additions & 2 deletions pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ good-names=id,i,j,k,ex,Run,_,fp,T,ev
# locally-disabled - it spams too much
# duplicate-code - unavoidable
# cyclic-import - doesn't test if both import on load
# abstract-class-little-used - prevents from setting right foundation
# unused-argument - generic callbacks and setup methods create a lot of warnings
# too-many-* - are not enforced for the sake of readability
# too-few-* - same as too-many-*
Expand All @@ -27,7 +26,6 @@ good-names=id,i,j,k,ex,Run,_,fp,T,ev
# wrong-import-order - isort guards this
disable=
format,
abstract-class-little-used,
abstract-method,
cyclic-import,
duplicate-code,
Expand Down
29 changes: 15 additions & 14 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
[tool.poetry]
name = "zm-py"
version = "0.1.0"
version = "0.5.3"
description = ""
authors = ["Rohan Kapoor <[email protected]>"]
authors = ["Rohan Kapoor <[email protected]>","Nic Boet <[email protected]>"]
license = "Apache-2.0"

readme = "README.md"
Expand All @@ -16,20 +16,21 @@ packages = [
]

[tool.poetry.dependencies]
python = "^3.6"
python = "^3.11"
requests = ">=2.0"

[tool.poetry.dev-dependencies]
pytest = "^4.6"
pylint = "^2.5.2"
pydocstyle = "^5.0.2"
mypy = "^0.770"
flake8 = "^3.8.1"
flake8-docstrings = "^1.5.0"
colorlog = "^4.1.0"
requests = "^2.23.0"
tox = "^3.15.0"
autopep8 = "^1.5.2"
pytest = "^7.4.3"
pylint = "^3.0.3"
pydocstyle = "^6.3.0"
mypy = "^1.8.0"
flake8 = "^6.1.0"
flake8-docstrings = "^1.7.0"
colorlog = "^6.8.0"
requests = "^2.31.0"
tox = "^4.11.4"
autopep8 = "^2.0.4"
platformdirs = "<4.0.0"

[tool.black]
line-length = 100
Expand All @@ -49,5 +50,5 @@ exclude = '''
'''

[build-system]
requires = ["poetry>=0.12"]
requires = ["poetry>=1.7.1"]
build-backend = "poetry.masonry.api"
16 changes: 8 additions & 8 deletions requirements_test.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# linters such as flake8 and pylint should be pinned, as new releases
# make new things fail. Manually update these pins when pulling in a
# new version
black==20.8b1
colorlog==3.1.4
flake8-docstrings==1.3.0
flake8==3.5
mypy==0.782
pydocstyle==2.1.1
pylint==2.6.0
black==23.12.1
colorlog==6.8.0
flake8-docstrings==1.7.0
flake8==6.1.0
mypy==1.8.0
pydocstyle==6.3.0
pylint==3.0.3
pylint-strict-informational==0.1
pytest==3.8.0
pytest==7.4.3
16 changes: 8 additions & 8 deletions tests/test_zm.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,37 +10,37 @@ class TestZoneMinder(unittest.TestCase):

def test_build_server_url_no_trailing_slash(self):
"""Verifies that server_url is correct with no trailing slashes."""
host = "http://zoneminder.com"
host = "https://zoneminder.com"
server_path = "zm"
self.assertEqual(
"http://zoneminder.com/zm/".format(host, server_path),
"https://zoneminder.com/zm/",
zm.ZoneMinder._build_server_url(host, server_path),
)

def test_build_server_url_with_trailing_slash_path(self):
"""Verifies that server_url is correct with trailing slash in path."""
host = "http://zoneminder.com"
host = "https://zoneminder.com"
server_path = "/zm/"
self.assertEqual(
"http://zoneminder.com/zm/".format(host, server_path),
"https://zoneminder.com/zm/",
zm.ZoneMinder._build_server_url(host, server_path),
)

def test_build_server_url_with_trailing_slash_host(self):
"""Verifies that server_url is correct with trailing slash in host."""
host = "http://zoneminder.com/"
host = "https://zoneminder.com/"
server_path = "zm/"
self.assertEqual(
"http://zoneminder.com/zm/".format(host, server_path),
"https://zoneminder.com/zm/",
zm.ZoneMinder._build_server_url(host, server_path),
)

def test_build_server_url_with_both_trailing_slash(self):
"""Verifies that server_url is correct with trailing slash in both."""
host = "http://zoneminder.com/"
host = "https://zoneminder.com/"
server_path = "/zm/"
self.assertEqual(
"http://zoneminder.com/zm/".format(host, server_path),
"https://zoneminder.com/zm/",
zm.ZoneMinder._build_server_url(host, server_path),
)

Expand Down
16 changes: 14 additions & 2 deletions tox.ini
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
[tox]
envlist = py36, py37, py38, py39, pylint, lint, typing
envlist = py311, py312, pylint, lint, typing, black
skip_missing_interpreters = True

[gh-actions]
python =
3.11: py311, pylint, lint, typing, black
3.12: py312, pylint, lint, typing, black

[testenv]
setenv =
PYTHONPATH = {toxinidir}:{toxinidir}/zoneminder
Expand Down Expand Up @@ -29,8 +34,15 @@ commands =

[testenv:typing]
basepython = {env:PYTHON3_PATH:python3}
whitelist_externals=/bin/bash
allowlist_externals=/bin/bash
deps =
-r{toxinidir}/requirements_test.txt
commands =
/bin/bash -c 'mypy zoneminder/*.py'

[testenv:black]
basepython = {env:PYTHON3_PATH:python3}
deps =
-r{toxinidir}/requirements_test.txt
commands =
black --check --diff zoneminder
18 changes: 9 additions & 9 deletions zoneminder/monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def get_time_period(value):
for time_period in TimePeriod:
if time_period.period == value:
return time_period
raise ValueError("{} is not a valid TimePeriod".format(value))
raise ValueError(f"{value} is not a valid TimePeriod")

ALL = ("all", "Events")
HOUR = ("hour", "Events Last Hour")
Expand All @@ -92,7 +92,7 @@ def __init__(self, client, raw_result):
self._raw_result = raw_result
raw_monitor = raw_result["Monitor"]
self._monitor_id = int(raw_monitor["Id"])
self._monitor_url = "api/monitors/{}.json".format(self._monitor_id)
self._monitor_url = f"api/monitors/{self._monitor_id}.json"
self._name = raw_monitor["Name"]
self._controllable = bool(int(raw_monitor["Controllable"]))
self._mjpeg_image_url = self._build_image_url(raw_monitor, "jpeg")
Expand Down Expand Up @@ -154,7 +154,7 @@ def still_image_url(self) -> str:
def is_recording(self) -> Optional[bool]:
"""Indicate if this Monitor is currently recording."""
status_response = self._client.get_state(
"api/monitors/alarm/id:{}/command:status.json".format(self._monitor_id)
f"api/monitors/alarm/id:{self._monitor_id}/command:status.json"
)

if not status_response:
Expand All @@ -172,7 +172,7 @@ def is_recording(self) -> Optional[bool]:
def is_available(self) -> bool:
"""Indicate if this Monitor is currently available."""
status_response = self._client.get_state(
"api/monitors/daemonStatus/id:{}/daemon:zmc.json".format(self._monitor_id)
f"api/monitors/daemonStatus/id:{self._monitor_id}/daemon:zmc.json"
)

if not status_response:
Expand All @@ -191,7 +191,7 @@ def get_events(self, time_period, include_archived=False) -> Optional[int]:
Specifically only gets events that have occurred within the TimePeriod
provided.
"""
date_filter = "1%20{}".format(time_period.period)
date_filter = f"1%20{time_period.period}"
if time_period == TimePeriod.ALL:
# The consoleEvents API uses DATE_SUB, so give it
# something large
Expand All @@ -202,7 +202,7 @@ def get_events(self, time_period, include_archived=False) -> Optional[int]:
archived_filter = ""

event = self._client.get_state(
"api/events/consoleEvents/{}{}.json".format(date_filter, archived_filter)
f"api/events/consoleEvents/{date_filter}{archived_filter}.json"
)

try:
Expand All @@ -222,7 +222,7 @@ def _build_image_url(self, monitor, mode) -> str:
"monitor": monitor["Id"],
}
)
url = "{zms_url}?{query}".format(zms_url=self._client.get_zms_url(), query=query)
url = f"{self._client.get_zms_url()}?{query}"
_LOGGER.debug("Monitor %s %s URL (without auth): %s", monitor["Id"], mode, url)
return self._client.get_url_with_auth(url)

Expand All @@ -231,7 +231,7 @@ def ptz_control_command(self, direction, token, base_url) -> bool:
if not self.controllable:
raise MonitorControlTypeError()

ptz_url = "{}index.php".format(base_url)
ptz_url = f"{base_url}index.php"

params = {
"view": "request",
Expand All @@ -242,5 +242,5 @@ def ptz_control_command(self, direction, token, base_url) -> bool:
"token": token,
}

req = post(url=ptz_url, params=params)
req = post(url=ptz_url, params=params, timeout=10)
return bool(req.ok)
12 changes: 7 additions & 5 deletions zoneminder/zm.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ def login(self):
urljoin(self._server_url, "api/host/login.json"),
data=login_post,
verify=self._verify_ssl,
timeout=ZoneMinder.DEFAULT_TIMEOUT,
)
if req.ok:
try:
Expand All @@ -76,6 +77,7 @@ def _legacy_auth(self):
urljoin(self._server_url, "index.php"),
data=login_post,
verify=self._verify_ssl,
timeout=ZoneMinder.DEFAULT_TIMEOUT,
)
self._cookies = req.cookies

Expand Down Expand Up @@ -133,7 +135,7 @@ def _zm_request(self, method, api_url, data=None, timeout=DEFAULT_TIMEOUT) -> di
return req.json()
except ValueError:
_LOGGER.exception(
"JSON decode exception caught while" 'attempting to decode "%s"',
'JSON decode exception caught while attempting to decode "%s"',
req.text,
)
return {}
Expand Down Expand Up @@ -188,7 +190,7 @@ def set_active_state(self, state_name):
sets a timeout of 120, which should be adequate for most users.
"""
_LOGGER.info("Setting ZoneMinder run state to state %s", state_name)
return self._zm_request("GET", "api/states/change/{}.json".format(state_name), timeout=120)
return self._zm_request("GET", f"api/states/change/{state_name}.json", timeout=120)

def get_zms_url(self) -> str:
"""Get the url to the current ZMS instance."""
Expand All @@ -199,11 +201,11 @@ def get_url_with_auth(self, url) -> str:
if not self._username:
return url

url += "&user={:s}".format(quote(self._username))
url += f"&user={quote(self._username)}"

if not self._password:
return url
return url + "&pass={:s}".format(quote(self._password))
return url + f"&pass={quote(self._password)}"

@property
def is_available(self) -> bool:
Expand Down Expand Up @@ -231,7 +233,7 @@ def _build_server_url(server_host, server_path) -> str:
server_url = urljoin(server_host, server_path)
if server_url[-1] == "/":
return server_url
return "{}/".format(server_url)
return f"{server_url}/"

def move_monitor(self, monitor: Monitor, direction: str):
"""Call Zoneminder to move."""
Expand Down

0 comments on commit 9952d44

Please sign in to comment.