Skip to content

Commit

Permalink
Add black to CI/dev workflow (#22)
Browse files Browse the repository at this point in the history
This commit adds [black](https://github.com/psf/black) to the
development workflow for pyopnsense. Using an autoformatter will
simplify development because we no longer have to worry about formatting
code with a consistent style used in the project because black will just
make the changes necessary automatically.

Black has been added to all the CI configurations and a full run has
been made on the repository updating the formatting.
  • Loading branch information
mtreinish authored Jun 18, 2023
1 parent aa8d2ef commit 5d59535
Show file tree
Hide file tree
Showing 13 changed files with 98 additions and 83 deletions.
5 changes: 2 additions & 3 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,11 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install tox flake8
python -m pip install tox
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: Lint with flake8
run: |
# stop the build if there are Python syntax errors or undefined names
flake8 . --count --show-source --statistics
tox -epep8
- name: Tests
run: |
tox -epy
3 changes: 2 additions & 1 deletion pyopnsense/backup.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class BackupClient(client.OPNClient):
"""A client for interacting with the backup endpoint. To use it, make
sure the os-api-backup plugin is installed.
:param str api_key: The API key to use for requests
:param str api_secret: The API secret to use for requests
:param str base_url: The base API endpoint for the OPNsense deployment
Expand All @@ -34,4 +35,4 @@ def download(self):
:returns: Returns the OPNsense configuration as XML string.
:rtype: str
"""
return self._get('backup/backup/download', True)
return self._get("backup/backup/download", True)
31 changes: 20 additions & 11 deletions pyopnsense/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@
class OPNClient(object):
"""Representation of the OPNsense API client."""

def __init__(self, api_key, api_secret, base_url, verify_cert=False,
timeout=DEFAULT_TIMEOUT):
def __init__(
self, api_key, api_secret, base_url, verify_cert=False, timeout=DEFAULT_TIMEOUT
):
"""Initialize the OPNsense API client."""
self.api_key = api_key
self.api_secret = api_secret
Expand All @@ -46,18 +47,26 @@ def _process_response(self, response, raw=False):
return response.text if raw else json.loads(response.text)
else:
raise exceptions.APIException(
status_code=response.status_code, resp_body=response.text)
status_code=response.status_code, resp_body=response.text
)

def _get(self, endpoint, raw=False):
req_url = '{}/{}'.format(self.base_url, endpoint)
response = requests.get(req_url, verify=self.verify_cert,
auth=(self.api_key, self.api_secret),
timeout=self.timeout)
req_url = "{}/{}".format(self.base_url, endpoint)
response = requests.get(
req_url,
verify=self.verify_cert,
auth=(self.api_key, self.api_secret),
timeout=self.timeout,
)
return self._process_response(response, raw)

def _post(self, endpoint, body, raw=False):
req_url = '{}/{}'.format(self.base_url, endpoint)
response = requests.post(req_url, data=body, verify=self.verify_cert,
auth=(self.api_key, self.api_secret),
timeout=self.timeout)
req_url = "{}/{}".format(self.base_url, endpoint)
response = requests.post(
req_url,
data=body,
verify=self.verify_cert,
auth=(self.api_key, self.api_secret),
timeout=self.timeout,
)
return self._process_response(response, raw)
37 changes: 21 additions & 16 deletions pyopnsense/diagnostics.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,14 @@ class NetFlowClient(client.OPNClient):
:param str api_secret: The API secret to use for requests
:param str base_url: The base API endpoint for the OPNsense deployment
"""

def status(self):
"""Return the current netflow status.
:returns: A dict representing the current status of netflow
:rtype: dict
"""
return self._get('diagnostics/netflow/status')
return self._get("diagnostics/netflow/status")


class InterfaceClient(client.OPNClient):
Expand All @@ -44,13 +45,14 @@ class InterfaceClient(client.OPNClient):
:param str base_url: The base API endpoint for the OPNsense deployment
:param int timeout: The timeout in seconds for API requests
"""

def get_ndp(self):
"""Get NDP table for router."""
return self._get('diagnostics/interface/getNdp')
return self._get("diagnostics/interface/getNdp")

def get_arp(self):
"""Get ARP table for router."""
return self._get('diagnostics/interface/getArp')
return self._get("diagnostics/interface/getArp")


class NetworkInsightClient(client.OPNClient):
Expand All @@ -61,21 +63,22 @@ class NetworkInsightClient(client.OPNClient):
:param str base_url: The base API endpoint for the OPNsense deployment
:param int timeout: The timeout in seconds for API requests
"""

def get_interfaces(self):
"""Return the available interfaces."""
return self._get('diagnostics/networkinsight/getinterfaces')
return self._get("diagnostics/networkinsight/getinterfaces")

def get_services(self):
"""Return the available services."""
return self._get('diagnostics/networkinsight/getservices')
return self._get("diagnostics/networkinsight/getservices")

def get_protocols(self):
"""Return the protocols."""
return self._get('diagnostics/networkinsight/getprotocols')
return self._get("diagnostics/networkinsight/getprotocols")

def get_timeserie(self):
"""Return the time serie."""
return self._get('diagnostics/networkinsight/timeserie')
return self._get("diagnostics/networkinsight/timeserie")


class SystemHealthClient(client.OPNClient):
Expand All @@ -86,25 +89,27 @@ class SystemHealthClient(client.OPNClient):
:param str base_url: The base API endpoint for the OPNsense deployment
:param int timeout: The timeout in seconds for API requests
"""

def get_health_list(self):
"""Return the health list."""
return self._get('diagnostics/systemhealth/getRRDlist')
return self._get("diagnostics/systemhealth/getRRDlist")

def get_health_data(self, metric, start=0, stop=0, maxitems=1024,
inverse=False, details=False):
def get_health_data(
self, metric, start=0, stop=0, maxitems=1024, inverse=False, details=False
):
"""Return the health data."""
url = ['diagnostics/systemhealth/getSystemHealth']
url = ["diagnostics/systemhealth/getSystemHealth"]
url.append(urllib.parse.quote(metric))
url.append(start)
url.append(stop)
url.append(maxitems)
if inverse:
url.append('true')
url.append("true")
else:
url.append('false')
url.append("false")
if details:
url.append('true')
url.append("true")
else:
url.append('false')
url.append("false")

return self._get('/'.join(url))
return self._get("/".join(url))
2 changes: 1 addition & 1 deletion pyopnsense/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,5 @@ def __init__(self, status_code=None, resp_body=None, *args, **kwargs):
"""Initialize the API exception."""
self.resp_body = resp_body
self.status_code = status_code
message = kwargs.get('message', resp_body)
message = kwargs.get("message", resp_body)
super(APIException, self).__init__(message, *args, **kwargs)
11 changes: 3 additions & 8 deletions pyopnsense/firewall.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@ def get_automation_rules(self):
return self._get("firewall/filter/searchRule")

def get_rule_status(self, uuid):
"""
Return the current status (enabled/disabled) of a specific firewall
"""Return the current status (enabled/disabled) of a specific firewall
rule
Parameter: uuid
Expand All @@ -49,17 +48,13 @@ def get_rule_status(self, uuid):
return self._get(f"firewall/filter/getRule/{uuid}")

def toggle_rule(self, uuid):
"""
Function to toggle a specific rule by uuid
"""Function to toggle a specific rule by uuid
:returns: A dict representing the new status of the rule
:rtype: dict
"""
return self._post(f"firewall/filter/toggleRule/{uuid}", "")

def apply_rules(self):
"""
Function to apply changes to rules.
"""
"""Function to apply changes to rules."""
self._post("firewall/filter/apply/", "")
8 changes: 4 additions & 4 deletions pyopnsense/firmware.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def status(self):
OPNsense firmware.
:rtype: dict
"""
return self._get('core/firmware/status')
return self._get("core/firmware/status")

def upgrade(self, upgrade_list=None):
"""Issue an upgrade request.
Expand All @@ -45,6 +45,6 @@ def upgrade(self, upgrade_list=None):
specified it will issue a request to upgrade all packages.
"""
if upgrade_list is None:
upgrade_list = 'all'
body = json.dumps({'upgrade': upgrade_list})
return self._post('core/firmware/upgrade', body)
upgrade_list = "all"
body = json.dumps({"upgrade": upgrade_list})
return self._post("core/firmware/upgrade", body)
2 changes: 1 addition & 1 deletion pyopnsense/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,4 @@ def status(self):
:returns: A dict representing the current status of gateways
:rtype: dict
"""
return self._get('routes/gateway/status')
return self._get("routes/gateway/status")
12 changes: 5 additions & 7 deletions pyopnsense/tests/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,10 @@


class TestCase(testtools.TestCase):

def setUp(self):
super(TestCase, self).setUp()
stdout = self.useFixture(fixtures.StringStream('stdout')).stream
self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout))
stderr = self.useFixture(fixtures.StringStream('stderr')).stream
self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
self.useFixture(fixtures.LoggerFixture(nuke_handlers=False,
level=None))
stdout = self.useFixture(fixtures.StringStream("stdout")).stream
self.useFixture(fixtures.MonkeyPatch("sys.stdout", stdout))
stderr = self.useFixture(fixtures.StringStream("stderr")).stream
self.useFixture(fixtures.MonkeyPatch("sys.stderr", stderr))
self.useFixture(fixtures.LoggerFixture(nuke_handlers=False, level=None))
52 changes: 27 additions & 25 deletions pyopnsense/tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,58 +18,60 @@

import json

import mock
from unittest import mock

from pyopnsense import client
from pyopnsense import exceptions
from pyopnsense.tests import base


class TestOPNClient(base.TestCase):

@mock.patch('requests.get')
@mock.patch("requests.get")
def test_get_success(self, request_mock):
response_mock = mock.MagicMock()
response_mock.status_code = 200
response_mock.text = json.dumps({'a': 'body'})
response_mock.text = json.dumps({"a": "body"})
request_mock.return_value = response_mock
opnclient = client.OPNClient('', '', '', timeout=10)
resp = opnclient._get('fake_url')
self.assertEqual({'a': 'body'}, resp)
opnclient = client.OPNClient("", "", "", timeout=10)
resp = opnclient._get("fake_url")
self.assertEqual({"a": "body"}, resp)
request_mock.assert_called_once_with(
'/fake_url', auth=('', ''), timeout=10, verify=False)
"/fake_url", auth=("", ""), timeout=10, verify=False
)

@mock.patch('requests.get')
@mock.patch("requests.get")
def test_get_failures(self, request_mock):
response_mock = mock.MagicMock()
response_mock.status_code = 401
response_mock.text = json.dumps({'a': 'body'})
response_mock.text = json.dumps({"a": "body"})
request_mock.return_value = response_mock
opnclient = client.OPNClient('', '', '')
self.assertRaises(exceptions.APIException, opnclient._get, 'fake_url')
opnclient = client.OPNClient("", "", "")
self.assertRaises(exceptions.APIException, opnclient._get, "fake_url")
request_mock.assert_called_once_with(
'/fake_url', auth=('', ''), timeout=5, verify=False)
"/fake_url", auth=("", ""), timeout=5, verify=False
)

@mock.patch('requests.post')
@mock.patch("requests.post")
def test_post_success(self, request_mock):
response_mock = mock.MagicMock()
response_mock.status_code = 200
response_mock.text = json.dumps({'a': 'body'})
response_mock.text = json.dumps({"a": "body"})
request_mock.return_value = response_mock
opnclient = client.OPNClient('', '', '')
resp = opnclient._post('fake_url', 'body')
self.assertEqual({'a': 'body'}, resp)
opnclient = client.OPNClient("", "", "")
resp = opnclient._post("fake_url", "body")
self.assertEqual({"a": "body"}, resp)
request_mock.assert_called_once_with(
'/fake_url', data='body', auth=('', ''), timeout=5, verify=False)
"/fake_url", data="body", auth=("", ""), timeout=5, verify=False
)

@mock.patch('requests.post')
@mock.patch("requests.post")
def test_post_failures(self, request_mock):
response_mock = mock.MagicMock()
response_mock.status_code = 401
response_mock.text = json.dumps({'a': 'body'})
response_mock.text = json.dumps({"a": "body"})
request_mock.return_value = response_mock
opnclient = client.OPNClient('', '', '')
self.assertRaises(
exceptions.APIException, opnclient._post, 'fake_url', 'body')
opnclient = client.OPNClient("", "", "")
self.assertRaises(exceptions.APIException, opnclient._post, "fake_url", "body")
request_mock.assert_called_once_with(
'/fake_url', data='body', auth=('', ''), timeout=5, verify=False)
"/fake_url", data="body", auth=("", ""), timeout=5, verify=False
)
4 changes: 1 addition & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,4 @@
except ImportError:
pass

setuptools.setup(
setup_requires=['pbr'],
pbr=True)
setuptools.setup(setup_requires=["pbr"], pbr=True)
3 changes: 2 additions & 1 deletion test-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.

hacking>=0.11.0,<0.12 # Apache-2.0
hacking~=6.0
stestr>=1.1.0 # Apache-2.0
coverage>=3.6 # Apache-2.0
sphinx>1.6
mock>=2.0.0 # BSD
black~=23.0
11 changes: 9 additions & 2 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,13 @@ deps = -r{toxinidir}/requirements.txt
commands =
stestr run '{posargs}'

[testenv:black]
commands = black {posargs} pyopnsense setup.py

[testenv:pep8]
commands = flake8
commands =
black --check {posargs} pyopnsense setup.py
flake8

[testenv:venv]
commands = {posargs}
Expand All @@ -35,6 +40,8 @@ commands = python setup.py build_sphinx
[flake8]
# E123, E125 skipped as they are invalid PEP-8.
show-source = True
ignore = E123,E125
ignore = E123,E125,H405
extend-ignore = E203
max-line-length = 88
builtins = _
exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build

0 comments on commit 5d59535

Please sign in to comment.