From 6c9acf89599c045ecda0239cbed22ced37ff23c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sven=20Rue=C3=9F?= Date: Sun, 29 Dec 2024 07:54:22 +0000 Subject: [PATCH] feat: added Python 3.10 support and dev container for testing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sven Rueß --- .devcontainer/python_310/Dockerfile | 26 +++++++ .devcontainer/python_310/devcontainer.json | 30 ++++++++ .github/workflows/ci.yml | 1 + poetry.lock | 90 +++++++++++++++++++++- pyproject.toml | 2 +- ruff.toml | 2 +- src/aiovodafone/api.py | 19 +++-- 7 files changed, 156 insertions(+), 14 deletions(-) create mode 100644 .devcontainer/python_310/Dockerfile create mode 100644 .devcontainer/python_310/devcontainer.json diff --git a/.devcontainer/python_310/Dockerfile b/.devcontainer/python_310/Dockerfile new file mode 100644 index 0000000..df11b94 --- /dev/null +++ b/.devcontainer/python_310/Dockerfile @@ -0,0 +1,26 @@ +# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.177.0/containers/python-3/.devcontainer/base.Dockerfile + +# [Choice] Python version: 3, 3.9, 3.8, 3.7, 3.6 +ARG VARIANT="3.10" +FROM mcr.microsoft.com/vscode/devcontainers/python:1-${VARIANT} + +# [Option] Install Node.js +ARG INSTALL_NODE="true" +ARG NODE_VERSION="lts/*" +RUN if [ "${INSTALL_NODE}" = "true" ]; then su vscode -c "umask 0002 && . /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi + +# [Optional] If your pip requirements rarely change, uncomment this section to add them to the image. +RUN pip3 --disable-pip-version-check --no-cache-dir install pre-commit +RUN pip3 --disable-pip-version-check --no-cache-dir install poetry +RUN pip3 --disable-pip-version-check --no-cache-dir install aiohttp +RUN pip3 --disable-pip-version-check --no-cache-dir install bs4 + +# [Optional] Uncomment this section to install additional OS packages. +# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ +# && apt-get -y install --no-install-recommends + +# [Optional] Uncomment this line to install global node packages. +# RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g " 2>&1 + +# Set the default shell to bash instead of sh +ENV SHELL /bin/bash diff --git a/.devcontainer/python_310/devcontainer.json b/.devcontainer/python_310/devcontainer.json new file mode 100644 index 0000000..e43a71f --- /dev/null +++ b/.devcontainer/python_310/devcontainer.json @@ -0,0 +1,30 @@ +{ + "name": "Python 3.10", + "build": { + "dockerfile": "Dockerfile", + "context": "..", + "args": { + "VARIANT": "3.10", + "INSTALL_NODE": "true", + "NODE_VERSION": "lts/*" + } + }, + "customizations": { + "vscode": { + "settings": { + "terminal.integrated.shell.linux": "/bin/bash", + "python.pythonPath": "/usr/local/bin/python", + "python.languageServer": "Pylance", + "[python]": { + "editor.defaultFormatter": "charliermarsh.ruff" + } + }, + "extensions": [ + "ms-python.python", + "ms-python.vscode-pylance", + "charliermarsh.ruff" + ] + } + }, + "remoteUser": "vscode" +} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6e37b72..c1502ec 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,6 +40,7 @@ jobs: fail-fast: false matrix: python-version: + - "3.10" - "3.11" - "3.12" - "3.13" diff --git a/poetry.lock b/poetry.lock index fdb1029..738e5d8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -99,6 +99,7 @@ files = [ [package.dependencies] aiohappyeyeballs = ">=2.3.0" aiosignal = ">=1.1.2" +async-timeout = {version = ">=4.0,<6.0", markers = "python_version < \"3.11\""} attrs = ">=17.3.0" frozenlist = ">=1.1.1" multidict = ">=4.5,<7.0" @@ -122,6 +123,17 @@ files = [ [package.dependencies] frozenlist = ">=1.1.0" +[[package]] +name = "async-timeout" +version = "5.0.1" +description = "Timeout context manager for asyncio programs" +optional = false +python-versions = ">=3.8" +files = [ + {file = "async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c"}, + {file = "async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3"}, +] + [[package]] name = "attrs" version = "24.3.0" @@ -244,9 +256,26 @@ files = [ {file = "coverage-7.6.10.tar.gz", hash = "sha256:7fb105327c8f8f0682e29843e2ff96af9dcbe5bab8eeb4b398c6a33a16d80a23"}, ] +[package.dependencies] +tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} + [package.extras] toml = ["tomli"] +[[package]] +name = "exceptiongroup" +version = "1.2.2" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, + {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, +] + +[package.extras] +test = ["pytest (>=6)"] + [[package]] name = "frozenlist" version = "1.5.0" @@ -474,6 +503,9 @@ files = [ {file = "multidict-6.1.0.tar.gz", hash = "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a"}, ] +[package.dependencies] +typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.11\""} + [[package]] name = "packaging" version = "24.2" @@ -604,9 +636,11 @@ files = [ [package.dependencies] colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" packaging = "*" pluggy = ">=1.5,<2" +tomli = {version = ">=1", markers = "python_version < \"3.11\""} [package.extras] dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] @@ -640,6 +674,58 @@ files = [ {file = "soupsieve-2.6.tar.gz", hash = "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb"}, ] +[[package]] +name = "tomli" +version = "2.2.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.8" +files = [ + {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"}, + {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"}, + {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"}, + {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"}, + {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"}, + {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"}, + {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"}, + {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"}, + {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 = "yarl" version = "1.18.3" @@ -738,5 +824,5 @@ propcache = ">=0.2.0" [metadata] lock-version = "2.0" -python-versions = "^3.11" -content-hash = "c0af1144e6787bd1250cdb14c3a4918b1fd5d738725f50ed27db0970750e16e1" +python-versions = "^3.10" +content-hash = "75b3aaf92a6f5f6d004e1befcd99faea3e8de492fd6a58880c2397764d6cbdb8" diff --git a/pyproject.toml b/pyproject.toml index 744b5b7..0c49129 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,7 +22,7 @@ packages = [ "Changelog" = "https://github.com/chemelli74/aiovodafone/blob/main/CHANGELOG.md" [tool.poetry.dependencies] -python = "^3.11" +python = "^3.10" aiohttp = "*" beautifulsoup4 = "*" diff --git a/ruff.toml b/ruff.toml index 1fd5f94..16e66cd 100644 --- a/ruff.toml +++ b/ruff.toml @@ -1,4 +1,4 @@ -target-version = "py311" +target-version = "py310" lint.logger-objects = ["aiovodafone.const._LOGGER"] diff --git a/src/aiovodafone/api.py b/src/aiovodafone/api.py index 6062839..a3e8f86 100644 --- a/src/aiovodafone/api.py +++ b/src/aiovodafone/api.py @@ -7,7 +7,7 @@ import urllib.parse from abc import ABC, abstractmethod from dataclasses import dataclass -from datetime import UTC, datetime, timedelta +from datetime import datetime, timedelta, timezone from http import HTTPStatus from http.cookies import SimpleCookie from typing import Any, cast @@ -82,8 +82,8 @@ async def get_device_type( if "data" in response_json and "ModelName" in response_json["data"]: return DeviceType.TECHNICOLOR - for protocol in ["https", "http"]: - try: + try: + for protocol in ["https", "http"]: async with session.get( f"{protocol}://{host}/login.html", headers=HEADERS, @@ -97,9 +97,8 @@ async def get_device_type( and "var csrf_token = " in await response.text() ): return DeviceType.SERCOMM - except aiohttp.client_exceptions.ClientConnectorSSLError: - _LOGGER.debug("Unable to login using protocol %s", protocol) - continue + except aiohttp.client_exceptions.ClientConnectorSSLError: + _LOGGER.debug("Unable to login using protocol %s", protocol) return None @@ -143,7 +142,7 @@ async def _post_page_result( ) -> aiohttp.ClientResponse: """Get data from a web page via POST.""" _LOGGER.debug("POST page %s from host %s", page, self.host) - timestamp = int(datetime.now(tz=UTC).timestamp()) + timestamp = int(datetime.now(tz=timezone.utc).timestamp()) url = f"{self.base_url}{page}?_={timestamp}&csrf_token={self.csrf_token}" return await self.session.post( url, @@ -157,7 +156,7 @@ async def _post_page_result( async def _get_page_result(self, page: str) -> aiohttp.ClientResponse: """Get data from a web page via GET.""" _LOGGER.debug("GET page %s [%s]", page, self.host) - timestamp = int(datetime.now(tz=UTC).timestamp()) + timestamp = int(datetime.now(tz=timezone.utc).timestamp()) url = f"{self.base_url}{page}?_={timestamp}&csrf_token={self.csrf_token}" return await self.session.get( @@ -240,7 +239,7 @@ async def _encrypt_string( def convert_uptime(self, uptime: str) -> datetime: """Convert uptime to datetime.""" - return datetime.now(tz=UTC) - timedelta( + return datetime.now(tz=timezone.utc) - timedelta( seconds=int(uptime), ) @@ -578,7 +577,7 @@ def convert_uptime(self, uptime: str) -> datetime: h = int(uptime.split(":")[1]) m = int(uptime.split(":")[2]) - return datetime.now(tz=UTC) - timedelta( + return datetime.now(tz=timezone.utc) - timedelta( days=d, hours=h, minutes=m,