From c3d4a165f7ce4d6b18b1ea5737a360d18866a660 Mon Sep 17 00:00:00 2001 From: Ben Einaudi Date: Sun, 5 Jan 2025 13:25:57 +0100 Subject: [PATCH] feature(code) add linter --- .flake8 | 7 + .github/workflows/pythonpackage.yml | 3 + oauth2_client/credentials_manager.py | 7 +- oauth2_client/http_server.py | 21 ++- poetry.lock | 160 +++++++++++++++++- pyproject.toml | 5 + .../test_credential_manager.py | 10 +- tests/oauth2_client_tests/test_http_server.py | 2 +- 8 files changed, 198 insertions(+), 17 deletions(-) create mode 100644 .flake8 diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..e4f8eaf --- /dev/null +++ b/.flake8 @@ -0,0 +1,7 @@ +[flake8] +ignore = E203, W503 +max-line-length = 130 +max-complexity = 16 +buildins = OAuth2Client +exclude = .git,.github,.venv,.eggs,build + diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 245d82c..6ff7ad9 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -36,3 +36,6 @@ jobs: - name: Launch tests run: poetry run pytest + + - name: Launch Linting + run: poetry run flake8 --show-source --statistics \ No newline at end of file diff --git a/oauth2_client/credentials_manager.py b/oauth2_client/credentials_manager.py index bd5a195..583676c 100644 --- a/oauth2_client/credentials_manager.py +++ b/oauth2_client/credentials_manager.py @@ -1,4 +1,4 @@ -import base64 +from base64 import b64encode import logging from http import HTTPStatus from threading import Event @@ -38,8 +38,7 @@ def __init__(self, authorize_service: Optional[str], @property def authorization_header(self): - return 'Basic %s' % base64.b64encode(bytes('%s:%s' % (self.client_id, self.client_secret), 'UTF-8'))\ - .decode('UTF-8') + return f"Basic {b64encode(bytes('%s:%s' % (self.client_id, self.client_secret), 'UTF-8')).decode('UTF-8')}" @property def public_api(self): @@ -86,7 +85,7 @@ def _handle_bad_response(response: Response): error = response.json() raise OAuthError(HTTPStatus(response.status_code), error.get('error'), error.get('error_description')) except BaseException as ex: - if type(ex) != OAuthError: + if not isinstance(ex, OAuthError): _logger.exception( '_handle_bad_response - error while getting error as json - %s - %s' % (type(ex), str(ex))) raise OAuthError(HTTPStatus(response.status_code), 'unknown_error', response.text) diff --git a/oauth2_client/http_server.py b/oauth2_client/http_server.py index faba5bf..2ba0e50 100644 --- a/oauth2_client/http_server.py +++ b/oauth2_client/http_server.py @@ -4,14 +4,18 @@ from http import HTTPStatus from http.server import BaseHTTPRequestHandler from socketserver import TCPServer -from typing import Callable, Any, Type, Optional +from typing import Callable, Optional, Any +try: + from typing import Self +except ImportError: # before python 3.11 + from typing_extensions import Self from urllib.parse import unquote _logger = logging.getLogger(__name__) class _ReuseAddressTcpServer(TCPServer): - def __init__(self, host: str, port: int, handler_class: Type[BaseHTTPRequestHandler]): + def __init__(self, host: str, port: int, handler_class: Callable[[Any, Any, Self], BaseHTTPRequestHandler]): self.allow_reuse_address = True TCPServer.__init__(self, (host, port), handler_class) @@ -32,11 +36,12 @@ class Handler(BaseHTTPRequestHandler): def do_GET(self): _logger.debug('GET - %s' % self.path) params_received = read_request_parameters(self.path) - response = 'Response received (%s). Result was transmitted to the original thread. You can close this window.' % json.dumps( - params_received) + response = (f"Response received ({json.dumps(params_received)})." + " Result was transmitted to the original thread. You can close this window." + ) self.send_response(HTTPStatus.OK.value, 'OK') self.send_header("Content-type", 'text/plain') - self.send_header("Content-Length", len(response)) + self.send_header("Content-Length", str(len(response))) self.end_headers() try: self.wfile.write(bytes(response, 'UTF-8')) @@ -46,7 +51,11 @@ def do_GET(self): self.wfile.flush() _logger.debug('start_http_server - instantiating server to listen on "%s:%d"', host, port) - httpd = _ReuseAddressTcpServer(host, port, Handler) + httpd = _ReuseAddressTcpServer( + host, + port, + lambda request, client_address, server: Handler(request, client_address, server) + ) def serve(): _logger.debug('server daemon - starting server') diff --git a/poetry.lock b/poetry.lock index 0763907..d00b16a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,5 +1,51 @@ # This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand. +[[package]] +name = "black" +version = "24.10.0" +description = "The uncompromising code formatter." +optional = false +python-versions = ">=3.9" +files = [ + {file = "black-24.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6668650ea4b685440857138e5fe40cde4d652633b1bdffc62933d0db4ed9812"}, + {file = "black-24.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1c536fcf674217e87b8cc3657b81809d3c085d7bf3ef262ead700da345bfa6ea"}, + {file = "black-24.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:649fff99a20bd06c6f727d2a27f401331dc0cc861fb69cde910fe95b01b5928f"}, + {file = "black-24.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:fe4d6476887de70546212c99ac9bd803d90b42fc4767f058a0baa895013fbb3e"}, + {file = "black-24.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5a2221696a8224e335c28816a9d331a6c2ae15a2ee34ec857dcf3e45dbfa99ad"}, + {file = "black-24.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f9da3333530dbcecc1be13e69c250ed8dfa67f43c4005fb537bb426e19200d50"}, + {file = "black-24.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4007b1393d902b48b36958a216c20c4482f601569d19ed1df294a496eb366392"}, + {file = "black-24.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:394d4ddc64782e51153eadcaaca95144ac4c35e27ef9b0a42e121ae7e57a9175"}, + {file = "black-24.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e39e0fae001df40f95bd8cc36b9165c5e2ea88900167bddf258bacef9bbdc3"}, + {file = "black-24.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d37d422772111794b26757c5b55a3eade028aa3fde43121ab7b673d050949d65"}, + {file = "black-24.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:14b3502784f09ce2443830e3133dacf2c0110d45191ed470ecb04d0f5f6fcb0f"}, + {file = "black-24.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:30d2c30dc5139211dda799758559d1b049f7f14c580c409d6ad925b74a4208a8"}, + {file = "black-24.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981"}, + {file = "black-24.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b"}, + {file = "black-24.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2"}, + {file = "black-24.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b"}, + {file = "black-24.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:17374989640fbca88b6a448129cd1745c5eb8d9547b464f281b251dd00155ccd"}, + {file = "black-24.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:63f626344343083322233f175aaf372d326de8436f5928c042639a4afbbf1d3f"}, + {file = "black-24.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfa1d0cb6200857f1923b602f978386a3a2758a65b52e0950299ea014be6800"}, + {file = "black-24.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:2cd9c95431d94adc56600710f8813ee27eea544dd118d45896bb734e9d7a0dc7"}, + {file = "black-24.10.0-py3-none-any.whl", hash = "sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d"}, + {file = "black-24.10.0.tar.gz", hash = "sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875"}, +] + +[package.dependencies] +click = ">=8.0.0" +mypy-extensions = ">=0.4.3" +packaging = ">=22.0" +pathspec = ">=0.9.0" +platformdirs = ">=2" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.10)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +uvloop = ["uvloop (>=0.15.2)"] + [[package]] name = "certifi" version = "2024.12.14" @@ -112,6 +158,20 @@ files = [ {file = "charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3"}, ] +[[package]] +name = "click" +version = "8.1.8" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, + {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + [[package]] name = "colorama" version = "0.4.6" @@ -137,6 +197,22 @@ files = [ [package.extras] test = ["pytest (>=6)"] +[[package]] +name = "flake8" +version = "7.1.1" +description = "the modular source code checker: pep8 pyflakes and co" +optional = false +python-versions = ">=3.8.1" +files = [ + {file = "flake8-7.1.1-py2.py3-none-any.whl", hash = "sha256:597477df7860daa5aa0fdd84bf5208a043ab96b8e96ab708770ae0364dd03213"}, + {file = "flake8-7.1.1.tar.gz", hash = "sha256:049d058491e228e03e67b390f311bbf88fce2dbaa8fa673e7aea87b7198b8d38"}, +] + +[package.dependencies] +mccabe = ">=0.7.0,<0.8.0" +pycodestyle = ">=2.12.0,<2.13.0" +pyflakes = ">=3.2.0,<3.3.0" + [[package]] name = "idna" version = "3.10" @@ -162,6 +238,28 @@ files = [ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] +[[package]] +name = "mccabe" +version = "0.7.0" +description = "McCabe checker, plugin for flake8" +optional = false +python-versions = ">=3.6" +files = [ + {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, + {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, +] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + [[package]] name = "packaging" version = "24.2" @@ -173,6 +271,33 @@ files = [ {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, ] +[[package]] +name = "pathspec" +version = "0.12.1" +description = "Utility library for gitignore style pattern matching of file paths." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, +] + +[[package]] +name = "platformdirs" +version = "4.3.6" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +optional = false +python-versions = ">=3.8" +files = [ + {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, + {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, +] + +[package.extras] +docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] +type = ["mypy (>=1.11.2)"] + [[package]] name = "pluggy" version = "1.5.0" @@ -188,6 +313,28 @@ files = [ dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] +[[package]] +name = "pycodestyle" +version = "2.12.1" +description = "Python style guide checker" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pycodestyle-2.12.1-py2.py3-none-any.whl", hash = "sha256:46f0fb92069a7c28ab7bb558f05bfc0110dac69a0cd23c61ea0040283a9d78b3"}, + {file = "pycodestyle-2.12.1.tar.gz", hash = "sha256:6838eae08bbce4f6accd5d5572075c63626a15ee3e6f842df996bf62f6d73521"}, +] + +[[package]] +name = "pyflakes" +version = "3.2.0" +description = "passive checker of Python programs" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pyflakes-3.2.0-py2.py3-none-any.whl", hash = "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a"}, + {file = "pyflakes-3.2.0.tar.gz", hash = "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f"}, +] + [[package]] name = "pytest" version = "8.2.2" @@ -272,6 +419,17 @@ files = [ {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"}, ] +[[package]] +name = "typing-extensions" +version = "4.12.2" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, +] + [[package]] name = "urllib3" version = "2.3.0" @@ -292,4 +450,4 @@ zstd = ["zstandard (>=0.18.0)"] [metadata] lock-version = "2.0" python-versions = ">=3.9" -content-hash = "cdad2388c31f92b4cc2a6e1ab81bd055912d2520bccd4c7c7629848a66b1c2f8" +content-hash = "d1c55f99626350168af5b43a630614eb31937223a1e90aa32d08a6c103902d0e" diff --git a/pyproject.toml b/pyproject.toml index 3710e1f..d788e50 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,6 @@ +[tool.black] +line-length = 130 + [tool.poetry] name = "oauth2-client" version = "1.4.2" @@ -14,6 +17,8 @@ python = ">=3.9" requests = ">=2.5.0" [tool.poetry.group.dev.dependencies] +black= "24.10.0" +flake8= "7.1.1" pytest = "~8.2.2" [tool.pytest.ini_options] diff --git a/tests/oauth2_client_tests/test_credential_manager.py b/tests/oauth2_client_tests/test_credential_manager.py index c8fad61..dccecc3 100644 --- a/tests/oauth2_client_tests/test_credential_manager.py +++ b/tests/oauth2_client_tests/test_credential_manager.py @@ -84,7 +84,7 @@ def _handle_post(self, parameters): self.end_headers() -class TestServer(object): +class MockTestServer(object): def __init__(self, port, handler_class): self.httpd = _ReuseAddressTcpServer('', port, handler_class) @@ -112,7 +112,7 @@ def _check_get_parameters(self, parameters): test_case.assertEqual(parameters.get('state', None), 'state_test') test_case.assertEqual(parameters.get('client_id', None), 'client_id_test') test_case.assertEqual(parameters.get('scope', None), 'scope1 scope2') - with TestServer(authorize_server_port, CheckAuthorizeHandler): + with MockTestServer(authorize_server_port, CheckAuthorizeHandler): manager = None try: manager = CredentialManager(service_information, proxies=dict(http='')) @@ -137,7 +137,7 @@ def _check_get_parameters(self, parameters): # send bad state parameters['state'] = 'other_state' - with TestServer(authorize_server_port, CheckAuthorizeHandlerbadState): + with MockTestServer(authorize_server_port, CheckAuthorizeHandlerbadState): manager = None try: manager = CredentialManager(service_information, proxies=dict(http='')) @@ -232,7 +232,7 @@ def _handle_request(self): self.end_headers() self.wfile.write(bytes(body, 'UTF-8')) - with TestServer(api_server_port, BearerHandler): + with MockTestServer(api_server_port, BearerHandler): _logger.debug('test_get_token_with_code - server started') api_url = 'http://localhost:%d/api/uri' % api_server_port manager = CredentialManager(service_information, proxies=dict(http='')) @@ -278,7 +278,7 @@ def _handle_post(self, parameters): self.send_header("Content-Length", 0) self.end_headers() - with TestServer(token_server_port, CheckGetTokenWithCode): + with MockTestServer(token_server_port, CheckGetTokenWithCode): manager = CredentialManager(service_information, proxies=dict(http='')) call_request(manager) if not no_refresh_token: diff --git a/tests/oauth2_client_tests/test_http_server.py b/tests/oauth2_client_tests/test_http_server.py index fbc4a6b..b6989f9 100644 --- a/tests/oauth2_client_tests/test_http_server.py +++ b/tests/oauth2_client_tests/test_http_server.py @@ -65,7 +65,7 @@ def _extract_response(text): if idx_start >= 0: idx_end = text.find('}', idx_start) if idx_end >= 0: - return json.loads(text[idx_start: idx_end+1]) + return json.loads(text[idx_start: idx_end + 1]) else: return dict() else: