From 42f0083546f3a0781a0ba04b02ba0c3c6bac608f Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Sun, 1 Nov 2020 22:08:11 +0100 Subject: [PATCH 01/18] Add known API keys --- src/renault_api/const.py | 182 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 src/renault_api/const.py diff --git a/src/renault_api/const.py b/src/renault_api/const.py new file mode 100644 index 00000000..a7de4c23 --- /dev/null +++ b/src/renault_api/const.py @@ -0,0 +1,182 @@ +"""Constants for Renault API.""" +CONF_GIGYA_APIKEY = "gigya-api-key" +CONF_GIGYA_URL = "gigya-api-url" +CONF_KAMEREON_APIKEY = "kamereon-api-key" +CONF_KAMEREON_URL = "kamereon-api-url" + +AVAILABLE_LOCALES = { + "bg_BG": { + CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_APIKEY: "3__3ER_6lFvXEXHTP_faLtq6eEdbKDXd9F5GoKwzRyZq37ZQ-db7mXcLzR1Jtls5sn", # noqa + CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", + CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + }, + "cs_CZ": { + CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_APIKEY: "3_oRlKr5PCVL_sPWUZdJ8c5NOl5Ej8nIZw7VKG7S9Rg36UkDszFzfHfxCaUAUU5or2", # noqa + CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", + CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + }, + "da_DK": { + CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_APIKEY: "3_5x-2C8b1R4MJPQXkwTPdIqgBpcw653Dakw_ZaEneQRkTBdg9UW9Qg_5G-tMNrTMc", # noqa + CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", + CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + }, + "de_DE": { + CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_APIKEY: "3_7PLksOyBRkHv126x5WhHb-5pqC1qFR8pQjxSeLB6nhAnPERTUlwnYoznHSxwX668", # noqa + CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", + CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + }, + "de_AT": { + CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_APIKEY: "3__B4KghyeUb0GlpU62ZXKrjSfb7CPzwBS368wioftJUL5qXE0Z_sSy0rX69klXuHy", # noqa + CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", + CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + }, + "de_CH": { + CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_APIKEY: "3_UyiWZs_1UXYCUqK_1n7l7l44UiI_9N9hqwtREV0-UYA_5X7tOV-VKvnGxPBww4q2", # noqa + CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", + CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + }, + "en_GB": { + CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_APIKEY: "3_e8d4g4SE_Fo8ahyHwwP7ohLGZ79HKNN2T8NjQqoNnk6Epj6ilyYwKdHUyCw3wuxz", # noqa + CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", + CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + }, + "en_IE": { + CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_APIKEY: "3_Xn7tuOnT9raLEXuwSI1_sFFZNEJhSD0lv3gxkwFtGI-RY4AgiePBiJ9EODh8d9yo", # noqa + CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", + CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + }, + "es_ES": { + CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_APIKEY: "3_DyMiOwEaxLcPdBTu63Gv3hlhvLaLbW3ufvjHLeuU8U5bx3zx19t5rEKq7KMwk9f1", # noqa + CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", + CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + }, + "es_MX": { + CONF_GIGYA_URL: "https://accounts.us1.gigya.com", + CONF_GIGYA_APIKEY: "3_BFzR-2wfhMhUs5OCy3R8U8IiQcHS-81vF8bteSe8eFrboMTjEWzbf4pY1aHQ7cW0", # noqa + CONF_KAMEREON_URL: "https://api-wired-prod-1-usw2.wrd-aws.com", + CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + }, + "fi_FI": { + CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_APIKEY: "3_xSRCLDYhk1SwSeYQLI3DmA8t-etfAfu5un51fws125ANOBZHgh8Lcc4ReWSwaqNY", # noqa + CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", + CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + }, + "fr_FR": { + CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_APIKEY: "3_4LKbCcMMcvjDm3X89LU4z4mNKYKdl_W0oD9w-Jvih21WqgJKtFZAnb9YdUgWT9_a", # noqa + CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", + CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + }, + "fr_BE": { + CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_APIKEY: "3_ZK9x38N8pzEvdiG7ojWHeOAAej43APkeJ5Av6VbTkeoOWR4sdkRc-wyF72HzUB8X", # noqa + CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", + CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + }, + "fr_CH": { + CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_APIKEY: "3_h3LOcrKZ9mTXxMI9clb2R1VGAWPke6jMNqMw4yYLz4N7PGjYyD0hqRgIFAIHusSn", # noqa + CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", + CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + }, + "fr_LU": { + CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_APIKEY: "3_zt44Wl_wT9mnqn-BHrR19PvXj3wYRPQKLcPbGWawlatFR837KdxSZZStbBTDaqnb", # noqa + CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", + CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + }, + "hr_HR": { + CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_APIKEY: "3_HcDC5GGZ89NMP1jORLhYNNCcXt7M3thhZ85eGrcQaM2pRwrgrzcIRWEYi_36cFj9", # noqa + CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", + CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + }, + "hu_HU": { + CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_APIKEY: "3_nGDWrkSGZovhnVFv5hdIxyuuCuJGZfNmlRGp7-5kEn9yb0bfIfJqoDa2opHOd3Mu", # noqa + CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", + CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + }, + "it_IT": { + CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_APIKEY: "3_js8th3jdmCWV86fKR3SXQWvXGKbHoWFv8NAgRbH7FnIBsi_XvCpN_rtLcI07uNuq", # noqa + CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", + CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + }, + "it_CH": { + CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_APIKEY: "3_gHkmHaGACxSLKXqD_uDDx415zdTw7w8HXAFyvh0qIP0WxnHPMF2B9K_nREJVSkGq", # noqa + CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", + CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + }, + "nl_NL": { + CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_APIKEY: "3_ZIOtjqmP0zaHdEnPK7h1xPuBYgtcOyUxbsTY8Gw31Fzy7i7Ltjfm-hhPh23fpHT5", # noqa + CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", + CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + }, + "nl_BE": { + CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_APIKEY: "3_yachztWczt6i1pIMhLIH9UA6DXK6vXXuCDmcsoA4PYR0g35RvLPDbp49YribFdpC", # noqa + CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", + CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + }, + "no_NO": { + CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_APIKEY: "3_QrPkEJr69l7rHkdCVls0owC80BB4CGz5xw_b0gBSNdn3pL04wzMBkcwtbeKdl1g9", # noqa + CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", + CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + }, + "pl_PL": { + CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_APIKEY: "3_2YBjydYRd1shr6bsZdrvA9z7owvSg3W5RHDYDp6AlatXw9hqx7nVoanRn8YGsBN8", # noqa + CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", + CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + }, + "pt_PT": { + CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_APIKEY: "3__afxovspi2-Ip1E5kNsAgc4_35lpLAKCF6bq4_xXj2I2bFPjIWxAOAQJlIkreKTD", # noqa + CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", + CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + }, + "ro_RO": { + CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_APIKEY: "3_WlBp06vVHuHZhiDLIehF8gchqbfegDJADPQ2MtEsrc8dWVuESf2JCITRo5I2CIxs", # noqa + CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", + CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + }, + "ru_RU": { + CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_APIKEY: "3_N_ecy4iDyoRtX8v5xOxewwZLKXBjRgrEIv85XxI0KJk8AAdYhJIi17LWb086tGXR", # noqa + CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", + CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + }, + "sk_SK": { + CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_APIKEY: "3_e8d4g4SE_Fo8ahyHwwP7ohLGZ79HKNN2T8NjQqoNnk6Epj6ilyYwKdHUyCw3wuxz", # noqa + CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", + CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + }, + "sl_SI": { + CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_APIKEY: "3_QKt0ADYxIhgcje4F3fj9oVidHsx3JIIk-GThhdyMMQi8AJR0QoHdA62YArVjbZCt", # noqa + CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", + CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + }, + "sv_SE": { + CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_APIKEY: "3_EN5Hcnwanu9_Dqot1v1Aky1YelT5QqG4TxveO0EgKFWZYu03WkeB9FKuKKIWUXIS", # noqa + CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", + CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + }, +} From dddc68d85a35c9f17b73a028ed7a464e52fa7ce7 Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Sun, 1 Nov 2020 22:19:34 +0100 Subject: [PATCH 02/18] Add base exception --- src/renault_api/exceptions.py | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/renault_api/exceptions.py diff --git a/src/renault_api/exceptions.py b/src/renault_api/exceptions.py new file mode 100644 index 00000000..77ebcfe6 --- /dev/null +++ b/src/renault_api/exceptions.py @@ -0,0 +1,7 @@ +"""Exceptions for Renault API.""" + + +class RenaultError(Exception): + """Base class for Renault API errors.""" + + pass From fe5f569276e2623a0a8c815aeeab039f81a0c148 Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Sun, 1 Nov 2020 22:20:25 +0100 Subject: [PATCH 03/18] Add RenaultClient --- pyproject.toml | 2 ++ src/renault_api/client.py | 70 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 src/renault_api/client.py diff --git a/pyproject.toml b/pyproject.toml index 8ff581dc..96ceb0cd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,6 +21,8 @@ Changelog = "https://github.com/hacf-fr/renault-api/releases" [tool.poetry.dependencies] python = "^3.7.1" click = "^7.0" +aiohttp = "^3.7.2" +typing-extensions = "^3.7.4" [tool.poetry.dev-dependencies] pytest = "^6.1.2" diff --git a/src/renault_api/client.py b/src/renault_api/client.py new file mode 100644 index 00000000..cbb7e45f --- /dev/null +++ b/src/renault_api/client.py @@ -0,0 +1,70 @@ +"""Client for Renault API.""" +import logging +from typing import Dict +from typing import Optional + +import aiohttp +from aiohttp.client_exceptions import ClientResponseError + +from .const import AVAILABLE_LOCALES +from .const import CONF_GIGYA_APIKEY +from .const import CONF_GIGYA_URL +from .const import CONF_KAMEREON_APIKEY +from .const import CONF_KAMEREON_URL +from .exceptions import RenaultError + +_LOGGER = logging.getLogger(__package__) + + +class RenaultClient: + """Proxy to the Renault API.""" + + def __init__(self) -> None: + """Initialise Renault Client.""" + self.aiohttp_session: Optional[aiohttp.ClientSession] = None + + async def preload_api_keys(self, locale: str) -> Dict[str, str]: + """Load the credential store with API Keys. + + Args: + locale (str): locale code (preferrably from AVAILABLE_LOCALES.keys()). + + Returns: + Dict with gigya-api-key, gigya-api-url, + kamereon-api-key and kamereon-api-url + + Raises: + RenaultError: an issue occured loading the API keys + """ + if locale in AVAILABLE_LOCALES.keys(): + return AVAILABLE_LOCALES[locale] + else: + _LOGGER.warning( + "Locale %s was not found in AVAILABLE_LOCALES. " + "Attempting to load details from Renault servers.", + locale, + ) + if self.aiohttp_session is None: + raise RenaultError("aiohttp_session is not set.") + + url = f"https://renault-wrd-prod-1-euw1-myrapp-one.s3-eu-west-1.amazonaws.com/configuration/android/config_{locale}.json" # noqa + async with self.aiohttp_session.get(url) as response: + try: + response.raise_for_status() + except ClientResponseError as exc: + raise RenaultError( + f"Locale not found on Renault server ({exc.status})." + ) from exc + response_body = await response.json(content_type=None) + + _LOGGER.debug( + "Received api keys from myrenault response: %s", response_body + ) + + servers = response_body["servers"] + return { + CONF_GIGYA_APIKEY: servers["gigyaProd"]["apikey"], + CONF_GIGYA_URL: servers["gigyaProd"]["target"], + CONF_KAMEREON_APIKEY: servers["wiredProd"]["apikey"], + CONF_KAMEREON_URL: servers["wiredProd"]["target"], + } From dda2f31744289d8bdbfdc213b62224ae2df65c7e Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Sun, 1 Nov 2020 23:24:44 +0100 Subject: [PATCH 04/18] Add tests for API keys --- noxfile.py | 8 +- poetry.lock | 218 +++++++++++++++++++++--- pyproject.toml | 2 + tests/fixtures/config_sample.txt | 283 +++++++++++++++++++++++++++++++ tests/test_api_keys.py | 85 ++++++++++ 5 files changed, 573 insertions(+), 23 deletions(-) create mode 100644 tests/fixtures/config_sample.txt create mode 100644 tests/test_api_keys.py diff --git a/noxfile.py b/noxfile.py index 17945e1e..d0bc0397 100644 --- a/noxfile.py +++ b/noxfile.py @@ -108,7 +108,7 @@ def mypy(session: Session) -> None: """Type-check using mypy.""" args = session.posargs or ["src", "tests", "docs/conf.py"] session.install(".") - session.install("mypy", "pytest") + session.install("mypy", "pytest", "pytest-asyncio", "aioresponses") session.run("mypy", *args) if not session.posargs: session.run("mypy", f"--python-executable={sys.executable}", "noxfile.py") @@ -118,7 +118,9 @@ def mypy(session: Session) -> None: def tests(session: Session) -> None: """Run the test suite.""" session.install(".") - session.install("coverage[toml]", "pytest", "pygments") + session.install( + "coverage[toml]", "pytest", "pygments", "pytest-asyncio", "aioresponses" + ) try: session.run("coverage", "run", "--parallel", "-m", "pytest", *session.posargs) finally: @@ -145,7 +147,7 @@ def coverage(session: Session) -> None: def typeguard(session: Session) -> None: """Runtime type checking using Typeguard.""" session.install(".") - session.install("pytest", "typeguard", "pygments") + session.install("pytest", "typeguard", "pygments", "pytest-asyncio", "aioresponses") session.run("pytest", f"--typeguard-packages={package}", *session.posargs) diff --git a/poetry.lock b/poetry.lock index 12b696a0..5864b710 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,3 +1,33 @@ +[[package]] +name = "aiohttp" +version = "3.7.2" +description = "Async http client/server framework (asyncio)" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +async-timeout = ">=3.0,<4.0" +attrs = ">=17.3.0" +chardet = ">=2.0,<4.0" +multidict = ">=4.5,<7.0" +typing-extensions = ">=3.6.5" +yarl = ">=1.0,<2.0" + +[package.extras] +speedups = ["aiodns", "brotlipy", "cchardet"] + +[[package]] +name = "aioresponses" +version = "0.7.1" +description = "Mock out requests made by ClientSession from aiohttp package" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +aiohttp = ">=2.0.0,<4.0.0" + [[package]] name = "alabaster" version = "0.7.12" @@ -25,6 +55,14 @@ python-versions = ">=3.6.1" [package.dependencies] cached-property = "*" +[[package]] +name = "async-timeout" +version = "3.0.1" +description = "Timeout context manager for asyncio programs" +category = "main" +optional = false +python-versions = ">=3.5.3" + [[package]] name = "atomicwrites" version = "1.4.0" @@ -37,7 +75,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" name = "attrs" version = "20.2.0" description = "Classes Without Boilerplate" -category = "dev" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" @@ -123,7 +161,7 @@ python-versions = ">=3.6.1" name = "chardet" version = "3.0.4" description = "Universal encoding detector for Python 2 and 3" -category = "dev" +category = "main" optional = false python-versions = "*" @@ -317,7 +355,7 @@ license = ["editdistance"] name = "idna" version = "2.10" description = "Internationalized Domain Names in Applications (IDNA)" -category = "dev" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" @@ -394,6 +432,14 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "multidict" +version = "5.0.0" +description = "multidict implementation" +category = "main" +optional = false +python-versions = ">=3.5" + [[package]] name = "mypy" version = "0.790" @@ -582,9 +628,23 @@ toml = "*" checkqa_mypy = ["mypy (==0.780)"] testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] +[[package]] +name = "pytest-asyncio" +version = "0.14.0" +description = "Pytest support for asyncio." +category = "dev" +optional = false +python-versions = ">= 3.5" + +[package.dependencies] +pytest = ">=5.4.0" + +[package.extras] +testing = ["async-generator (>=1.3)", "coverage", "hypothesis (>=5.7.1)"] + [[package]] name = "pytz" -version = "2020.1" +version = "2020.4" description = "World timezone definitions, modern and historical" category = "dev" optional = false @@ -902,7 +962,7 @@ test = ["pytest", "typing-extensions"] name = "typing-extensions" version = "3.7.4.3" description = "Backported and Experimental Type Hints for Python 3.5+" -category = "dev" +category = "main" optional = false python-versions = "*" @@ -958,6 +1018,19 @@ jupyter = ["nbformat", "nbconvert", "jupyter-client", "ipython", "ipykernel"] optional = ["pygments", "colorama", "nbformat", "nbconvert", "jupyter-client", "ipython", "ipykernel"] tests = ["pytest", "pytest-cov", "codecov", "scikit-build", "cmake", "ninja", "pybind11", "nbformat", "nbconvert", "jupyter-client", "ipython", "ipykernel"] +[[package]] +name = "yarl" +version = "1.6.2" +description = "Yet another URL library" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +idna = ">=2.0" +multidict = ">=4.0" +typing-extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""} + [[package]] name = "zipp" version = "3.4.0" @@ -973,9 +1046,48 @@ testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake [metadata] lock-version = "1.1" python-versions = "^3.7.1" -content-hash = "9bc0706c1e703f96075f4a92bf1f7ad256775ee75fe1785864b4f7d2e89d4bcd" +content-hash = "95d167fa6a2b7e92155f9b1efd60ac26afb7aa7320593b9856c5894d94fd4524" [metadata.files] +aiohttp = [ + {file = "aiohttp-3.7.2-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:0989ff15834a4503056d103077ec3652f9ea5699835e1ceaee46b91cf59830bf"}, + {file = "aiohttp-3.7.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:8fbeeb2296bb9fe16071a674eadade7391be785ae0049610e64b60ead6abcdd7"}, + {file = "aiohttp-3.7.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:48104c883099c0e614c5c38f98c1d174a2c68f52f58b2a6e5a07b59df78262ab"}, + {file = "aiohttp-3.7.2-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:c9a415f4f2764ab6c7d63ee6b86f02a46b4df9bc11b0de7ffef206908b7bf0b4"}, + {file = "aiohttp-3.7.2-cp36-cp36m-manylinux2014_ppc64le.whl", hash = "sha256:7e26712871ebaf55497a60f55483dc5e74326d1fb0bfceab86ebaeaa3a266733"}, + {file = "aiohttp-3.7.2-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:8319a55de469d5af3517dfe1f6a77f248f6668c5a552396635ef900f058882ef"}, + {file = "aiohttp-3.7.2-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:2aea79734ac5ceeac1ec22b4af4efb4efd6a5ca3d73d77ec74ed782cf318f238"}, + {file = "aiohttp-3.7.2-cp36-cp36m-win_amd64.whl", hash = "sha256:be9fa3fe94fc95e9bf84e84117a577c892906dd3cb0a95a7ae21e12a84777567"}, + {file = "aiohttp-3.7.2-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:f04dcbf6af1868048a9b4754b1684c669252aa2419aa67266efbcaaead42ced7"}, + {file = "aiohttp-3.7.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:2e886611b100c8c93b753b457e645c5e4b8008ec443434d2a480e5a2bb3e6514"}, + {file = "aiohttp-3.7.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:cdbb65c361ff790c424365a83a496fc8dd1983689a5fb7c6852a9a3ff1710c61"}, + {file = "aiohttp-3.7.2-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:8a8addd41320637c1445fea0bae1fd9fe4888acc2cd79217ee33e5d1c83cfe01"}, + {file = "aiohttp-3.7.2-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:b822bf7b764283b5015e3c49b7bb93f37fc03545f4abe26383771c6b1c813436"}, + {file = "aiohttp-3.7.2-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:ad5c3559e3cd64f746df43fa498038c91aa14f5d7615941ea5b106e435f3b892"}, + {file = "aiohttp-3.7.2-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:835bd35e14e4f36414e47c195e6645449a0a1c3fd5eeae4b7f22cb4c5e4f503a"}, + {file = "aiohttp-3.7.2-cp37-cp37m-win_amd64.whl", hash = "sha256:11e087c316e933f1f52f3d4a09ce13f15ad966fc43df47f44ca4e8067b6a2e0d"}, + {file = "aiohttp-3.7.2-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:f8c583c31c6e790dc003d9d574e3ed2c5b337947722965096c4d684e4f183570"}, + {file = "aiohttp-3.7.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:b84cef790cb93cec82a468b7d2447bf16e3056d2237b652e80f57d653b61da88"}, + {file = "aiohttp-3.7.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:4afd8002d9238e5e93acf1a8baa38b3ddf1f7f0ebef174374131ff0c6c2d7973"}, + {file = "aiohttp-3.7.2-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:a1f1cc11c9856bfa7f1ca55002c39070bde2a97ce48ef631468e99e2ac8e3fe6"}, + {file = "aiohttp-3.7.2-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:7f1aeb72f14b9254296cdefa029c00d3c4550a26e1059084f2ee10d22086c2d0"}, + {file = "aiohttp-3.7.2-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:67f8564c534d75c1d613186939cee45a124d7d37e7aece83b17d18af665b0d7a"}, + {file = "aiohttp-3.7.2-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:184ead67248274f0e20b0cd6bb5f25209b2fad56e5373101cc0137c32c825c87"}, + {file = "aiohttp-3.7.2-cp38-cp38-win_amd64.whl", hash = "sha256:6e0d1231a626d07b23f6fe904caa44efb249da4222d8a16ab039fb2348722292"}, + {file = "aiohttp-3.7.2-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:476b1f8216e59a3c2ffb71b8d7e1da60304da19f6000d422bacc371abb0fc43d"}, + {file = "aiohttp-3.7.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:89c1aa729953b5ac6ca3c82dcbd83e7cdecfa5cf9792c78c154a642e6e29303d"}, + {file = "aiohttp-3.7.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:c53f1d2bd48f5f407b534732f5b3c6b800a58e70b53808637848d8a9ee127fe7"}, + {file = "aiohttp-3.7.2-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:06efdb01ab71ec20786b592d510d1d354fbe0b2e4449ee47067b9ca65d45a006"}, + {file = "aiohttp-3.7.2-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:027be45c4b37e21be81d07ae5242361d73eebad1562c033f80032f955f34df82"}, + {file = "aiohttp-3.7.2-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:1c36b7ef47cfbc150314c2204cd73613d96d6d0982d41c7679b7cdcf43c0e979"}, + {file = "aiohttp-3.7.2-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:c588a0f824dc7158be9eec1ff465d1c868ad69a4dc518cd098cc11e4f7da09d9"}, + {file = "aiohttp-3.7.2-cp39-cp39-win_amd64.whl", hash = "sha256:547b196a7177511da4f475fc81d0bb88a51a8d535c7444bbf2338b6dc82cb996"}, + {file = "aiohttp-3.7.2.tar.gz", hash = "sha256:c6da1af59841e6d43255d386a2c4bfb59c0a3b262bdb24325cc969d211be6070"}, +] +aioresponses = [ + {file = "aioresponses-0.7.1-py2.py3-none-any.whl", hash = "sha256:88eeb32256ef0af57450647277d3118ce8005682f06f27b23c5e2f8fcc0384b9"}, + {file = "aioresponses-0.7.1.tar.gz", hash = "sha256:f65bba2be1e9a4997ee166bc0161a50be0fef7350ad09e6afdb2adccf74dfefe"}, +] alabaster = [ {file = "alabaster-0.7.12-py2.py3-none-any.whl", hash = "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359"}, {file = "alabaster-0.7.12.tar.gz", hash = "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"}, @@ -988,6 +1100,10 @@ appdirs = [ {file = "aspy.refactor_imports-2.1.1-py2.py3-none-any.whl", hash = "sha256:9df76bf19ef81620068b785a386740ab3c8939fcbdcebf20c4a4e0057230d782"}, {file = "aspy.refactor_imports-2.1.1.tar.gz", hash = "sha256:eec8d1a73bedf64ffb8b589ad919a030c1fb14acf7d1ce0ab192f6eedae895c5"}, ] +async-timeout = [ + {file = "async-timeout-3.0.1.tar.gz", hash = "sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f"}, + {file = "async_timeout-3.0.1-py3-none-any.whl", hash = "sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3"}, +] atomicwrites = [ {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, @@ -1183,6 +1299,41 @@ mccabe = [ {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, ] +multidict = [ + {file = "multidict-5.0.0-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:11dcf2366da487d5b9de1d4b2055308c7ed9bde1a52973d07a89b42252af9ebe"}, + {file = "multidict-5.0.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:167bd8e6351b57525bbf2d524ca5a133834699a2fcb090aad0c330c6017f3f3e"}, + {file = "multidict-5.0.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:60af726c19a899ed49bbb276e062f08b80222cb6b9feda44b59a128b5ff52966"}, + {file = "multidict-5.0.0-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:32f0a904859a6274d7edcbb01752c8ae9c633fb7d1c131771ff5afd32eceee42"}, + {file = "multidict-5.0.0-cp36-cp36m-manylinux2014_ppc64le.whl", hash = "sha256:7561a804093ea4c879e06b5d3d18a64a0bc21004bade3540a4b31342b528d326"}, + {file = "multidict-5.0.0-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:786ad04ad954afe9927a1b3049aa58722e182160fe2fcac7ad7f35c93595d4f6"}, + {file = "multidict-5.0.0-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:02b2ea2bb1277a970d238c5c783023790ca94d386c657aeeb165259950951cc6"}, + {file = "multidict-5.0.0-cp36-cp36m-win_amd64.whl", hash = "sha256:932964cf57c0e59d1f3fb63ff342440cf8aaa75bf0dbcbad902c084024975380"}, + {file = "multidict-5.0.0-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:c692087913e12b801a759e25a626c3d311f416252dfba2ecdfd254583427949f"}, + {file = "multidict-5.0.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:cda06c99cd6f4a36571bb38e560a6fcfb1f136521e57f612e0bc31957b1cd4bd"}, + {file = "multidict-5.0.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:84e4943d8725659942e7401bdf31780acde9cfdaf6fe977ff1449fffafcd93a9"}, + {file = "multidict-5.0.0-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:bbec545b8f82536bc50afa9abce832176ed250aa22bfff3e20b3463fb90b0b35"}, + {file = "multidict-5.0.0-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:c339b7d73c0ea5c551025617bb8aa1c00a0111187b6545f48836343e6cfbe6a0"}, + {file = "multidict-5.0.0-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:0ce1d956ecbf112d49915ebc2f29c03e35fe451fb5e9f491edf9a2f4395ee0af"}, + {file = "multidict-5.0.0-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:39713fa2c687e0d0e709ad751a8a709ac051fcdc7f2048f6fd09365dd03c83eb"}, + {file = "multidict-5.0.0-cp37-cp37m-win_amd64.whl", hash = "sha256:0ffdb4b897b15df798c0a5939a0323ccf703f2bae551dfab4eb1af7fbab38ead"}, + {file = "multidict-5.0.0-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:4ef76ce695da72e176f6a51867afb3bf300ce16ba2597824caaef625af5906a9"}, + {file = "multidict-5.0.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:711289412b78cf41a21457f4c806890466013d62bf4296bd3d71fad73ff8a581"}, + {file = "multidict-5.0.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:2b0cfc33f53e5c8226f7d7c4e126fa0780f970ef1e96f7c6353da7d01eafe490"}, + {file = "multidict-5.0.0-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:28b5913e5b6fef273e5d4230b61f33c8a51c3ce5f44a88582dee6b5ca5c9977b"}, + {file = "multidict-5.0.0-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:a5eca9ee72b372199c2b76672145e47d3c829889eefa2037b1f3018f54e5f67d"}, + {file = "multidict-5.0.0-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:20eaf1c279c543e07c164e4ac02151488829177da06607efa7ccfecd71b21e79"}, + {file = "multidict-5.0.0-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:ec8bc0ab00c76c4260a201eaa58812ea8b1b7fde0ecf5f9c9365a182bd4691ed"}, + {file = "multidict-5.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:aad240c1429e386af38a2d6761032f0bec5177fed7c5f582c835c99fff135b5c"}, + {file = "multidict-5.0.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:52b5b51281d760197ce3db063c166fdb626e01c8e428a325aa37198ce31c9565"}, + {file = "multidict-5.0.0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:5263359a03368985b5296b7a73363d761a269848081879ba04a6e4bfd0cf4a78"}, + {file = "multidict-5.0.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:620c39b1270b68e194023ad471b6a54bdb517bb48515939c9829b56c783504a3"}, + {file = "multidict-5.0.0-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:2739d1d9237835122b27d88990849ecf41ef670e0fcb876159edd236ca9ef40f"}, + {file = "multidict-5.0.0-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:62f6e66931fb87e9016e7c1cc806ab4f3e39392fd502362df3cac888078b27cb"}, + {file = "multidict-5.0.0-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:5dd303b545b62f9d2b14f99fbdb84c109a20e64a57f6a192fe6aebcb6263b59d"}, + {file = "multidict-5.0.0-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:60b12d14bc122ba2dae1e4460a891b3a96e73d815b4365675f6ec0a1725416a5"}, + {file = "multidict-5.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:79dc3e6e7ce853fb7ed17c134e01fcb0d0c826b33201aa2a910fb27ed75c2eb9"}, + {file = "multidict-5.0.0.tar.gz", hash = "sha256:1b324444299c3a49b601b1bf621fc21704e29066f6ac2b7d7e4034a4a18662a1"}, +] mypy = [ {file = "mypy-0.790-cp35-cp35m-macosx_10_6_x86_64.whl", hash = "sha256:bd03b3cf666bff8d710d633d1c56ab7facbdc204d567715cb3b9f85c6e94f669"}, {file = "mypy-0.790-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:2170492030f6faa537647d29945786d297e4862765f0b4ac5930ff62e300d802"}, @@ -1263,9 +1414,13 @@ pytest = [ {file = "pytest-6.1.2-py3-none-any.whl", hash = "sha256:4288fed0d9153d9646bfcdf0c0428197dba1ecb27a33bb6e031d002fa88653fe"}, {file = "pytest-6.1.2.tar.gz", hash = "sha256:c0a7e94a8cdbc5422a51ccdad8e6f1024795939cc89159a0ae7f0b316ad3823e"}, ] +pytest-asyncio = [ + {file = "pytest-asyncio-0.14.0.tar.gz", hash = "sha256:9882c0c6b24429449f5f969a5158b528f39bde47dc32e85b9f0403965017e700"}, + {file = "pytest_asyncio-0.14.0-py3-none-any.whl", hash = "sha256:2eae1e34f6c68fc0a9dc12d4bea190483843ff4708d24277c41568d6b6044f1d"}, +] pytz = [ - {file = "pytz-2020.1-py2.py3-none-any.whl", hash = "sha256:a494d53b6d39c3c6e44c3bec237336e14305e4f29bbf800b599253057fbb79ed"}, - {file = "pytz-2020.1.tar.gz", hash = "sha256:c35965d010ce31b23eeb663ed3cc8c906275d6be1a34393a1d73a41febf4a048"}, + {file = "pytz-2020.4-py2.py3-none-any.whl", hash = "sha256:5c55e189b682d420be27c6995ba6edce0c0a77dd67bfbe2ae6607134d5851ffd"}, + {file = "pytz-2020.4.tar.gz", hash = "sha256:3e6b7dd2d1e0a59084bcee14a17af60c5c562cdc16d828e8eba2e683d3a7e268"}, ] pyyaml = [ {file = "PyYAML-5.3.1-cp27-cp27m-win32.whl", hash = "sha256:74809a57b329d6cc0fdccee6318f44b9b8649961fa73144a98735b0aaf029f1f"}, @@ -1289,34 +1444,22 @@ regex = [ {file = "regex-2020.10.28-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:f43109822df2d3faac7aad79613f5f02e4eab0fc8ad7932d2e70e2a83bd49c26"}, {file = "regex-2020.10.28-cp36-cp36m-win32.whl", hash = "sha256:8092a5a06ad9a7a247f2a76ace121183dc4e1a84c259cf9c2ce3bbb69fac3582"}, {file = "regex-2020.10.28-cp36-cp36m-win_amd64.whl", hash = "sha256:49461446b783945597c4076aea3f49aee4b4ce922bd241e4fcf62a3e7c61794c"}, - {file = "regex-2020.10.28-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:297116e79074ec2a2f885d22db00ce6e88b15f75162c5e8b38f66ea734e73c64"}, {file = "regex-2020.10.28-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:8ca9dca965bd86ea3631b975d63b0693566d3cc347e55786d5514988b6f5b84c"}, {file = "regex-2020.10.28-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ea37320877d56a7f0a1e6a625d892cf963aa7f570013499f5b8d5ab8402b5625"}, {file = "regex-2020.10.28-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:3a5f08039eee9ea195a89e180c5762bfb55258bfb9abb61a20d3abee3b37fd12"}, {file = "regex-2020.10.28-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:cb905f3d2e290a8b8f1579d3984f2cfa7c3a29cc7cba608540ceeed18513f520"}, - {file = "regex-2020.10.28-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:96f99219dddb33e235a37283306834700b63170d7bb2a1ee17e41c6d589c8eb9"}, - {file = "regex-2020.10.28-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:227a8d2e5282c2b8346e7f68aa759e0331a0b4a890b55a5cfbb28bd0261b84c0"}, - {file = "regex-2020.10.28-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:2564def9ce0710d510b1fc7e5178ce2d20f75571f788b5197b3c8134c366f50c"}, {file = "regex-2020.10.28-cp37-cp37m-win32.whl", hash = "sha256:a62162be05edf64f819925ea88d09d18b09bebf20971b363ce0c24e8b4aa14c0"}, {file = "regex-2020.10.28-cp37-cp37m-win_amd64.whl", hash = "sha256:03855ee22980c3e4863dc84c42d6d2901133362db5daf4c36b710dd895d78f0a"}, - {file = "regex-2020.10.28-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bf4f896c42c63d1f22039ad57de2644c72587756c0cfb3cc3b7530cfe228277f"}, {file = "regex-2020.10.28-cp38-cp38-manylinux1_i686.whl", hash = "sha256:625116aca6c4b57c56ea3d70369cacc4d62fead4930f8329d242e4fe7a58ce4b"}, {file = "regex-2020.10.28-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2dc522e25e57e88b4980d2bdd334825dbf6fa55f28a922fc3bfa60cc09e5ef53"}, {file = "regex-2020.10.28-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:119e0355dbdd4cf593b17f2fc5dbd4aec2b8899d0057e4957ba92f941f704bf5"}, {file = "regex-2020.10.28-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:cfcf28ed4ce9ced47b9b9670a4f0d3d3c0e4d4779ad4dadb1ad468b097f808aa"}, - {file = "regex-2020.10.28-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:b45bab9f224de276b7bc916f6306b86283f6aa8afe7ed4133423efb42015a898"}, - {file = "regex-2020.10.28-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:52e83a5f28acd621ba8e71c2b816f6541af7144b69cc5859d17da76c436a5427"}, - {file = "regex-2020.10.28-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:aacc8623ffe7999a97935eeabbd24b1ae701d08ea8f874a6ff050e93c3e658cf"}, {file = "regex-2020.10.28-cp38-cp38-win32.whl", hash = "sha256:06b52815d4ad38d6524666e0d50fe9173533c9cc145a5779b89733284e6f688f"}, {file = "regex-2020.10.28-cp38-cp38-win_amd64.whl", hash = "sha256:c3466a84fce42c2016113101018a9981804097bacbab029c2d5b4fcb224b89de"}, - {file = "regex-2020.10.28-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:127a9e0c0d91af572fbb9e56d00a504dbd4c65e574ddda3d45b55722462210de"}, {file = "regex-2020.10.28-cp39-cp39-manylinux1_i686.whl", hash = "sha256:c2c6c56ee97485a127555c9595c069201b5161de9d05495fbe2132b5ac104786"}, {file = "regex-2020.10.28-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:1ec66700a10e3c75f1f92cbde36cca0d3aaee4c73dfa26699495a3a30b09093c"}, {file = "regex-2020.10.28-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:11116d424734fe356d8777f89d625f0df783251ada95d6261b4c36ad27a394bb"}, {file = "regex-2020.10.28-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:f1fce1e4929157b2afeb4bb7069204d4370bab9f4fc03ca1fbec8bd601f8c87d"}, - {file = "regex-2020.10.28-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:3dfca201fa6b326239e1bccb00b915e058707028809b8ecc0cf6819ad233a740"}, - {file = "regex-2020.10.28-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:b8a686a6c98872007aa41fdbb2e86dc03b287d951ff4a7f1da77fb7f14113e4d"}, - {file = "regex-2020.10.28-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:c32c91a0f1ac779cbd73e62430de3d3502bbc45ffe5bb6c376015acfa848144b"}, {file = "regex-2020.10.28-cp39-cp39-win32.whl", hash = "sha256:832339223b9ce56b7b15168e691ae654d345ac1635eeb367ade9ecfe0e66bee0"}, {file = "regex-2020.10.28-cp39-cp39-win_amd64.whl", hash = "sha256:654c1635f2313d0843028487db2191530bca45af61ca85d0b16555c399625b0e"}, {file = "regex-2020.10.28.tar.gz", hash = "sha256:dd3e6547ecf842a29cf25123fbf8d2461c53c8d37aa20d87ecee130c89b7079b"}, @@ -1522,6 +1665,41 @@ xdoctest = [ {file = "xdoctest-0.15.0-py2.py3-none-any.whl", hash = "sha256:695ea04303a48cbb319709270d43f7bae7f3de3701aec73f09d90a216499992e"}, {file = "xdoctest-0.15.0.tar.gz", hash = "sha256:7f0a184d403b69b166ebec1aadb13c98c96c59101e974ae2e4db4c3a803ec371"}, ] +yarl = [ + {file = "yarl-1.6.2-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:d77f6c9133d2aabb290a7846aaa74ec14d7b5ab35b01591fac5a70c4a8c959a2"}, + {file = "yarl-1.6.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:311effab3b3828ab34f0e661bb57ff422f67d5c33056298bda4c12195251f8dd"}, + {file = "yarl-1.6.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:f835015a825980b65356e9520979a1564c56efea7da7d4b68a14d4a07a3a7336"}, + {file = "yarl-1.6.2-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:59f78b5da34ddcffb663b772f7619e296518712e022e57fc5d9f921818e2ab7c"}, + {file = "yarl-1.6.2-cp36-cp36m-manylinux2014_ppc64le.whl", hash = "sha256:3526cb5905907f0e42bee7ef57ae4a5f02bc27dcac27859269e2bba0caa4c2b6"}, + {file = "yarl-1.6.2-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:e77bf79ad1ccae672eab22453838382fe9029fc27c8029e84913855512a587d8"}, + {file = "yarl-1.6.2-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:b3dd1052afd436ba737e61f5d3bed1f43a7f9a33fc58fbe4226eb919a7006019"}, + {file = "yarl-1.6.2-cp36-cp36m-win_amd64.whl", hash = "sha256:6f29115b0c330da25a04f48612d75333bca04521181a666ca0b8761005a99150"}, + {file = "yarl-1.6.2-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:f3031c78edf10315abe232254e6a36b65afe65fded41ee54ed7976d0b2cdf0da"}, + {file = "yarl-1.6.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:4bed5cd7c8e69551eb19df15295ba90e62b9a6a1149c76eb4a9bab194402a156"}, + {file = "yarl-1.6.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:39b1e586f34b1d2512c9b39aa3cf24c870c972d525e36edc9ee19065db4737bb"}, + {file = "yarl-1.6.2-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:03b7a44384ad60be1b7be93c2a24dc74895f8d767ea0bce15b2f6fc7695a3843"}, + {file = "yarl-1.6.2-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:a1fd575dd058e10ad4c35065e7c3007cc74d142f622b14e168d8a273a2fa8713"}, + {file = "yarl-1.6.2-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:9b48d31f8d881713fd461abfe7acbb4dcfeb47cec3056aa83f2fbcd2244577f7"}, + {file = "yarl-1.6.2-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:1c05ae3d5ea4287470046a2c2754f0a4c171b84ea72c8a691f776eb1753dfb91"}, + {file = "yarl-1.6.2-cp37-cp37m-win_amd64.whl", hash = "sha256:f4f27ff3dd80bc7c402def211a47291ea123d59a23f59fe18fc0e81e3e71f385"}, + {file = "yarl-1.6.2-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:73d4e1e1ef5e52d526c92f07d16329e1678612c6a81dd8101fdcae11a72de15c"}, + {file = "yarl-1.6.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:db643ce2b58a4bd11a82348225c53c76ecdd82bb37cf4c085e6df1b676f4038c"}, + {file = "yarl-1.6.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:d25d3311794e6c71b608d7c47651c8f65eea5ab15358a27f29330b3475e8f8e5"}, + {file = "yarl-1.6.2-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:51c6d3cf7a1f1fbe134bb92f33b7affd94d6de24cd64b466eb12de52120fb8c6"}, + {file = "yarl-1.6.2-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:cd623170c729a865037828e3f99f8ebdb22a467177a539680dfc5670b74c84e2"}, + {file = "yarl-1.6.2-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:c056e86bff5a0b566e0d9fab4f67e83b12ae9cbcd250d334cbe2005bbe8c96f2"}, + {file = "yarl-1.6.2-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:f4c007156732866aa4507d619fe6f8f2748caabed4f66b276ccd97c82572620c"}, + {file = "yarl-1.6.2-cp38-cp38-win_amd64.whl", hash = "sha256:2bb2e21cf062dfbe985c3cd4618bae9f25271efcad9e7be1277861247eee9839"}, + {file = "yarl-1.6.2-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:b99c25ed5c355b35d1e6dae87ac7297a4844a57dc5766b173b88b6163a36eb0d"}, + {file = "yarl-1.6.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:2467baf8233f7c64048df37e11879c553943ffe7f373e689711ec2807ea13805"}, + {file = "yarl-1.6.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:e3a0c43a26dfed955b2a06fdc4d51d2c51bc2200aff8ce8faf14e676ea8c8862"}, + {file = "yarl-1.6.2-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:f2f0174cb15435957d3b751093f89aede77df59a499ab7516bbb633b77ead13a"}, + {file = "yarl-1.6.2-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:d695439c201ed340745250f9eb4dfe8d32bf1e680c16477107b8f3ce4bff4fdb"}, + {file = "yarl-1.6.2-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:f57744fc61e118b5d114ae8077d8eb9df4d2d2c11e2af194e21f0c11ed9dcf6c"}, + {file = "yarl-1.6.2-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:d894a2442d2cd20a3b0b0dce5a353d316c57d25a2b445e03f7eac90eee27b8af"}, + {file = "yarl-1.6.2-cp39-cp39-win_amd64.whl", hash = "sha256:076157404db9db4bb3fa9db22db319bbb36d075eeab19ba018ce20ae0cacf037"}, + {file = "yarl-1.6.2.tar.gz", hash = "sha256:c45b49b59a5724869899798e1bbd447ac486215269511d3b76b4c235a1b766b6"}, +] zipp = [ {file = "zipp-3.4.0-py3-none-any.whl", hash = "sha256:102c24ef8f171fd729d46599845e95c7ab894a4cf45f5de11a44cc7444fb1108"}, {file = "zipp-3.4.0.tar.gz", hash = "sha256:ed5eee1974372595f9e416cc7bbeeb12335201d8081ca8a0743c954d4446e5cb"}, diff --git a/pyproject.toml b/pyproject.toml index 96ceb0cd..cd464490 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,6 +47,8 @@ pre-commit-hooks = "^3.3.0" sphinx-rtd-theme = "^0.5.0" sphinx-click = "^2.5.0" Pygments = "^2.7.2" +pytest-asyncio = "^0.14.0" +aioresponses = "^0.7.1" [tool.poetry.scripts] renault-api = "renault_api.__main__:main" diff --git a/tests/fixtures/config_sample.txt b/tests/fixtures/config_sample.txt new file mode 100644 index 00000000..b01893d9 --- /dev/null +++ b/tests/fixtures/config_sample.txt @@ -0,0 +1,283 @@ +{ + "instabug": { + "enabled": false + }, + "visibility": { + "sections": { + "smart_route_planner": true, + "pairing_ivi": true, + "pairing_ze": true, + "ots": true + }, + "subsections": {}, + "views": { + "profile_menu_alertes": true, + "car_maintenance_tab_title": true, + "car_offers_tab_title": true, + "car_menu_status_pressure": false, + "car_status_quotation": true, + "help_menu_contact": true, + "help_FAQ_tab_title": true, + "help_ADVICES_tab_title": true, + "help_notice_title": true, + "profile_menu_infos": true, + "profile_menu_infos_modify_email": false, + "profile_menu_settings": true, + "profile_menu_settings_delete_cta": true, + "profile_menu_edition_region_layout": false, + "carpage_tab_title_status": true, + "navigation_myr_off": true, + "navigation_myr": true, + "navigation_menu_map_parking_btn": true, + "navigation_menu_map_more_btn": true, + "navigation_menu_poi_bottom_ctas": true, + "navigation_menu_poi_details_sendto_cta": true, + "help_myr": true, + "profile_myr": true, + "signup_firstname": true, + "add_car_type_layout": false, + "input_layout_add_car_reg": false, + "profile": { + "input_layout_civility": true, + "input_layout_firstname": true, + "input_layout_lastname": true, + "input_layout_birthday": false, + "input_layout_national_id": false, + "input_layout_mobile_phone": true, + "input_layout_landline_phone": false, + "input_layout_address": true, + "input_layout_postal_code": true, + "input_layout_city": true, + "profile_menu_infos_region_layout": false, + "input_layout_marital_status": false, + "input_layout_children_number": false + } + } + }, + "pages": { + "car": { + "cotation": "https://cote.renault.fr/", + "general_advise": [ + { + "picture": "", + "maxAdviseNb": 2 + } + ], + "acceleration_advise": [ + { + "picture": "", + "maxAdviseNb": 2 + } + ], + "switch_advise": [ + { + "picture": "", + "maxAdviseNb": 2 + } + ], + "anticipation_advise": [ + { + "picture": "", + "maxAdviseNb": 2 + } + ], + "eco_advice_elec_conduct": [ + { + "picture": "", + "maxAdviseNb": 3 + } + ], + "eco_advice_elec_tyre": [ + { + "picture": "", + "maxAdviseNb": 1 + } + ], + "eco_advice_elec_conso": [ + { + "picture": "", + "maxAdviseNb": 4 + } + ] + }, + "offers": { + "user": true, + "car": true + }, + "rating_application": { + "mail": "contact.client@renault.com", + "url": "" + }, + "faq": { + "maxSectionNb": 3, + "maxQuestionNb": 3, + "picture": "", + "response": [ + { + "idSection": "1", + "idQuestion": "1", + "urlType": "video", + "url": "Eni138mjSpw" + }, + { + "idSection": "1", + "idQuestion": "2", + "urlType": "video", + "url": "KRkqPA0_5rk" + } + ], + "contact": { + "display": true, + "urlType": "mail", + "url": "contact.client@renault.com" + } + }, + "advices": { + "maxSectionNb": 3, + "maxQuestionNb": 3, + "picture": "", + "response": [ + { + "idSection": "1", + "idQuestion": "1", + "urlType": "video", + "url": "Eni138mjSpw" + }, + { + "idSection": "1", + "idQuestion": "2", + "urlType": "video", + "url": "KRkqPA0_5rk" + }, + { + "idSection": "1", + "idQuestion": "3", + "urlType": "video", + "url": "ReUP5ErzceA" + }, + { + "idSection": "2", + "idQuestion": "1", + "urlType": "video", + "url": "Ur-JvJd8M90" + }, + { + "idSection": "2", + "idQuestion": "2", + "urlType": "video", + "url": "aK9j5urvogw" + }, + { + "idSection": "2", + "idQuestion": "3", + "urlType": "video", + "url": "-YSbVnkdaEI" + } + ], + "contact": { + "display": true, + "urlType": "mail", + "url": "contact.client@renault.com" + } + } + }, + "regex": { + "name": "^[\\p{L}\\s\\’'-]{2,255}$", + "email": "^[[:alnum:]]([-_.]?[[:alnum:]])*@[[:alnum:]]([-.]?[[:alnum:]])*\\.([a-z]{2,4})$", + "password": "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?!.*\\s)[A-Za-z\\d\\W]{8,}", + "phone": "^0[1,2,3,4,5,9](([\\.\\s]?[0-9]{2}){4})\\s?$", + "mobile_phone": "^0[6,7](([\\.\\s]?[0-9]{2}){4})\\s?$", + "vin": "^[a-zA-Z0-9]{17}$", + "registration_number": "", + "postal_code": "^((0[1-9])|([1-8][0-9])|(9[0-8])|(2A)|(2B))[0-9]{3}$", + "city": "^[a-zA-ZÀ-ÿ\\s-]{1,40}$" + }, + "contact": { + "call_center": { + "channels": [ + { + "id": 1, + "type": "mail", + "value": "assistance.multimedia@renault.com" + }, + { + "id": 2, + "type": "url", + "value": "https://easyconnect.renault.fr" + } + ] + }, + "renault_assistance": { + "phone_number": "0800051515" + } + }, + "servers": { + "kamareon": { + "target": "https://alliance-platform-serviceadapter-staging.apps.prod.eu.kamereon.org", + "apikey": "Z7P4xyNrTITzNZh52oObSOVfKns9XGLE" + }, + "wired": { + "target": "https://api-wired-dev-1-euw1.wrd-aws.com", + "apikey": "AHdOWFASWEPUVQVlhJWshsios0FqTG2E" + }, + "wiredValid": { + "target": "https://api-wired-valid-1-euw1.wrd-aws.com", + "apikey": "AHdOWFASWEPUVQVlhJWshsios0FqTG2E" + }, + "wiredProd": { + "target": "https://api-wired-prod-1-euw1.wrd-aws.com", + "apikey": "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB" + }, + "gigya": { + "target": "https://accounts.eu1.gigya.com", + "apikey": "3_S0OWIrqeJ6mxOkXFT8i3TTDwW1IGKk2rIypZjGXi4Hh8vce2ohuERio1Ka5DBbUr" + }, + "gigyaValid": { + "target": "https://accounts.eu1.gigya.com", + "apikey": "3_2YjuX_CyODLN3o4wK70yHKUJFHxKFiePSD65DlCS89AmsZ0Va77k_g7HUmubA4pj" + }, + "gigyaProd": { + "target": "https://accounts.eu1.gigya.com", + "apikey": "3_4LKbCcMMcvjDm3X89LU4z4mNKYKdl_W0oD9w-Jvih21WqgJKtFZAnb9YdUgWT9_a" + } + }, + "booking": { + "url": "https://www.renault.fr/contact/rdv-entretien.html" + }, + "settings": { + "defaultUnits": { + "system": "Metric", + "mileage": { + "value": "km" + }, + "volume": { + "value": "l" + }, + "pressure": { + "value": "bar" + }, + "speed": { + "value": "km/h" + }, + "consumption": { + "value": "l100" + }, + "temperature": { + "value": "c" + } + }, + "links": { + "notice": "https://www.renault.fr/legal.html", + "legal_info_url": "https://www.renault.fr/donnees-personnelles.html" + } + }, + "additional_legal_page": { + "display": false, + "picture": "", + "url1": "https://www.renault.de/datenschutz-und-rechtliche-hinweise.html", + "url2": "https://www.renault.de/cookies.html", + "url3": "https://www.renault.de/impressum.html" + }, +"globalCommunication": false + +} diff --git a/tests/test_api_keys.py b/tests/test_api_keys.py new file mode 100644 index 00000000..4c01204c --- /dev/null +++ b/tests/test_api_keys.py @@ -0,0 +1,85 @@ +"""Test cases for the Renault client API keys.""" +from typing import AsyncGenerator + +import pytest +from aiohttp import ClientSession +from aioresponses import aioresponses # type: ignore + +from renault_api.client import RenaultClient +from renault_api.const import AVAILABLE_LOCALES +from renault_api.const import CONF_GIGYA_APIKEY +from renault_api.const import CONF_GIGYA_URL +from renault_api.const import CONF_KAMEREON_APIKEY +from renault_api.const import CONF_KAMEREON_URL +from renault_api.exceptions import RenaultError + + +@pytest.fixture +async def renault_client() -> AsyncGenerator[RenaultClient, None]: + """Fixture for testing RenaultClient.""" + async with ClientSession() as aiohttp_session: + client = RenaultClient() + client.aiohttp_session = aiohttp_session + + yield client + + +@pytest.mark.asyncio +@pytest.mark.parametrize("locale", AVAILABLE_LOCALES.keys()) +async def test_available_locales(locale: str) -> None: + """Ensure all items AVAILABLE_LOCALES have correct data.""" + expected_api_keys = AVAILABLE_LOCALES[locale] + + renault_client = RenaultClient() + api_keys = await renault_client.preload_api_keys(locale) + assert api_keys == expected_api_keys + for key in [ + CONF_GIGYA_APIKEY, + CONF_GIGYA_URL, + CONF_KAMEREON_APIKEY, + CONF_KAMEREON_URL, + ]: + assert api_keys[key] + + +@pytest.mark.asyncio +async def test_missing_aiohttp_session() -> None: + """Ensure is able to parse a known known.""" + locale = "invalid" + + renault_client = RenaultClient() + with pytest.raises(RenaultError) as excinfo: + await renault_client.preload_api_keys(locale) + assert "aiohttp_session is not set." in str(excinfo) + + +@pytest.mark.asyncio +async def test_preload_unknown_api_keys(renault_client: RenaultClient) -> None: + """Ensure is able to parse a known known.""" + expected_api_keys = AVAILABLE_LOCALES["fr_FR"] + + fake_locale = "invalid" + fake_url = f"https://renault-wrd-prod-1-euw1-myrapp-one.s3-eu-west-1.amazonaws.com/configuration/android/config_{fake_locale}.json" # noqa + with open("tests/fixtures/config_sample.txt", "r") as f: + fake_body = f.read() + + with aioresponses() as mock_aioresponses: + mock_aioresponses.get(fake_url, status=200, body=fake_body) + + api_keys = await renault_client.preload_api_keys(fake_locale) + + assert api_keys == expected_api_keys + + +@pytest.mark.asyncio +async def test_preload_invalid_api_keys(renault_client: RenaultClient) -> None: + """Ensure is able to parse an invalid locale.""" + fake_locale = "fake" + fake_url = f"https://renault-wrd-prod-1-euw1-myrapp-one.s3-eu-west-1.amazonaws.com/configuration/android/config_{fake_locale}.json" # noqa + + with aioresponses() as mock_aioresponses: + mock_aioresponses.get(fake_url, status=404) + + with pytest.raises(RenaultError) as excinfo: + await renault_client.preload_api_keys(fake_locale) + assert "Locale not found on Renault server" in str(excinfo) From 41581d74105fdb929e4708fc1127ffab26d74297 Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Tue, 3 Nov 2020 07:47:00 +0100 Subject: [PATCH 05/18] Update constants --- src/renault_api/const.py | 181 ++++++++++++++++++++------------------- 1 file changed, 94 insertions(+), 87 deletions(-) diff --git a/src/renault_api/const.py b/src/renault_api/const.py index a7de4c23..862dd51a 100644 --- a/src/renault_api/const.py +++ b/src/renault_api/const.py @@ -4,179 +4,186 @@ CONF_KAMEREON_APIKEY = "kamereon-api-key" CONF_KAMEREON_URL = "kamereon-api-url" +GIGYA_URL_EU = "https://accounts.eu1.gigya.com" +GIGYA_URL_US = "https://accounts.us1.gigya.com" +KAMEREON_APIKEY = "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB" +KAMEREON_URL_EU = "https://api-wired-prod-1-euw1.wrd-aws.com" +KAMEREON_URL_US = "https://api-wired-prod-1-usw2.wrd-aws.com" + + AVAILABLE_LOCALES = { "bg_BG": { - CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_URL: GIGYA_URL_EU, CONF_GIGYA_APIKEY: "3__3ER_6lFvXEXHTP_faLtq6eEdbKDXd9F5GoKwzRyZq37ZQ-db7mXcLzR1Jtls5sn", # noqa - CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", - CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + CONF_KAMEREON_URL: KAMEREON_URL_EU, + CONF_KAMEREON_APIKEY: KAMEREON_APIKEY, }, "cs_CZ": { - CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_URL: GIGYA_URL_EU, CONF_GIGYA_APIKEY: "3_oRlKr5PCVL_sPWUZdJ8c5NOl5Ej8nIZw7VKG7S9Rg36UkDszFzfHfxCaUAUU5or2", # noqa - CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", - CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + CONF_KAMEREON_URL: KAMEREON_URL_EU, + CONF_KAMEREON_APIKEY: KAMEREON_APIKEY, }, "da_DK": { - CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_URL: GIGYA_URL_EU, CONF_GIGYA_APIKEY: "3_5x-2C8b1R4MJPQXkwTPdIqgBpcw653Dakw_ZaEneQRkTBdg9UW9Qg_5G-tMNrTMc", # noqa - CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", - CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + CONF_KAMEREON_URL: KAMEREON_URL_EU, + CONF_KAMEREON_APIKEY: KAMEREON_APIKEY, }, "de_DE": { - CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_URL: GIGYA_URL_EU, CONF_GIGYA_APIKEY: "3_7PLksOyBRkHv126x5WhHb-5pqC1qFR8pQjxSeLB6nhAnPERTUlwnYoznHSxwX668", # noqa - CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", - CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + CONF_KAMEREON_URL: KAMEREON_URL_EU, + CONF_KAMEREON_APIKEY: KAMEREON_APIKEY, }, "de_AT": { - CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_URL: GIGYA_URL_EU, CONF_GIGYA_APIKEY: "3__B4KghyeUb0GlpU62ZXKrjSfb7CPzwBS368wioftJUL5qXE0Z_sSy0rX69klXuHy", # noqa - CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", - CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + CONF_KAMEREON_URL: KAMEREON_URL_EU, + CONF_KAMEREON_APIKEY: KAMEREON_APIKEY, }, "de_CH": { - CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_URL: GIGYA_URL_EU, CONF_GIGYA_APIKEY: "3_UyiWZs_1UXYCUqK_1n7l7l44UiI_9N9hqwtREV0-UYA_5X7tOV-VKvnGxPBww4q2", # noqa - CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", - CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + CONF_KAMEREON_URL: KAMEREON_URL_EU, + CONF_KAMEREON_APIKEY: KAMEREON_APIKEY, }, "en_GB": { - CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_URL: GIGYA_URL_EU, CONF_GIGYA_APIKEY: "3_e8d4g4SE_Fo8ahyHwwP7ohLGZ79HKNN2T8NjQqoNnk6Epj6ilyYwKdHUyCw3wuxz", # noqa - CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", - CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + CONF_KAMEREON_URL: KAMEREON_URL_EU, + CONF_KAMEREON_APIKEY: KAMEREON_APIKEY, }, "en_IE": { - CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_URL: GIGYA_URL_EU, CONF_GIGYA_APIKEY: "3_Xn7tuOnT9raLEXuwSI1_sFFZNEJhSD0lv3gxkwFtGI-RY4AgiePBiJ9EODh8d9yo", # noqa - CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", - CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + CONF_KAMEREON_URL: KAMEREON_URL_EU, + CONF_KAMEREON_APIKEY: KAMEREON_APIKEY, }, "es_ES": { - CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_URL: GIGYA_URL_EU, CONF_GIGYA_APIKEY: "3_DyMiOwEaxLcPdBTu63Gv3hlhvLaLbW3ufvjHLeuU8U5bx3zx19t5rEKq7KMwk9f1", # noqa - CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", - CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + CONF_KAMEREON_URL: KAMEREON_URL_EU, + CONF_KAMEREON_APIKEY: KAMEREON_APIKEY, }, "es_MX": { - CONF_GIGYA_URL: "https://accounts.us1.gigya.com", + CONF_GIGYA_URL: GIGYA_URL_US, CONF_GIGYA_APIKEY: "3_BFzR-2wfhMhUs5OCy3R8U8IiQcHS-81vF8bteSe8eFrboMTjEWzbf4pY1aHQ7cW0", # noqa - CONF_KAMEREON_URL: "https://api-wired-prod-1-usw2.wrd-aws.com", - CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + CONF_KAMEREON_URL: KAMEREON_URL_US, + CONF_KAMEREON_APIKEY: KAMEREON_APIKEY, }, "fi_FI": { - CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_URL: GIGYA_URL_EU, CONF_GIGYA_APIKEY: "3_xSRCLDYhk1SwSeYQLI3DmA8t-etfAfu5un51fws125ANOBZHgh8Lcc4ReWSwaqNY", # noqa - CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", - CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + CONF_KAMEREON_URL: KAMEREON_URL_EU, + CONF_KAMEREON_APIKEY: KAMEREON_APIKEY, }, "fr_FR": { - CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_URL: GIGYA_URL_EU, CONF_GIGYA_APIKEY: "3_4LKbCcMMcvjDm3X89LU4z4mNKYKdl_W0oD9w-Jvih21WqgJKtFZAnb9YdUgWT9_a", # noqa - CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", - CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + CONF_KAMEREON_URL: KAMEREON_URL_EU, + CONF_KAMEREON_APIKEY: KAMEREON_APIKEY, }, "fr_BE": { - CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_URL: GIGYA_URL_EU, CONF_GIGYA_APIKEY: "3_ZK9x38N8pzEvdiG7ojWHeOAAej43APkeJ5Av6VbTkeoOWR4sdkRc-wyF72HzUB8X", # noqa - CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", - CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + CONF_KAMEREON_URL: KAMEREON_URL_EU, + CONF_KAMEREON_APIKEY: KAMEREON_APIKEY, }, "fr_CH": { - CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_URL: GIGYA_URL_EU, CONF_GIGYA_APIKEY: "3_h3LOcrKZ9mTXxMI9clb2R1VGAWPke6jMNqMw4yYLz4N7PGjYyD0hqRgIFAIHusSn", # noqa - CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", - CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + CONF_KAMEREON_URL: KAMEREON_URL_EU, + CONF_KAMEREON_APIKEY: KAMEREON_APIKEY, }, "fr_LU": { - CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_URL: GIGYA_URL_EU, CONF_GIGYA_APIKEY: "3_zt44Wl_wT9mnqn-BHrR19PvXj3wYRPQKLcPbGWawlatFR837KdxSZZStbBTDaqnb", # noqa - CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", - CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + CONF_KAMEREON_URL: KAMEREON_URL_EU, + CONF_KAMEREON_APIKEY: KAMEREON_APIKEY, }, "hr_HR": { - CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_URL: GIGYA_URL_EU, CONF_GIGYA_APIKEY: "3_HcDC5GGZ89NMP1jORLhYNNCcXt7M3thhZ85eGrcQaM2pRwrgrzcIRWEYi_36cFj9", # noqa - CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", - CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + CONF_KAMEREON_URL: KAMEREON_URL_EU, + CONF_KAMEREON_APIKEY: KAMEREON_APIKEY, }, "hu_HU": { - CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_URL: GIGYA_URL_EU, CONF_GIGYA_APIKEY: "3_nGDWrkSGZovhnVFv5hdIxyuuCuJGZfNmlRGp7-5kEn9yb0bfIfJqoDa2opHOd3Mu", # noqa - CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", - CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + CONF_KAMEREON_URL: KAMEREON_URL_EU, + CONF_KAMEREON_APIKEY: KAMEREON_APIKEY, }, "it_IT": { - CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_URL: GIGYA_URL_EU, CONF_GIGYA_APIKEY: "3_js8th3jdmCWV86fKR3SXQWvXGKbHoWFv8NAgRbH7FnIBsi_XvCpN_rtLcI07uNuq", # noqa - CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", - CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + CONF_KAMEREON_URL: KAMEREON_URL_EU, + CONF_KAMEREON_APIKEY: KAMEREON_APIKEY, }, "it_CH": { - CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_URL: GIGYA_URL_EU, CONF_GIGYA_APIKEY: "3_gHkmHaGACxSLKXqD_uDDx415zdTw7w8HXAFyvh0qIP0WxnHPMF2B9K_nREJVSkGq", # noqa - CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", - CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + CONF_KAMEREON_URL: KAMEREON_URL_EU, + CONF_KAMEREON_APIKEY: KAMEREON_APIKEY, }, "nl_NL": { - CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_URL: GIGYA_URL_EU, CONF_GIGYA_APIKEY: "3_ZIOtjqmP0zaHdEnPK7h1xPuBYgtcOyUxbsTY8Gw31Fzy7i7Ltjfm-hhPh23fpHT5", # noqa - CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", - CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + CONF_KAMEREON_URL: KAMEREON_URL_EU, + CONF_KAMEREON_APIKEY: KAMEREON_APIKEY, }, "nl_BE": { - CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_URL: GIGYA_URL_EU, CONF_GIGYA_APIKEY: "3_yachztWczt6i1pIMhLIH9UA6DXK6vXXuCDmcsoA4PYR0g35RvLPDbp49YribFdpC", # noqa - CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", - CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + CONF_KAMEREON_URL: KAMEREON_URL_EU, + CONF_KAMEREON_APIKEY: KAMEREON_APIKEY, }, "no_NO": { - CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_URL: GIGYA_URL_EU, CONF_GIGYA_APIKEY: "3_QrPkEJr69l7rHkdCVls0owC80BB4CGz5xw_b0gBSNdn3pL04wzMBkcwtbeKdl1g9", # noqa - CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", - CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + CONF_KAMEREON_URL: KAMEREON_URL_EU, + CONF_KAMEREON_APIKEY: KAMEREON_APIKEY, }, "pl_PL": { - CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_URL: GIGYA_URL_EU, CONF_GIGYA_APIKEY: "3_2YBjydYRd1shr6bsZdrvA9z7owvSg3W5RHDYDp6AlatXw9hqx7nVoanRn8YGsBN8", # noqa - CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", - CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + CONF_KAMEREON_URL: KAMEREON_URL_EU, + CONF_KAMEREON_APIKEY: KAMEREON_APIKEY, }, "pt_PT": { - CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_URL: GIGYA_URL_EU, CONF_GIGYA_APIKEY: "3__afxovspi2-Ip1E5kNsAgc4_35lpLAKCF6bq4_xXj2I2bFPjIWxAOAQJlIkreKTD", # noqa - CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", - CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + CONF_KAMEREON_URL: KAMEREON_URL_EU, + CONF_KAMEREON_APIKEY: KAMEREON_APIKEY, }, "ro_RO": { - CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_URL: GIGYA_URL_EU, CONF_GIGYA_APIKEY: "3_WlBp06vVHuHZhiDLIehF8gchqbfegDJADPQ2MtEsrc8dWVuESf2JCITRo5I2CIxs", # noqa - CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", - CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + CONF_KAMEREON_URL: KAMEREON_URL_EU, + CONF_KAMEREON_APIKEY: KAMEREON_APIKEY, }, "ru_RU": { - CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_URL: GIGYA_URL_EU, CONF_GIGYA_APIKEY: "3_N_ecy4iDyoRtX8v5xOxewwZLKXBjRgrEIv85XxI0KJk8AAdYhJIi17LWb086tGXR", # noqa - CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", - CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + CONF_KAMEREON_URL: KAMEREON_URL_EU, + CONF_KAMEREON_APIKEY: KAMEREON_APIKEY, }, "sk_SK": { - CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_URL: GIGYA_URL_EU, CONF_GIGYA_APIKEY: "3_e8d4g4SE_Fo8ahyHwwP7ohLGZ79HKNN2T8NjQqoNnk6Epj6ilyYwKdHUyCw3wuxz", # noqa - CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", - CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + CONF_KAMEREON_URL: KAMEREON_URL_EU, + CONF_KAMEREON_APIKEY: KAMEREON_APIKEY, }, "sl_SI": { - CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_URL: GIGYA_URL_EU, CONF_GIGYA_APIKEY: "3_QKt0ADYxIhgcje4F3fj9oVidHsx3JIIk-GThhdyMMQi8AJR0QoHdA62YArVjbZCt", # noqa - CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", - CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + CONF_KAMEREON_URL: KAMEREON_URL_EU, + CONF_KAMEREON_APIKEY: KAMEREON_APIKEY, }, "sv_SE": { - CONF_GIGYA_URL: "https://accounts.eu1.gigya.com", + CONF_GIGYA_URL: GIGYA_URL_EU, CONF_GIGYA_APIKEY: "3_EN5Hcnwanu9_Dqot1v1Aky1YelT5QqG4TxveO0EgKFWZYu03WkeB9FKuKKIWUXIS", # noqa - CONF_KAMEREON_URL: "https://api-wired-prod-1-euw1.wrd-aws.com", - CONF_KAMEREON_APIKEY: "oF09WnKqvBDcrQzcW1rJNpjIuy7KdGaB", + CONF_KAMEREON_URL: KAMEREON_URL_EU, + CONF_KAMEREON_APIKEY: KAMEREON_APIKEY, }, } From dbb19e5f7f0ab2f4bb3ea30d21b9ae5bd490cb22 Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Tue, 3 Nov 2020 07:47:26 +0100 Subject: [PATCH 06/18] RenaultError => RenaultException --- src/renault_api/client.py | 8 ++++---- src/renault_api/exceptions.py | 2 +- tests/test_api_keys.py | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/renault_api/client.py b/src/renault_api/client.py index cbb7e45f..9d271a81 100644 --- a/src/renault_api/client.py +++ b/src/renault_api/client.py @@ -11,7 +11,7 @@ from .const import CONF_GIGYA_URL from .const import CONF_KAMEREON_APIKEY from .const import CONF_KAMEREON_URL -from .exceptions import RenaultError +from .exceptions import RenaultException _LOGGER = logging.getLogger(__package__) @@ -34,7 +34,7 @@ async def preload_api_keys(self, locale: str) -> Dict[str, str]: kamereon-api-key and kamereon-api-url Raises: - RenaultError: an issue occured loading the API keys + RenaultException: an issue occured loading the API keys """ if locale in AVAILABLE_LOCALES.keys(): return AVAILABLE_LOCALES[locale] @@ -45,14 +45,14 @@ async def preload_api_keys(self, locale: str) -> Dict[str, str]: locale, ) if self.aiohttp_session is None: - raise RenaultError("aiohttp_session is not set.") + raise RenaultException("aiohttp_session is not set.") url = f"https://renault-wrd-prod-1-euw1-myrapp-one.s3-eu-west-1.amazonaws.com/configuration/android/config_{locale}.json" # noqa async with self.aiohttp_session.get(url) as response: try: response.raise_for_status() except ClientResponseError as exc: - raise RenaultError( + raise RenaultException( f"Locale not found on Renault server ({exc.status})." ) from exc response_body = await response.json(content_type=None) diff --git a/src/renault_api/exceptions.py b/src/renault_api/exceptions.py index 77ebcfe6..ffa5cb32 100644 --- a/src/renault_api/exceptions.py +++ b/src/renault_api/exceptions.py @@ -1,7 +1,7 @@ """Exceptions for Renault API.""" -class RenaultError(Exception): +class RenaultException(Exception): """Base class for Renault API errors.""" pass diff --git a/tests/test_api_keys.py b/tests/test_api_keys.py index 4c01204c..2dcf5f99 100644 --- a/tests/test_api_keys.py +++ b/tests/test_api_keys.py @@ -11,7 +11,7 @@ from renault_api.const import CONF_GIGYA_URL from renault_api.const import CONF_KAMEREON_APIKEY from renault_api.const import CONF_KAMEREON_URL -from renault_api.exceptions import RenaultError +from renault_api.exceptions import RenaultException @pytest.fixture @@ -48,7 +48,7 @@ async def test_missing_aiohttp_session() -> None: locale = "invalid" renault_client = RenaultClient() - with pytest.raises(RenaultError) as excinfo: + with pytest.raises(RenaultException) as excinfo: await renault_client.preload_api_keys(locale) assert "aiohttp_session is not set." in str(excinfo) @@ -80,6 +80,6 @@ async def test_preload_invalid_api_keys(renault_client: RenaultClient) -> None: with aioresponses() as mock_aioresponses: mock_aioresponses.get(fake_url, status=404) - with pytest.raises(RenaultError) as excinfo: + with pytest.raises(RenaultException) as excinfo: await renault_client.preload_api_keys(fake_locale) assert "Locale not found on Renault server" in str(excinfo) From 5f1d91176df669aead1027d735f25c4d672aa251 Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Tue, 3 Nov 2020 09:02:40 +0100 Subject: [PATCH 07/18] Add LOCALE_BASE_URL for retrieving API keys --- src/renault_api/client.py | 3 ++- src/renault_api/const.py | 3 +++ tests/test_api_keys.py | 3 ++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/renault_api/client.py b/src/renault_api/client.py index 9d271a81..fc83618a 100644 --- a/src/renault_api/client.py +++ b/src/renault_api/client.py @@ -11,6 +11,7 @@ from .const import CONF_GIGYA_URL from .const import CONF_KAMEREON_APIKEY from .const import CONF_KAMEREON_URL +from .const import LOCALE_BASE_URL from .exceptions import RenaultException _LOGGER = logging.getLogger(__package__) @@ -47,7 +48,7 @@ async def preload_api_keys(self, locale: str) -> Dict[str, str]: if self.aiohttp_session is None: raise RenaultException("aiohttp_session is not set.") - url = f"https://renault-wrd-prod-1-euw1-myrapp-one.s3-eu-west-1.amazonaws.com/configuration/android/config_{locale}.json" # noqa + url = f"{LOCALE_BASE_URL}/configuration/android/config_{locale}.json" async with self.aiohttp_session.get(url) as response: try: response.raise_for_status() diff --git a/src/renault_api/const.py b/src/renault_api/const.py index 862dd51a..73526aaf 100644 --- a/src/renault_api/const.py +++ b/src/renault_api/const.py @@ -10,6 +10,9 @@ KAMEREON_URL_EU = "https://api-wired-prod-1-euw1.wrd-aws.com" KAMEREON_URL_US = "https://api-wired-prod-1-usw2.wrd-aws.com" +LOCALE_BASE_URL = ( + "https://renault-wrd-prod-1-euw1-myrapp-one.s3-eu-west-1.amazonaws.com" +) AVAILABLE_LOCALES = { "bg_BG": { diff --git a/tests/test_api_keys.py b/tests/test_api_keys.py index 2dcf5f99..be259717 100644 --- a/tests/test_api_keys.py +++ b/tests/test_api_keys.py @@ -11,6 +11,7 @@ from renault_api.const import CONF_GIGYA_URL from renault_api.const import CONF_KAMEREON_APIKEY from renault_api.const import CONF_KAMEREON_URL +from renault_api.const import LOCALE_BASE_URL from renault_api.exceptions import RenaultException @@ -59,7 +60,7 @@ async def test_preload_unknown_api_keys(renault_client: RenaultClient) -> None: expected_api_keys = AVAILABLE_LOCALES["fr_FR"] fake_locale = "invalid" - fake_url = f"https://renault-wrd-prod-1-euw1-myrapp-one.s3-eu-west-1.amazonaws.com/configuration/android/config_{fake_locale}.json" # noqa + fake_url = f"{LOCALE_BASE_URL}/configuration/android/config_{fake_locale}.json" with open("tests/fixtures/config_sample.txt", "r") as f: fake_body = f.read() From 4a1b03e6f517c6f558d6e279b675ad2dfcde6244 Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Tue, 3 Nov 2020 10:04:28 +0100 Subject: [PATCH 08/18] Add ability to bypass AVAILABLE_LOCALES --- src/renault_api/client.py | 12 ++++++-- src/renault_api/helpers.py | 62 ++++++++++++++++++++++++++++++++++++++ tests/test_api_keys.py | 20 ++++++++++++ 3 files changed, 91 insertions(+), 3 deletions(-) create mode 100644 src/renault_api/helpers.py diff --git a/src/renault_api/client.py b/src/renault_api/client.py index fc83618a..ee4bfe61 100644 --- a/src/renault_api/client.py +++ b/src/renault_api/client.py @@ -24,11 +24,14 @@ def __init__(self) -> None: """Initialise Renault Client.""" self.aiohttp_session: Optional[aiohttp.ClientSession] = None - async def preload_api_keys(self, locale: str) -> Dict[str, str]: + async def preload_api_keys( + self, locale: str, force_load: bool = False + ) -> Dict[str, str]: """Load the credential store with API Keys. Args: locale (str): locale code (preferrably from AVAILABLE_LOCALES.keys()). + force_load (bool): bypass internal AVAILABLE_LOCALES Returns: Dict with gigya-api-key, gigya-api-url, @@ -37,11 +40,12 @@ async def preload_api_keys(self, locale: str) -> Dict[str, str]: Raises: RenaultException: an issue occured loading the API keys """ - if locale in AVAILABLE_LOCALES.keys(): + if locale in AVAILABLE_LOCALES.keys() and not force_load: return AVAILABLE_LOCALES[locale] else: _LOGGER.warning( - "Locale %s was not found in AVAILABLE_LOCALES. " + "Locale %s was not found in AVAILABLE_LOCALES " + "(or force_load used)." "Attempting to load details from Renault servers.", locale, ) @@ -56,6 +60,8 @@ async def preload_api_keys(self, locale: str) -> Dict[str, str]: raise RenaultException( f"Locale not found on Renault server ({exc.status})." ) from exc + # Server sometimes returns invalid content-type + # eg. application/octet-stream response_body = await response.json(content_type=None) _LOGGER.debug( diff --git a/src/renault_api/helpers.py b/src/renault_api/helpers.py new file mode 100644 index 00000000..9cb1d1e6 --- /dev/null +++ b/src/renault_api/helpers.py @@ -0,0 +1,62 @@ +"""Helpers for Renault API.""" +import asyncio +import functools + +from aiohttp import ClientSession + + +def create_aiohttp_closed_event( + session: ClientSession, +) -> asyncio.Event: # pragma: no cover + """Work around aiohttp issue that doesn't properly close transports on exit. + + See https://github.com/aio-libs/aiohttp/issues/1925#issuecomment-639080209 + + Args: + session (ClientSession): session for which to generate the event. + + Returns: + An event that will be set once all transports have been properly closed. + """ + transports = 0 + all_is_lost = asyncio.Event() + + def connection_lost(exc, orig_lost): # type: ignore + nonlocal transports + + try: + orig_lost(exc) + finally: + transports -= 1 + if transports == 0: + all_is_lost.set() + + def eof_received(orig_eof_received): # type: ignore + try: + orig_eof_received() + except AttributeError: + # It may happen that eof_received() is called after + # _app_protocol and _transport are set to None. + pass + + for conn in session.connector._conns.values(): # type: ignore + for handler, _ in conn: + proto = getattr(handler.transport, "_ssl_protocol", None) + if proto is None: + continue + + transports += 1 + orig_lost = proto.connection_lost + orig_eof_received = proto.eof_received + + proto.connection_lost = functools.partial( + connection_lost, orig_lost=orig_lost + ) + proto.eof_received = functools.partial( + eof_received, orig_eof_received=orig_eof_received + ) + + if transports == 0: + all_is_lost.set() + + return all_is_lost diff --git a/tests/test_api_keys.py b/tests/test_api_keys.py index be259717..7006b256 100644 --- a/tests/test_api_keys.py +++ b/tests/test_api_keys.py @@ -13,17 +13,23 @@ from renault_api.const import CONF_KAMEREON_URL from renault_api.const import LOCALE_BASE_URL from renault_api.exceptions import RenaultException +from renault_api.helpers import create_aiohttp_closed_event @pytest.fixture async def renault_client() -> AsyncGenerator[RenaultClient, None]: """Fixture for testing RenaultClient.""" async with ClientSession() as aiohttp_session: + closed_event = create_aiohttp_closed_event(aiohttp_session) + client = RenaultClient() client.aiohttp_session = aiohttp_session yield client + await aiohttp_session.close() + await closed_event.wait() + @pytest.mark.asyncio @pytest.mark.parametrize("locale", AVAILABLE_LOCALES.keys()) @@ -54,6 +60,20 @@ async def test_missing_aiohttp_session() -> None: assert "aiohttp_session is not set." in str(excinfo) +@pytest.mark.asyncio +@pytest.mark.parametrize("locale", AVAILABLE_LOCALES.keys()) +@pytest.mark.skip(reason="Makes real calls to Renault servers") +async def test_preload_force_api_keys( + renault_client: RenaultClient, locale: str +) -> None: + """Ensure is able to parse a known known.""" + expected_api_keys = AVAILABLE_LOCALES[locale] + + api_keys = await renault_client.preload_api_keys(locale, True) + + assert api_keys == expected_api_keys + + @pytest.mark.asyncio async def test_preload_unknown_api_keys(renault_client: RenaultClient) -> None: """Ensure is able to parse a known known.""" From cbbbf7f5d38e48e4eef86d49269b24e74a1d3b4a Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Tue, 3 Nov 2020 10:13:24 +0100 Subject: [PATCH 09/18] Downgrade aiohttp dependency to align with HA --- poetry.lock | 76 +++++++++++++++++++++++++------------------------- pyproject.toml | 3 +- 2 files changed, 39 insertions(+), 40 deletions(-) diff --git a/poetry.lock b/poetry.lock index 5864b710..bdded632 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,6 +1,6 @@ [[package]] name = "aiohttp" -version = "3.7.2" +version = "3.7.1" description = "Async http client/server framework (asyncio)" category = "main" optional = false @@ -342,7 +342,7 @@ gitdb = ">=4.0.1,<5" [[package]] name = "identify" -version = "1.5.6" +version = "1.5.7" description = "File identification library for Python" category = "dev" optional = false @@ -1046,43 +1046,43 @@ testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake [metadata] lock-version = "1.1" python-versions = "^3.7.1" -content-hash = "95d167fa6a2b7e92155f9b1efd60ac26afb7aa7320593b9856c5894d94fd4524" +content-hash = "2cb473cd3031ba76eb54f7ec3da76c4e19335125d01816cceac5617dff118a65" [metadata.files] aiohttp = [ - {file = "aiohttp-3.7.2-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:0989ff15834a4503056d103077ec3652f9ea5699835e1ceaee46b91cf59830bf"}, - {file = "aiohttp-3.7.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:8fbeeb2296bb9fe16071a674eadade7391be785ae0049610e64b60ead6abcdd7"}, - {file = "aiohttp-3.7.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:48104c883099c0e614c5c38f98c1d174a2c68f52f58b2a6e5a07b59df78262ab"}, - {file = "aiohttp-3.7.2-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:c9a415f4f2764ab6c7d63ee6b86f02a46b4df9bc11b0de7ffef206908b7bf0b4"}, - {file = "aiohttp-3.7.2-cp36-cp36m-manylinux2014_ppc64le.whl", hash = "sha256:7e26712871ebaf55497a60f55483dc5e74326d1fb0bfceab86ebaeaa3a266733"}, - {file = "aiohttp-3.7.2-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:8319a55de469d5af3517dfe1f6a77f248f6668c5a552396635ef900f058882ef"}, - {file = "aiohttp-3.7.2-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:2aea79734ac5ceeac1ec22b4af4efb4efd6a5ca3d73d77ec74ed782cf318f238"}, - {file = "aiohttp-3.7.2-cp36-cp36m-win_amd64.whl", hash = "sha256:be9fa3fe94fc95e9bf84e84117a577c892906dd3cb0a95a7ae21e12a84777567"}, - {file = "aiohttp-3.7.2-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:f04dcbf6af1868048a9b4754b1684c669252aa2419aa67266efbcaaead42ced7"}, - {file = "aiohttp-3.7.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:2e886611b100c8c93b753b457e645c5e4b8008ec443434d2a480e5a2bb3e6514"}, - {file = "aiohttp-3.7.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:cdbb65c361ff790c424365a83a496fc8dd1983689a5fb7c6852a9a3ff1710c61"}, - {file = "aiohttp-3.7.2-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:8a8addd41320637c1445fea0bae1fd9fe4888acc2cd79217ee33e5d1c83cfe01"}, - {file = "aiohttp-3.7.2-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:b822bf7b764283b5015e3c49b7bb93f37fc03545f4abe26383771c6b1c813436"}, - {file = "aiohttp-3.7.2-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:ad5c3559e3cd64f746df43fa498038c91aa14f5d7615941ea5b106e435f3b892"}, - {file = "aiohttp-3.7.2-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:835bd35e14e4f36414e47c195e6645449a0a1c3fd5eeae4b7f22cb4c5e4f503a"}, - {file = "aiohttp-3.7.2-cp37-cp37m-win_amd64.whl", hash = "sha256:11e087c316e933f1f52f3d4a09ce13f15ad966fc43df47f44ca4e8067b6a2e0d"}, - {file = "aiohttp-3.7.2-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:f8c583c31c6e790dc003d9d574e3ed2c5b337947722965096c4d684e4f183570"}, - {file = "aiohttp-3.7.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:b84cef790cb93cec82a468b7d2447bf16e3056d2237b652e80f57d653b61da88"}, - {file = "aiohttp-3.7.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:4afd8002d9238e5e93acf1a8baa38b3ddf1f7f0ebef174374131ff0c6c2d7973"}, - {file = "aiohttp-3.7.2-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:a1f1cc11c9856bfa7f1ca55002c39070bde2a97ce48ef631468e99e2ac8e3fe6"}, - {file = "aiohttp-3.7.2-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:7f1aeb72f14b9254296cdefa029c00d3c4550a26e1059084f2ee10d22086c2d0"}, - {file = "aiohttp-3.7.2-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:67f8564c534d75c1d613186939cee45a124d7d37e7aece83b17d18af665b0d7a"}, - {file = "aiohttp-3.7.2-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:184ead67248274f0e20b0cd6bb5f25209b2fad56e5373101cc0137c32c825c87"}, - {file = "aiohttp-3.7.2-cp38-cp38-win_amd64.whl", hash = "sha256:6e0d1231a626d07b23f6fe904caa44efb249da4222d8a16ab039fb2348722292"}, - {file = "aiohttp-3.7.2-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:476b1f8216e59a3c2ffb71b8d7e1da60304da19f6000d422bacc371abb0fc43d"}, - {file = "aiohttp-3.7.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:89c1aa729953b5ac6ca3c82dcbd83e7cdecfa5cf9792c78c154a642e6e29303d"}, - {file = "aiohttp-3.7.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:c53f1d2bd48f5f407b534732f5b3c6b800a58e70b53808637848d8a9ee127fe7"}, - {file = "aiohttp-3.7.2-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:06efdb01ab71ec20786b592d510d1d354fbe0b2e4449ee47067b9ca65d45a006"}, - {file = "aiohttp-3.7.2-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:027be45c4b37e21be81d07ae5242361d73eebad1562c033f80032f955f34df82"}, - {file = "aiohttp-3.7.2-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:1c36b7ef47cfbc150314c2204cd73613d96d6d0982d41c7679b7cdcf43c0e979"}, - {file = "aiohttp-3.7.2-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:c588a0f824dc7158be9eec1ff465d1c868ad69a4dc518cd098cc11e4f7da09d9"}, - {file = "aiohttp-3.7.2-cp39-cp39-win_amd64.whl", hash = "sha256:547b196a7177511da4f475fc81d0bb88a51a8d535c7444bbf2338b6dc82cb996"}, - {file = "aiohttp-3.7.2.tar.gz", hash = "sha256:c6da1af59841e6d43255d386a2c4bfb59c0a3b262bdb24325cc969d211be6070"}, + {file = "aiohttp-3.7.1-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:6072fd5b635b276071c2eda77931adb6254a6271645a260c63f7dd4a0872b04b"}, + {file = "aiohttp-3.7.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:fb7d473b5faa75341f4acb659267d16f300ebd28a7575b5c58cc467bfabb0fd4"}, + {file = "aiohttp-3.7.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:729deb9d0f56211ea4657c7d20ab134c0403173308d9ba21debe20d35a37302c"}, + {file = "aiohttp-3.7.1-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:00f258b8b1e40f87358095ef62ec0547df3f1bd30ce228af98ffe5aad4aaf864"}, + {file = "aiohttp-3.7.1-cp36-cp36m-manylinux2014_ppc64le.whl", hash = "sha256:00496dc15c3dd921218664b7aa55405d9032cb9523ccf812835ffc5e229d4b8e"}, + {file = "aiohttp-3.7.1-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:af8470ed2420dc9d6edcbc255204edbf3d3ba9eaa94bc1c3a470e328722a0fa2"}, + {file = "aiohttp-3.7.1-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:6c971a9728957df5e1cd7dda3a557382ca965f7d8d038f901c7c60fc502b9245"}, + {file = "aiohttp-3.7.1-cp36-cp36m-win_amd64.whl", hash = "sha256:52ba0350c03814f30156f65c76a303275fb616e81e70e345b066c761280f6762"}, + {file = "aiohttp-3.7.1-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:910b1f98412690341aaa73ae70ee185da0dbd6768de7b89c5b6c805119eff4a3"}, + {file = "aiohttp-3.7.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:1daa3fe52f632c51b064804a23df40bd1089e337b131f29b4bde2968ad414ed8"}, + {file = "aiohttp-3.7.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:4f9395802ca6d133e5106f4d328949fcb22c3f5ee65e87c1e586d5f5952d3397"}, + {file = "aiohttp-3.7.1-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:a04dc48f0117089860200847f24862ac084e0f25454c7507b40ce2715f92197b"}, + {file = "aiohttp-3.7.1-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:4fbe2e7642f9c78474cc5819420b77fc20de2114e0139838332b428aa14e1e07"}, + {file = "aiohttp-3.7.1-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:9e3ad780feccf411c300705dd56226bdbc991ee260138bd1b5059a4674176513"}, + {file = "aiohttp-3.7.1-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:1b328022c11531b174281736a20e464d7c9ca390232f1b2cca6f77074c438859"}, + {file = "aiohttp-3.7.1-cp37-cp37m-win_amd64.whl", hash = "sha256:628c9f2a590a0be02967ce014255868e8e6dc780649677ab43f87f8c3114e89d"}, + {file = "aiohttp-3.7.1-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:a6fa0dea87eec5179e4dc8974d8f20385ed030df272c64b2db75db62be3f3dd7"}, + {file = "aiohttp-3.7.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e51141d86d19c641c1c52f04095a8af5bf1208182b3a0bc16144bce050d3f8f5"}, + {file = "aiohttp-3.7.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:d6ec3d2c49353756f781111c0c2024ae422ba2338bf179940c298d4099fda277"}, + {file = "aiohttp-3.7.1-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:21d6b65bb3e14e82d358fa2d7ed193d1dae6592b79525ce484e58a65fcfb57c9"}, + {file = "aiohttp-3.7.1-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:4c6f3a389b8d6509a8d7b6639ec8bd50418a5a81e821f38ddec0d9226e4998b6"}, + {file = "aiohttp-3.7.1-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:26c1264409ca2d76b57ead2f5c2d22cb4510682f35e449c3a3afa98d4a7be462"}, + {file = "aiohttp-3.7.1-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:4d14d823e8c017be21e740d169bd9142fdfc8cc124954787e1e6336dbe1b8612"}, + {file = "aiohttp-3.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:85dbf57ca00a4b01e4a31bd27971e420984ce9075cf462dd02d6c0c9b537e29c"}, + {file = "aiohttp-3.7.1-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:96ce3cd77e0fa4ad3c579346d9796b837a58a094881b22e974b6c3df98cf8e4a"}, + {file = "aiohttp-3.7.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:c49905707caf50a516e407c6e0381f45d76781b1ee1f5ecde2a624961768f2fd"}, + {file = "aiohttp-3.7.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:08dabb185c6af8b741c315c0f871ea63267f3b3f835e77743f9270c44a3b422c"}, + {file = "aiohttp-3.7.1-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:db38a398227b3faac6bf8e6da806a2a4d2cbc3dbd0aa8b9f76e5624539a756db"}, + {file = "aiohttp-3.7.1-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:27dce131d4283a30045c7af5ae9faf07f2bdaa89d845bd3b9a3d3dabc730f06f"}, + {file = "aiohttp-3.7.1-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:a86c99e7bca0909942adc51411e57d15ef64604cc0f4ecf3bf0a24a634264f3e"}, + {file = "aiohttp-3.7.1-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:38768355d2f430b32b6013b5a274d74458f65db618c4f4721cd24db4586acf10"}, + {file = "aiohttp-3.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:8d194780edba342302472ae7caf6397293128f906e5e64bd3fe209462ff9e1c1"}, + {file = "aiohttp-3.7.1.tar.gz", hash = "sha256:04f9d70f6c4d089be5068d7df6281e638f6820d4f1b1ec3dc012b0b43fa997d2"}, ] aioresponses = [ {file = "aioresponses-0.7.1-py2.py3-none-any.whl", hash = "sha256:88eeb32256ef0af57450647277d3118ce8005682f06f27b23c5e2f8fcc0384b9"}, @@ -1234,8 +1234,8 @@ gitpython = [ {file = "GitPython-3.1.11.tar.gz", hash = "sha256:befa4d101f91bad1b632df4308ec64555db684c360bd7d2130b4807d49ce86b8"}, ] identify = [ - {file = "identify-1.5.6-py2.py3-none-any.whl", hash = "sha256:3139bf72d81dfd785b0a464e2776bd59bdc725b4cc10e6cf46b56a0db931c82e"}, - {file = "identify-1.5.6.tar.gz", hash = "sha256:969d844b7a85d32a5f9ac4e163df6e846d73c87c8b75847494ee8f4bd2186421"}, + {file = "identify-1.5.7-py2.py3-none-any.whl", hash = "sha256:e3c822614168c9ac248f4258ffe43092debceb45e299a07b8f2fb168ba875605"}, + {file = "identify-1.5.7.tar.gz", hash = "sha256:b505f7658afbddc11556de5ff9a5a52eed81b9a380f8ff77b7dd9781cfee6884"}, ] idna = [ {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, diff --git a/pyproject.toml b/pyproject.toml index cd464490..ab172bfc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,6 @@ homepage = "https://github.com/hacf-fr/renault-api" repository = "https://github.com/hacf-fr/renault-api" documentation = "https://renault-api.readthedocs.io" classifiers = [ - "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", @@ -21,7 +20,7 @@ Changelog = "https://github.com/hacf-fr/renault-api/releases" [tool.poetry.dependencies] python = "^3.7.1" click = "^7.0" -aiohttp = "^3.7.2" +aiohttp = "3.7.1" typing-extensions = "^3.7.4" [tool.poetry.dev-dependencies] From e5e3ad777cbc173264fa4c6218d0ff72d2921b50 Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Tue, 3 Nov 2020 10:33:38 +0100 Subject: [PATCH 10/18] Move typing-extensions to dev dependencies --- poetry.lock | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/poetry.lock b/poetry.lock index bdded632..007337e4 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1046,7 +1046,7 @@ testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake [metadata] lock-version = "1.1" python-versions = "^3.7.1" -content-hash = "2cb473cd3031ba76eb54f7ec3da76c4e19335125d01816cceac5617dff118a65" +content-hash = "a1eba52e7a8996810dd6c9900d200e058b93e8f11681adcac5f6e6724204f4bb" [metadata.files] aiohttp = [ diff --git a/pyproject.toml b/pyproject.toml index ab172bfc..e28bcf94 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,7 +21,6 @@ Changelog = "https://github.com/hacf-fr/renault-api/releases" python = "^3.7.1" click = "^7.0" aiohttp = "3.7.1" -typing-extensions = "^3.7.4" [tool.poetry.dev-dependencies] pytest = "^6.1.2" @@ -48,6 +47,7 @@ sphinx-click = "^2.5.0" Pygments = "^2.7.2" pytest-asyncio = "^0.14.0" aioresponses = "^0.7.1" +typing-extensions = "^3.7.4" [tool.poetry.scripts] renault-api = "renault_api.__main__:main" From 9011d478005e083978b8968b02692f9fb220c2ea Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Tue, 3 Nov 2020 10:58:59 +0100 Subject: [PATCH 11/18] Remove pytest-asyncio and aioresponses from noxfile.py (mypy session) --- noxfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/noxfile.py b/noxfile.py index d0bc0397..60874075 100644 --- a/noxfile.py +++ b/noxfile.py @@ -108,7 +108,7 @@ def mypy(session: Session) -> None: """Type-check using mypy.""" args = session.posargs or ["src", "tests", "docs/conf.py"] session.install(".") - session.install("mypy", "pytest", "pytest-asyncio", "aioresponses") + session.install("mypy", "pytest") session.run("mypy", *args) if not session.posargs: session.run("mypy", f"--python-executable={sys.executable}", "noxfile.py") From e4b5be7d3f3bfc2340f0796049bf0cb2b0984dd3 Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Tue, 3 Nov 2020 17:36:45 +0100 Subject: [PATCH 12/18] Set initial prerelease version --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index e28bcf94..12ccaf7e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "renault-api" -version = "0.0.0" +version = "0.0.1-alpha.0" description = "Renault API" authors = ["epenet "] license = "MIT" From 2b87b3667c76e5d07b11b9862e14a698d72a9960 Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Tue, 3 Nov 2020 22:32:36 +0100 Subject: [PATCH 13/18] Move get_api_keys to helpers module --- src/renault_api/client.py | 69 -------------------------------------- src/renault_api/helpers.py | 67 ++++++++++++++++++++++++++++++++++++ tests/test_api_keys.py | 41 +++++++++++----------- 3 files changed, 89 insertions(+), 88 deletions(-) diff --git a/src/renault_api/client.py b/src/renault_api/client.py index ee4bfe61..26ad4d6d 100644 --- a/src/renault_api/client.py +++ b/src/renault_api/client.py @@ -1,20 +1,4 @@ """Client for Renault API.""" -import logging -from typing import Dict -from typing import Optional - -import aiohttp -from aiohttp.client_exceptions import ClientResponseError - -from .const import AVAILABLE_LOCALES -from .const import CONF_GIGYA_APIKEY -from .const import CONF_GIGYA_URL -from .const import CONF_KAMEREON_APIKEY -from .const import CONF_KAMEREON_URL -from .const import LOCALE_BASE_URL -from .exceptions import RenaultException - -_LOGGER = logging.getLogger(__package__) class RenaultClient: @@ -22,56 +6,3 @@ class RenaultClient: def __init__(self) -> None: """Initialise Renault Client.""" - self.aiohttp_session: Optional[aiohttp.ClientSession] = None - - async def preload_api_keys( - self, locale: str, force_load: bool = False - ) -> Dict[str, str]: - """Load the credential store with API Keys. - - Args: - locale (str): locale code (preferrably from AVAILABLE_LOCALES.keys()). - force_load (bool): bypass internal AVAILABLE_LOCALES - - Returns: - Dict with gigya-api-key, gigya-api-url, - kamereon-api-key and kamereon-api-url - - Raises: - RenaultException: an issue occured loading the API keys - """ - if locale in AVAILABLE_LOCALES.keys() and not force_load: - return AVAILABLE_LOCALES[locale] - else: - _LOGGER.warning( - "Locale %s was not found in AVAILABLE_LOCALES " - "(or force_load used)." - "Attempting to load details from Renault servers.", - locale, - ) - if self.aiohttp_session is None: - raise RenaultException("aiohttp_session is not set.") - - url = f"{LOCALE_BASE_URL}/configuration/android/config_{locale}.json" - async with self.aiohttp_session.get(url) as response: - try: - response.raise_for_status() - except ClientResponseError as exc: - raise RenaultException( - f"Locale not found on Renault server ({exc.status})." - ) from exc - # Server sometimes returns invalid content-type - # eg. application/octet-stream - response_body = await response.json(content_type=None) - - _LOGGER.debug( - "Received api keys from myrenault response: %s", response_body - ) - - servers = response_body["servers"] - return { - CONF_GIGYA_APIKEY: servers["gigyaProd"]["apikey"], - CONF_GIGYA_URL: servers["gigyaProd"]["target"], - CONF_KAMEREON_APIKEY: servers["wiredProd"]["apikey"], - CONF_KAMEREON_URL: servers["wiredProd"]["target"], - } diff --git a/src/renault_api/helpers.py b/src/renault_api/helpers.py index 9cb1d1e6..bc0d8efd 100644 --- a/src/renault_api/helpers.py +++ b/src/renault_api/helpers.py @@ -1,8 +1,75 @@ """Helpers for Renault API.""" import asyncio import functools +import logging +from typing import Dict from aiohttp import ClientSession +from aiohttp.client_exceptions import ClientResponseError + +from .const import AVAILABLE_LOCALES +from .const import CONF_GIGYA_APIKEY +from .const import CONF_GIGYA_URL +from .const import CONF_KAMEREON_APIKEY +from .const import CONF_KAMEREON_URL +from .const import LOCALE_BASE_URL +from .exceptions import RenaultException + +_LOGGER = logging.getLogger(__package__) + + +async def get_api_keys( + locale: str, force_load: bool = False, aiohttp_session: ClientSession = None +) -> Dict[str, str]: + """Get the API keys for specified locale. + + Args: + locale (str): locale code (preferrably from AVAILABLE_LOCALES.keys()) + force_load (bool): bypass internal AVAILABLE_LOCALES + aiohttp_session (ClientSession): required if locale not in AVAILABLE_LOCALES + + Returns: + Dict with gigya-api-key, gigya-api-url, + kamereon-api-key and kamereon-api-url + + Raises: + RenaultException: an issue occured loading the API keys + """ + if locale in AVAILABLE_LOCALES.keys() and not force_load: + return AVAILABLE_LOCALES[locale] + else: + _LOGGER.warning( + "Locale %s was not found in AVAILABLE_LOCALES " + "(or force_load used)." + "Attempting to load details from Renault servers.", + locale, + ) + if aiohttp_session is None: + raise RenaultException("aiohttp_session is not set.") + + url = f"{LOCALE_BASE_URL}/configuration/android/config_{locale}.json" + async with aiohttp_session.get(url) as response: + try: + response.raise_for_status() + except ClientResponseError as exc: + raise RenaultException( + f"Locale not found on Renault server ({exc.status})." + ) from exc + # Server sometimes returns invalid content-type + # eg. application/octet-stream + response_body = await response.json(content_type=None) + + _LOGGER.debug( + "Received api keys from myrenault response: %s", response_body + ) + + servers = response_body["servers"] + return { + CONF_GIGYA_APIKEY: servers["gigyaProd"]["apikey"], + CONF_GIGYA_URL: servers["gigyaProd"]["target"], + CONF_KAMEREON_APIKEY: servers["wiredProd"]["apikey"], + CONF_KAMEREON_URL: servers["wiredProd"]["target"], + } def create_aiohttp_closed_event( diff --git a/tests/test_api_keys.py b/tests/test_api_keys.py index 7006b256..8dd069d3 100644 --- a/tests/test_api_keys.py +++ b/tests/test_api_keys.py @@ -14,19 +14,24 @@ from renault_api.const import LOCALE_BASE_URL from renault_api.exceptions import RenaultException from renault_api.helpers import create_aiohttp_closed_event +from renault_api.helpers import get_api_keys @pytest.fixture -async def renault_client() -> AsyncGenerator[RenaultClient, None]: +def renault_client(aiohttp_session: ClientSession) -> RenaultClient: """Fixture for testing RenaultClient.""" - async with ClientSession() as aiohttp_session: - closed_event = create_aiohttp_closed_event(aiohttp_session) + client = RenaultClient() + client.aiohttp_session = aiohttp_session + return client - client = RenaultClient() - client.aiohttp_session = aiohttp_session - yield client +@pytest.fixture +async def aiohttp_session() -> AsyncGenerator[ClientSession, None]: + """Fixture for generating ClientSession.""" + async with ClientSession() as aiohttp_session: + yield aiohttp_session + closed_event = create_aiohttp_closed_event(aiohttp_session) await aiohttp_session.close() await closed_event.wait() @@ -37,8 +42,7 @@ async def test_available_locales(locale: str) -> None: """Ensure all items AVAILABLE_LOCALES have correct data.""" expected_api_keys = AVAILABLE_LOCALES[locale] - renault_client = RenaultClient() - api_keys = await renault_client.preload_api_keys(locale) + api_keys = await get_api_keys(locale) assert api_keys == expected_api_keys for key in [ CONF_GIGYA_APIKEY, @@ -51,12 +55,11 @@ async def test_available_locales(locale: str) -> None: @pytest.mark.asyncio async def test_missing_aiohttp_session() -> None: - """Ensure is able to parse a known known.""" + """Ensure failure to unknown locale if aiohttp_session is not set.""" locale = "invalid" - renault_client = RenaultClient() with pytest.raises(RenaultException) as excinfo: - await renault_client.preload_api_keys(locale) + await get_api_keys(locale) assert "aiohttp_session is not set." in str(excinfo) @@ -64,18 +67,18 @@ async def test_missing_aiohttp_session() -> None: @pytest.mark.parametrize("locale", AVAILABLE_LOCALES.keys()) @pytest.mark.skip(reason="Makes real calls to Renault servers") async def test_preload_force_api_keys( - renault_client: RenaultClient, locale: str + aiohttp_session: ClientSession, locale: str ) -> None: - """Ensure is able to parse a known known.""" + """Ensure is able to parse a valid locale from Renault servers.""" expected_api_keys = AVAILABLE_LOCALES[locale] - api_keys = await renault_client.preload_api_keys(locale, True) + api_keys = await get_api_keys(locale, True, aiohttp_session) assert api_keys == expected_api_keys @pytest.mark.asyncio -async def test_preload_unknown_api_keys(renault_client: RenaultClient) -> None: +async def test_preload_unknown_api_keys(aiohttp_session: ClientSession) -> None: """Ensure is able to parse a known known.""" expected_api_keys = AVAILABLE_LOCALES["fr_FR"] @@ -87,20 +90,20 @@ async def test_preload_unknown_api_keys(renault_client: RenaultClient) -> None: with aioresponses() as mock_aioresponses: mock_aioresponses.get(fake_url, status=200, body=fake_body) - api_keys = await renault_client.preload_api_keys(fake_locale) + api_keys = await get_api_keys(fake_locale, aiohttp_session=aiohttp_session) assert api_keys == expected_api_keys @pytest.mark.asyncio -async def test_preload_invalid_api_keys(renault_client: RenaultClient) -> None: +async def test_preload_invalid_api_keys(aiohttp_session: ClientSession) -> None: """Ensure is able to parse an invalid locale.""" fake_locale = "fake" - fake_url = f"https://renault-wrd-prod-1-euw1-myrapp-one.s3-eu-west-1.amazonaws.com/configuration/android/config_{fake_locale}.json" # noqa + fake_url = f"{LOCALE_BASE_URL}/configuration/android/config_{fake_locale}.json" with aioresponses() as mock_aioresponses: mock_aioresponses.get(fake_url, status=404) with pytest.raises(RenaultException) as excinfo: - await renault_client.preload_api_keys(fake_locale) + await get_api_keys(fake_locale, aiohttp_session=aiohttp_session) assert "Locale not found on Renault server" in str(excinfo) From 1a8ab3fbd96b615d625be8091e0f5045c34f5f3b Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Wed, 4 Nov 2020 10:19:13 +0100 Subject: [PATCH 14/18] Fix tests --- tests/test_api_keys.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_api_keys.py b/tests/test_api_keys.py index 8dd069d3..ddc2f989 100644 --- a/tests/test_api_keys.py +++ b/tests/test_api_keys.py @@ -21,7 +21,6 @@ def renault_client(aiohttp_session: ClientSession) -> RenaultClient: """Fixture for testing RenaultClient.""" client = RenaultClient() - client.aiohttp_session = aiohttp_session return client From 855c75bb9a8560f3dcd1588df0944f1fb502204c Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Wed, 4 Nov 2020 11:00:36 +0100 Subject: [PATCH 15/18] Update poetry.lock using poetry 1.0.10 --- poetry.lock | 651 ++++++++++++++++++++++++++----------------------- pyproject.toml | 1 - 2 files changed, 346 insertions(+), 306 deletions(-) diff --git a/poetry.lock b/poetry.lock index 007337e4..ea893b00 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,10 +1,10 @@ [[package]] -name = "aiohttp" -version = "3.7.1" -description = "Async http client/server framework (asyncio)" category = "main" +description = "Async http client/server framework (asyncio)" +name = "aiohttp" optional = false python-versions = ">=3.6" +version = "3.7.1" [package.dependencies] async-timeout = ">=3.0,<4.0" @@ -18,106 +18,107 @@ yarl = ">=1.0,<2.0" speedups = ["aiodns", "brotlipy", "cchardet"] [[package]] -name = "aioresponses" -version = "0.7.1" -description = "Mock out requests made by ClientSession from aiohttp package" category = "dev" +description = "Mock out requests made by ClientSession from aiohttp package" +name = "aioresponses" optional = false python-versions = "*" +version = "0.7.1" [package.dependencies] aiohttp = ">=2.0.0,<4.0.0" [[package]] -name = "alabaster" -version = "0.7.12" -description = "A configurable sidebar-enabled Sphinx theme" category = "dev" +description = "A configurable sidebar-enabled Sphinx theme" +name = "alabaster" optional = false python-versions = "*" +version = "0.7.12" [[package]] -name = "appdirs" -version = "1.4.4" -description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" +description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +name = "appdirs" optional = false python-versions = "*" +version = "1.4.4" [[package]] -name = "aspy.refactor-imports" -version = "2.1.1" -description = "Utilities for refactoring imports in python-like syntax." category = "dev" +description = "Utilities for refactoring imports in python-like syntax." +name = "aspy.refactor-imports" optional = false python-versions = ">=3.6.1" +version = "2.1.1" [package.dependencies] cached-property = "*" [[package]] -name = "async-timeout" -version = "3.0.1" -description = "Timeout context manager for asyncio programs" category = "main" +description = "Timeout context manager for asyncio programs" +name = "async-timeout" optional = false python-versions = ">=3.5.3" +version = "3.0.1" [[package]] -name = "atomicwrites" -version = "1.4.0" -description = "Atomic file writes." category = "dev" +description = "Atomic file writes." +marker = "sys_platform == \"win32\"" +name = "atomicwrites" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "1.4.0" [[package]] -name = "attrs" -version = "20.2.0" -description = "Classes Without Boilerplate" category = "main" +description = "Classes Without Boilerplate" +name = "attrs" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "20.2.0" [package.extras] -dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "sphinx-rtd-theme", "pre-commit"] +dev = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "sphinx-rtd-theme", "pre-commit"] docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"] -tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] -tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"] +tests = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] +tests_no_zope = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"] [[package]] -name = "babel" -version = "2.8.0" -description = "Internationalization utilities" category = "dev" +description = "Internationalization utilities" +name = "babel" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "2.8.0" [package.dependencies] pytz = ">=2015.7" [[package]] -name = "bandit" -version = "1.6.2" -description = "Security oriented static analyser for python code." category = "dev" +description = "Security oriented static analyser for python code." +name = "bandit" optional = false python-versions = "*" +version = "1.6.2" [package.dependencies] -colorama = {version = ">=0.3.9", markers = "platform_system == \"Windows\""} GitPython = ">=1.0.1" PyYAML = ">=3.13" +colorama = ">=0.3.9" six = ">=1.10.0" stevedore = ">=1.20.0" [[package]] -name = "black" -version = "20.8b1" -description = "The uncompromising code formatter." category = "dev" +description = "The uncompromising code formatter." +name = "black" optional = false python-versions = ">=3.6" +version = "20.8b1" [package.dependencies] appdirs = "*" @@ -134,98 +135,101 @@ colorama = ["colorama (>=0.4.3)"] d = ["aiohttp (>=3.3.2)", "aiohttp-cors"] [[package]] -name = "cached-property" -version = "1.5.2" -description = "A decorator for caching properties in classes." category = "dev" +description = "A decorator for caching properties in classes." +name = "cached-property" optional = false python-versions = "*" +version = "1.5.2" [[package]] -name = "certifi" -version = "2020.6.20" -description = "Python package for providing Mozilla's CA Bundle." category = "dev" +description = "Python package for providing Mozilla's CA Bundle." +name = "certifi" optional = false python-versions = "*" +version = "2020.6.20" [[package]] -name = "cfgv" -version = "3.2.0" -description = "Validate configuration and produce human readable error messages." category = "dev" +description = "Validate configuration and produce human readable error messages." +name = "cfgv" optional = false python-versions = ">=3.6.1" +version = "3.2.0" [[package]] -name = "chardet" -version = "3.0.4" -description = "Universal encoding detector for Python 2 and 3" category = "main" +description = "Universal encoding detector for Python 2 and 3" +name = "chardet" optional = false python-versions = "*" +version = "3.0.4" [[package]] -name = "click" -version = "7.1.2" -description = "Composable command line interface toolkit" category = "main" +description = "Composable command line interface toolkit" +name = "click" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "7.1.2" [[package]] -name = "colorama" -version = "0.4.4" -description = "Cross-platform colored terminal text." category = "dev" +description = "Cross-platform colored terminal text." +marker = "platform_system == \"Windows\" or sys_platform == \"win32\" or platform_system == \"Windows\"" +name = "colorama" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "0.4.4" [[package]] -name = "coverage" -version = "5.3" -description = "Code coverage measurement for Python" category = "dev" +description = "Code coverage measurement for Python" +name = "coverage" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" +version = "5.3" [package.dependencies] -toml = {version = "*", optional = true, markers = "extra == \"toml\""} +[package.dependencies.toml] +optional = true +version = "*" [package.extras] toml = ["toml"] [[package]] -name = "darglint" -version = "1.5.5" -description = "A utility for ensuring Google-style docstrings stay up to date with the source code." category = "dev" +description = "A utility for ensuring Google-style docstrings stay up to date with the source code." +name = "darglint" optional = false python-versions = ">=3.5,<4.0" +version = "1.5.5" [[package]] -name = "distlib" -version = "0.3.1" -description = "Distribution utilities" category = "dev" +description = "Distribution utilities" +name = "distlib" optional = false python-versions = "*" +version = "0.3.1" [[package]] -name = "docutils" -version = "0.16" -description = "Docutils -- Python Documentation Utilities" category = "dev" +description = "Docutils -- Python Documentation Utilities" +name = "docutils" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "0.16" [[package]] -name = "dparse" -version = "0.5.1" -description = "A parser for Python dependency files" category = "dev" +description = "A parser for Python dependency files" +name = "dparse" optional = false python-versions = ">=3.5" +version = "0.5.1" [package.dependencies] packaging = "*" @@ -236,34 +240,37 @@ toml = "*" pipenv = ["pipenv"] [[package]] -name = "filelock" -version = "3.0.12" -description = "A platform independent file lock." category = "dev" +description = "A platform independent file lock." +name = "filelock" optional = false python-versions = "*" +version = "3.0.12" [[package]] -name = "flake8" -version = "3.8.4" -description = "the modular source code checker: pep8 pyflakes and co" category = "dev" +description = "the modular source code checker: pep8 pyflakes and co" +name = "flake8" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +version = "3.8.4" [package.dependencies] -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} mccabe = ">=0.6.0,<0.7.0" pycodestyle = ">=2.6.0a1,<2.7.0" pyflakes = ">=2.2.0,<2.3.0" +[package.dependencies.importlib-metadata] +python = "<3.8" +version = "*" + [[package]] -name = "flake8-bandit" -version = "2.1.2" -description = "Automated security testing with bandit and flake8." category = "dev" +description = "Automated security testing with bandit and flake8." +name = "flake8-bandit" optional = false python-versions = "*" +version = "2.1.2" [package.dependencies] bandit = "*" @@ -272,108 +279,109 @@ flake8-polyfill = "*" pycodestyle = "*" [[package]] -name = "flake8-bugbear" -version = "20.1.4" -description = "A plugin for flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle." category = "dev" +description = "A plugin for flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle." +name = "flake8-bugbear" optional = false python-versions = ">=3.6" +version = "20.1.4" [package.dependencies] attrs = ">=19.2.0" flake8 = ">=3.0.0" [[package]] -name = "flake8-docstrings" -version = "1.5.0" -description = "Extension for flake8 which uses pydocstyle to check docstrings" category = "dev" +description = "Extension for flake8 which uses pydocstyle to check docstrings" +name = "flake8-docstrings" optional = false python-versions = "*" +version = "1.5.0" [package.dependencies] flake8 = ">=3" pydocstyle = ">=2.1" [[package]] -name = "flake8-polyfill" -version = "1.0.2" -description = "Polyfill package for Flake8 plugins" category = "dev" +description = "Polyfill package for Flake8 plugins" +name = "flake8-polyfill" optional = false python-versions = "*" +version = "1.0.2" [package.dependencies] flake8 = "*" [[package]] -name = "flake8-rst-docstrings" -version = "0.0.14" -description = "Python docstring reStructuredText (RST) validator" category = "dev" +description = "Python docstring reStructuredText (RST) validator" +name = "flake8-rst-docstrings" optional = false python-versions = "*" +version = "0.0.14" [package.dependencies] flake8 = ">=3.0.0" restructuredtext_lint = "*" [[package]] -name = "gitdb" -version = "4.0.5" -description = "Git Object Database" category = "dev" +description = "Git Object Database" +name = "gitdb" optional = false python-versions = ">=3.4" +version = "4.0.5" [package.dependencies] smmap = ">=3.0.1,<4" [[package]] -name = "gitpython" -version = "3.1.11" -description = "Python Git Library" category = "dev" +description = "Python Git Library" +name = "gitpython" optional = false python-versions = ">=3.4" +version = "3.1.11" [package.dependencies] gitdb = ">=4.0.1,<5" [[package]] -name = "identify" -version = "1.5.7" -description = "File identification library for Python" category = "dev" +description = "File identification library for Python" +name = "identify" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +version = "1.5.9" [package.extras] license = ["editdistance"] [[package]] -name = "idna" -version = "2.10" -description = "Internationalized Domain Names in Applications (IDNA)" category = "main" +description = "Internationalized Domain Names in Applications (IDNA)" +name = "idna" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "2.10" [[package]] -name = "imagesize" -version = "1.2.0" -description = "Getting image size from png/jpeg/jpeg2000/gif file" category = "dev" +description = "Getting image size from png/jpeg/jpeg2000/gif file" +name = "imagesize" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "1.2.0" [[package]] -name = "importlib-metadata" -version = "2.0.0" -description = "Read metadata from Python packages" category = "dev" +description = "Read metadata from Python packages" +marker = "python_version < \"3.8\"" +name = "importlib-metadata" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +version = "2.0.0" [package.dependencies] zipp = ">=0.5" @@ -383,20 +391,20 @@ docs = ["sphinx", "rst.linker"] testing = ["packaging", "pep517", "importlib-resources (>=1.3)"] [[package]] -name = "iniconfig" -version = "1.1.1" -description = "iniconfig: brain-dead simple config-ini parsing" category = "dev" +description = "iniconfig: brain-dead simple config-ini parsing" +name = "iniconfig" optional = false python-versions = "*" +version = "1.1.1" [[package]] -name = "jinja2" -version = "2.11.2" -description = "A very fast and expressive template engine." category = "dev" +description = "A very fast and expressive template engine." +name = "jinja2" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "2.11.2" [package.dependencies] MarkupSafe = ">=0.23" @@ -405,48 +413,51 @@ MarkupSafe = ">=0.23" i18n = ["Babel (>=0.8)"] [[package]] -name = "livereload" -version = "2.6.3" -description = "Python LiveReload is an awesome tool for web developers" category = "dev" +description = "Python LiveReload is an awesome tool for web developers" +name = "livereload" optional = false python-versions = "*" +version = "2.6.3" [package.dependencies] six = "*" -tornado = {version = "*", markers = "python_version > \"2.7\""} + +[package.dependencies.tornado] +python = ">=2.8" +version = "*" [[package]] -name = "markupsafe" -version = "1.1.1" -description = "Safely add untrusted strings to HTML/XML markup." category = "dev" +description = "Safely add untrusted strings to HTML/XML markup." +name = "markupsafe" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" +version = "1.1.1" [[package]] -name = "mccabe" -version = "0.6.1" -description = "McCabe checker, plugin for flake8" category = "dev" +description = "McCabe checker, plugin for flake8" +name = "mccabe" optional = false python-versions = "*" +version = "0.6.1" [[package]] -name = "multidict" -version = "5.0.0" -description = "multidict implementation" category = "main" +description = "multidict implementation" +name = "multidict" optional = false python-versions = ">=3.5" +version = "5.0.0" [[package]] -name = "mypy" -version = "0.790" -description = "Optional static typing for Python" category = "dev" +description = "Optional static typing for Python" +name = "mypy" optional = false python-versions = ">=3.5" +version = "0.790" [package.dependencies] mypy-extensions = ">=0.4.3,<0.5.0" @@ -457,184 +468,192 @@ typing-extensions = ">=3.7.4" dmypy = ["psutil (>=4.0)"] [[package]] -name = "mypy-extensions" -version = "0.4.3" -description = "Experimental type system extensions for programs checked with the mypy typechecker." category = "dev" +description = "Experimental type system extensions for programs checked with the mypy typechecker." +name = "mypy-extensions" optional = false python-versions = "*" +version = "0.4.3" [[package]] -name = "nodeenv" -version = "1.5.0" -description = "Node.js virtual environment builder" category = "dev" +description = "Node.js virtual environment builder" +name = "nodeenv" optional = false python-versions = "*" +version = "1.5.0" [[package]] -name = "packaging" -version = "20.4" -description = "Core utilities for Python packages" category = "dev" +description = "Core utilities for Python packages" +name = "packaging" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "20.4" [package.dependencies] pyparsing = ">=2.0.2" six = "*" [[package]] -name = "pathspec" -version = "0.8.0" -description = "Utility library for gitignore style pattern matching of file paths." category = "dev" +description = "Utility library for gitignore style pattern matching of file paths." +name = "pathspec" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "0.8.0" [[package]] -name = "pbr" -version = "5.5.1" -description = "Python Build Reasonableness" category = "dev" +description = "Python Build Reasonableness" +name = "pbr" optional = false python-versions = ">=2.6" +version = "5.5.1" [[package]] -name = "pep8-naming" -version = "0.11.1" -description = "Check PEP-8 naming conventions, plugin for flake8" category = "dev" +description = "Check PEP-8 naming conventions, plugin for flake8" +name = "pep8-naming" optional = false python-versions = "*" +version = "0.11.1" [package.dependencies] flake8-polyfill = ">=1.0.2,<2" [[package]] -name = "pluggy" -version = "0.13.1" -description = "plugin and hook calling mechanisms for python" category = "dev" +description = "plugin and hook calling mechanisms for python" +name = "pluggy" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "0.13.1" [package.dependencies] -importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} +[package.dependencies.importlib-metadata] +python = "<3.8" +version = ">=0.12" [package.extras] dev = ["pre-commit", "tox"] [[package]] -name = "pre-commit" -version = "2.8.2" -description = "A framework for managing and maintaining multi-language pre-commit hooks." category = "dev" +description = "A framework for managing and maintaining multi-language pre-commit hooks." +name = "pre-commit" optional = false python-versions = ">=3.6.1" +version = "2.8.2" [package.dependencies] cfgv = ">=2.0.0" identify = ">=1.0.0" -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} nodeenv = ">=0.11.1" pyyaml = ">=5.1" toml = "*" virtualenv = ">=20.0.8" +[package.dependencies.importlib-metadata] +python = "<3.8" +version = "*" + [[package]] -name = "pre-commit-hooks" -version = "3.3.0" -description = "Some out-of-the-box hooks for pre-commit." category = "dev" +description = "Some out-of-the-box hooks for pre-commit." +name = "pre-commit-hooks" optional = false python-versions = ">=3.6.1" +version = "3.3.0" [package.dependencies] "ruamel.yaml" = ">=0.15" toml = "*" [[package]] -name = "py" -version = "1.9.0" -description = "library with cross-python path, ini-parsing, io, code, log facilities" category = "dev" +description = "library with cross-python path, ini-parsing, io, code, log facilities" +name = "py" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "1.9.0" [[package]] -name = "pycodestyle" -version = "2.6.0" -description = "Python style guide checker" category = "dev" +description = "Python style guide checker" +name = "pycodestyle" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "2.6.0" [[package]] -name = "pydocstyle" -version = "5.1.1" -description = "Python docstring style checker" category = "dev" +description = "Python docstring style checker" +name = "pydocstyle" optional = false python-versions = ">=3.5" +version = "5.1.1" [package.dependencies] snowballstemmer = "*" [[package]] -name = "pyflakes" -version = "2.2.0" -description = "passive checker of Python programs" category = "dev" +description = "passive checker of Python programs" +name = "pyflakes" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "2.2.0" [[package]] -name = "pygments" -version = "2.7.2" -description = "Pygments is a syntax highlighting package written in Python." category = "dev" +description = "Pygments is a syntax highlighting package written in Python." +name = "pygments" optional = false python-versions = ">=3.5" +version = "2.7.2" [[package]] -name = "pyparsing" -version = "2.4.7" -description = "Python parsing module" category = "dev" +description = "Python parsing module" +name = "pyparsing" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +version = "2.4.7" [[package]] -name = "pytest" -version = "6.1.2" -description = "pytest: simple powerful testing with Python" category = "dev" +description = "pytest: simple powerful testing with Python" +name = "pytest" optional = false python-versions = ">=3.5" +version = "6.1.2" [package.dependencies] -atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} +atomicwrites = ">=1.0" attrs = ">=17.4.0" -colorama = {version = "*", markers = "sys_platform == \"win32\""} -importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} +colorama = "*" iniconfig = "*" packaging = "*" pluggy = ">=0.12,<1.0" py = ">=1.8.2" toml = "*" +[package.dependencies.importlib-metadata] +python = "<3.8" +version = ">=0.12" + [package.extras] -checkqa_mypy = ["mypy (==0.780)"] +checkqa_mypy = ["mypy (0.780)"] testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] [[package]] -name = "pytest-asyncio" -version = "0.14.0" -description = "Pytest support for asyncio." category = "dev" +description = "Pytest support for asyncio." +name = "pytest-asyncio" optional = false python-versions = ">= 3.5" +version = "0.14.0" [package.dependencies] pytest = ">=5.4.0" @@ -643,47 +662,47 @@ pytest = ">=5.4.0" testing = ["async-generator (>=1.3)", "coverage", "hypothesis (>=5.7.1)"] [[package]] -name = "pytz" -version = "2020.4" -description = "World timezone definitions, modern and historical" category = "dev" +description = "World timezone definitions, modern and historical" +name = "pytz" optional = false python-versions = "*" +version = "2020.4" [[package]] -name = "pyyaml" -version = "5.3.1" -description = "YAML parser and emitter for Python" category = "dev" +description = "YAML parser and emitter for Python" +name = "pyyaml" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "5.3.1" [[package]] -name = "regex" -version = "2020.10.28" -description = "Alternative regular expression module, to replace re." category = "dev" +description = "Alternative regular expression module, to replace re." +name = "regex" optional = false python-versions = "*" +version = "2020.10.28" [[package]] -name = "reorder-python-imports" -version = "2.3.6" -description = "Tool for reordering python imports" category = "dev" +description = "Tool for reordering python imports" +name = "reorder-python-imports" optional = false python-versions = ">=3.6.1" +version = "2.3.6" [package.dependencies] "aspy.refactor-imports" = ">=2.1.0" [[package]] -name = "requests" -version = "2.24.0" -description = "Python HTTP for Humans." category = "dev" +description = "Python HTTP for Humans." +name = "requests" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "2.24.0" [package.dependencies] certifi = ">=2017.4.17" @@ -693,98 +712,103 @@ urllib3 = ">=1.21.1,<1.25.0 || >1.25.0,<1.25.1 || >1.25.1,<1.26" [package.extras] security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"] -socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] +socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7)", "win-inet-pton"] [[package]] -name = "restructuredtext-lint" -version = "1.3.1" -description = "reStructuredText linter" category = "dev" +description = "reStructuredText linter" +name = "restructuredtext-lint" optional = false python-versions = "*" +version = "1.3.1" [package.dependencies] docutils = ">=0.11,<1.0" [[package]] -name = "ruamel.yaml" -version = "0.16.12" -description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order" category = "dev" +description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order" +name = "ruamel.yaml" optional = false python-versions = "*" +version = "0.16.12" [package.dependencies] -"ruamel.yaml.clib" = {version = ">=0.1.2", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.9\""} +[package.dependencies."ruamel.yaml.clib"] +python = "<3.9" +version = ">=0.1.2" [package.extras] docs = ["ryd"] jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"] [[package]] -name = "ruamel.yaml.clib" -version = "0.2.2" -description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml" category = "dev" +description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml" +marker = "platform_python_implementation == \"CPython\" and python_version < \"3.9\"" +name = "ruamel.yaml.clib" optional = false python-versions = "*" +version = "0.2.2" [[package]] -name = "safety" -version = "1.9.0" -description = "Checks installed dependencies for known vulnerabilities." category = "dev" +description = "Checks installed dependencies for known vulnerabilities." +name = "safety" optional = false python-versions = ">=3.5" +version = "1.9.0" [package.dependencies] Click = ">=6.0" dparse = ">=0.5.1" packaging = "*" requests = "*" +setuptools = "*" [[package]] -name = "six" -version = "1.15.0" -description = "Python 2 and 3 compatibility utilities" category = "dev" +description = "Python 2 and 3 compatibility utilities" +name = "six" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +version = "1.15.0" [[package]] -name = "smmap" -version = "3.0.4" -description = "A pure Python implementation of a sliding window memory map manager" category = "dev" +description = "A pure Python implementation of a sliding window memory map manager" +name = "smmap" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "3.0.4" [[package]] -name = "snowballstemmer" -version = "2.0.0" -description = "This package provides 26 stemmers for 25 languages generated from Snowball algorithms." category = "dev" +description = "This package provides 26 stemmers for 25 languages generated from Snowball algorithms." +name = "snowballstemmer" optional = false python-versions = "*" +version = "2.0.0" [[package]] -name = "sphinx" -version = "3.3.0" -description = "Python documentation generator" category = "dev" +description = "Python documentation generator" +name = "sphinx" optional = false python-versions = ">=3.5" +version = "3.3.0" [package.dependencies] +Jinja2 = ">=2.3" +Pygments = ">=2.0" alabaster = ">=0.7,<0.8" babel = ">=1.3" -colorama = {version = ">=0.3.5", markers = "sys_platform == \"win32\""} +colorama = ">=0.3.5" docutils = ">=0.12" imagesize = "*" -Jinja2 = ">=2.3" packaging = "*" -Pygments = ">=2.0" requests = ">=2.5.0" +setuptools = "*" snowballstemmer = ">=1.1" sphinxcontrib-applehelp = "*" sphinxcontrib-devhelp = "*" @@ -799,12 +823,12 @@ lint = ["flake8 (>=3.5.0)", "flake8-import-order", "mypy (>=0.790)", "docutils-s test = ["pytest", "pytest-cov", "html5lib", "typed-ast", "cython"] [[package]] -name = "sphinx-autobuild" -version = "2020.9.1" -description = "Rebuild Sphinx documentation on changes, with live-reload in the browser." category = "dev" +description = "Rebuild Sphinx documentation on changes, with live-reload in the browser." +name = "sphinx-autobuild" optional = false python-versions = ">=3.6" +version = "2020.9.1" [package.dependencies] livereload = "*" @@ -814,24 +838,24 @@ sphinx = "*" test = ["pytest", "pytest-cov"] [[package]] -name = "sphinx-click" -version = "2.5.0" -description = "Sphinx extension that automatically documents click applications" category = "dev" +description = "Sphinx extension that automatically documents click applications" +name = "sphinx-click" optional = false python-versions = "*" +version = "2.5.0" [package.dependencies] pbr = ">=2.0" sphinx = ">=1.5,<4.0" [[package]] -name = "sphinx-rtd-theme" -version = "0.5.0" -description = "Read the Docs theme for Sphinx" category = "dev" +description = "Read the Docs theme for Sphinx" +name = "sphinx-rtd-theme" optional = false python-versions = "*" +version = "0.5.0" [package.dependencies] sphinx = "*" @@ -840,177 +864,190 @@ sphinx = "*" dev = ["transifex-client", "sphinxcontrib-httpdomain", "bump2version"] [[package]] -name = "sphinxcontrib-applehelp" -version = "1.0.2" -description = "sphinxcontrib-applehelp is a sphinx extension which outputs Apple help books" category = "dev" +description = "sphinxcontrib-applehelp is a sphinx extension which outputs Apple help books" +name = "sphinxcontrib-applehelp" optional = false python-versions = ">=3.5" +version = "1.0.2" [package.extras] lint = ["flake8", "mypy", "docutils-stubs"] test = ["pytest"] [[package]] -name = "sphinxcontrib-devhelp" -version = "1.0.2" -description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp document." category = "dev" +description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp document." +name = "sphinxcontrib-devhelp" optional = false python-versions = ">=3.5" +version = "1.0.2" [package.extras] lint = ["flake8", "mypy", "docutils-stubs"] test = ["pytest"] [[package]] -name = "sphinxcontrib-htmlhelp" -version = "1.0.3" -description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" category = "dev" +description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" +name = "sphinxcontrib-htmlhelp" optional = false python-versions = ">=3.5" +version = "1.0.3" [package.extras] lint = ["flake8", "mypy", "docutils-stubs"] test = ["pytest", "html5lib"] [[package]] -name = "sphinxcontrib-jsmath" -version = "1.0.1" -description = "A sphinx extension which renders display math in HTML via JavaScript" category = "dev" +description = "A sphinx extension which renders display math in HTML via JavaScript" +name = "sphinxcontrib-jsmath" optional = false python-versions = ">=3.5" +version = "1.0.1" [package.extras] test = ["pytest", "flake8", "mypy"] [[package]] -name = "sphinxcontrib-qthelp" -version = "1.0.3" -description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp document." category = "dev" +description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp document." +name = "sphinxcontrib-qthelp" optional = false python-versions = ">=3.5" +version = "1.0.3" [package.extras] lint = ["flake8", "mypy", "docutils-stubs"] test = ["pytest"] [[package]] -name = "sphinxcontrib-serializinghtml" -version = "1.1.4" -description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)." category = "dev" +description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)." +name = "sphinxcontrib-serializinghtml" optional = false python-versions = ">=3.5" +version = "1.1.4" [package.extras] lint = ["flake8", "mypy", "docutils-stubs"] test = ["pytest"] [[package]] -name = "stevedore" -version = "3.2.2" -description = "Manage dynamic plugins for Python applications" category = "dev" +description = "Manage dynamic plugins for Python applications" +name = "stevedore" optional = false python-versions = ">=3.6" +version = "3.2.2" [package.dependencies] -importlib-metadata = {version = ">=1.7.0", markers = "python_version < \"3.8\""} pbr = ">=2.0.0,<2.1.0 || >2.1.0" +[package.dependencies.importlib-metadata] +python = "<3.8" +version = ">=1.7.0" + [[package]] -name = "toml" -version = "0.10.2" -description = "Python Library for Tom's Obvious, Minimal Language" category = "dev" +description = "Python Library for Tom's Obvious, Minimal Language" +name = "toml" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +version = "0.10.2" [[package]] -name = "tornado" -version = "6.1" -description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." category = "dev" +description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." +marker = "python_version > \"2.7\"" +name = "tornado" optional = false python-versions = ">= 3.5" +version = "6.1" [[package]] -name = "typed-ast" -version = "1.4.1" -description = "a fork of Python 2 and 3 ast modules with type comment support" category = "dev" +description = "a fork of Python 2 and 3 ast modules with type comment support" +name = "typed-ast" optional = false python-versions = "*" +version = "1.4.1" [[package]] -name = "typeguard" -version = "2.10.0" -description = "Run-time type checker for Python" category = "dev" +description = "Run-time type checker for Python" +name = "typeguard" optional = false python-versions = ">=3.5.3" +version = "2.10.0" [package.extras] doc = ["sphinx-rtd-theme", "sphinx-autodoc-typehints (>=1.2.0)"] test = ["pytest", "typing-extensions"] [[package]] -name = "typing-extensions" -version = "3.7.4.3" -description = "Backported and Experimental Type Hints for Python 3.5+" category = "main" +description = "Backported and Experimental Type Hints for Python 3.5+" +name = "typing-extensions" optional = false python-versions = "*" +version = "3.7.4.3" [[package]] -name = "urllib3" -version = "1.25.11" -description = "HTTP library with thread-safe connection pooling, file post, and more." category = "dev" +description = "HTTP library with thread-safe connection pooling, file post, and more." +name = "urllib3" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" +version = "1.25.11" [package.extras] brotli = ["brotlipy (>=0.6.0)"] secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] -socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] +socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"] [[package]] -name = "virtualenv" -version = "20.1.0" -description = "Virtual Python Environment builder" category = "dev" +description = "Virtual Python Environment builder" +name = "virtualenv" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +version = "20.1.0" [package.dependencies] appdirs = ">=1.4.3,<2" distlib = ">=0.3.1,<1" filelock = ">=3.0.0,<4" -importlib-metadata = {version = ">=0.12,<3", markers = "python_version < \"3.8\""} six = ">=1.9.0,<2" +[package.dependencies.importlib-metadata] +python = "<3.8" +version = ">=0.12,<3" + [package.extras] docs = ["proselint (>=0.10.2)", "sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=19.9.0rc1)"] testing = ["coverage (>=4)", "coverage-enable-subprocess (>=1)", "flaky (>=3)", "pytest (>=4)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.1)", "pytest-mock (>=2)", "pytest-randomly (>=1)", "pytest-timeout (>=1)", "pytest-xdist (>=1.31.0)", "packaging (>=20.0)", "xonsh (>=0.9.16)"] [[package]] -name = "xdoctest" -version = "0.15.0" -description = "A rewrite of the builtin doctest module" category = "dev" +description = "A rewrite of the builtin doctest module" +name = "xdoctest" optional = false python-versions = "*" +version = "0.15.0" [package.dependencies] -colorama = {version = "*", optional = true, markers = "platform_system == \"Windows\" and extra == \"colors\""} -Pygments = {version = "*", optional = true, markers = "extra == \"colors\""} six = "*" +[package.dependencies.Pygments] +optional = true +version = "*" + +[package.dependencies.colorama] +optional = true +version = "*" + [package.extras] all = ["six", "pytest", "pytest-cov", "codecov", "scikit-build", "cmake", "ninja", "pybind11", "pygments", "colorama", "nbformat", "nbconvert", "jupyter-client", "ipython", "ipykernel"] colors = ["pygments", "colorama"] @@ -1019,34 +1056,38 @@ optional = ["pygments", "colorama", "nbformat", "nbconvert", "jupyter-client", " tests = ["pytest", "pytest-cov", "codecov", "scikit-build", "cmake", "ninja", "pybind11", "nbformat", "nbconvert", "jupyter-client", "ipython", "ipykernel"] [[package]] -name = "yarl" -version = "1.6.2" -description = "Yet another URL library" category = "main" +description = "Yet another URL library" +name = "yarl" optional = false python-versions = ">=3.6" +version = "1.6.2" [package.dependencies] idna = ">=2.0" multidict = ">=4.0" -typing-extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""} + +[package.dependencies.typing-extensions] +python = "<3.8" +version = ">=3.7.4" [[package]] -name = "zipp" -version = "3.4.0" -description = "Backport of pathlib-compatible object wrapper for zip files" category = "dev" +description = "Backport of pathlib-compatible object wrapper for zip files" +marker = "python_version < \"3.8\"" +name = "zipp" optional = false python-versions = ">=3.6" +version = "3.4.0" [package.extras] docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] +testing = ["pytest (>=3.5,<3.7.3 || >3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] [metadata] -lock-version = "1.1" +content-hash = "c6407bab4b3d880e41d95a7dd83ced165d6469b4036c810f11c740616acf9b54" +lock-version = "1.0" python-versions = "^3.7.1" -content-hash = "a1eba52e7a8996810dd6c9900d200e058b93e8f11681adcac5f6e6724204f4bb" [metadata.files] aiohttp = [ @@ -1234,8 +1275,8 @@ gitpython = [ {file = "GitPython-3.1.11.tar.gz", hash = "sha256:befa4d101f91bad1b632df4308ec64555db684c360bd7d2130b4807d49ce86b8"}, ] identify = [ - {file = "identify-1.5.7-py2.py3-none-any.whl", hash = "sha256:e3c822614168c9ac248f4258ffe43092debceb45e299a07b8f2fb168ba875605"}, - {file = "identify-1.5.7.tar.gz", hash = "sha256:b505f7658afbddc11556de5ff9a5a52eed81b9a380f8ff77b7dd9781cfee6884"}, + {file = "identify-1.5.9-py2.py3-none-any.whl", hash = "sha256:5dd84ac64a9a115b8e0b27d1756b244b882ad264c3c423f42af8235a6e71ca12"}, + {file = "identify-1.5.9.tar.gz", hash = "sha256:c9504ba6a043ee2db0a9d69e43246bc138034895f6338d5aed1b41e4a73b1513"}, ] idna = [ {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, diff --git a/pyproject.toml b/pyproject.toml index 12ccaf7e..f08264b7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,7 +47,6 @@ sphinx-click = "^2.5.0" Pygments = "^2.7.2" pytest-asyncio = "^0.14.0" aioresponses = "^0.7.1" -typing-extensions = "^3.7.4" [tool.poetry.scripts] renault-api = "renault_api.__main__:main" From 99238aa9a47903ce04e12165db5ec50faa8f9500 Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Wed, 4 Nov 2020 11:02:43 +0100 Subject: [PATCH 16/18] Make aiohttp_session is Optional --- src/renault_api/helpers.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/renault_api/helpers.py b/src/renault_api/helpers.py index bc0d8efd..74b80893 100644 --- a/src/renault_api/helpers.py +++ b/src/renault_api/helpers.py @@ -2,7 +2,7 @@ import asyncio import functools import logging -from typing import Dict +from typing import Dict, Optional from aiohttp import ClientSession from aiohttp.client_exceptions import ClientResponseError @@ -19,7 +19,9 @@ async def get_api_keys( - locale: str, force_load: bool = False, aiohttp_session: ClientSession = None + locale: str, + force_load: bool = False, + aiohttp_session: Optional[ClientSession] = None, ) -> Dict[str, str]: """Get the API keys for specified locale. @@ -40,7 +42,7 @@ async def get_api_keys( else: _LOGGER.warning( "Locale %s was not found in AVAILABLE_LOCALES " - "(or force_load used)." + "(or force_load used). " "Attempting to load details from Renault servers.", locale, ) @@ -53,7 +55,7 @@ async def get_api_keys( response.raise_for_status() except ClientResponseError as exc: raise RenaultException( - f"Locale not found on Renault server ({exc.status})." + f"Locale not found on Renault server (HTTPStatus = {exc.status})." ) from exc # Server sometimes returns invalid content-type # eg. application/octet-stream From b539cfb5e9ede4eb5ed0794cf36a9eec445c148d Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Wed, 4 Nov 2020 11:12:20 +0100 Subject: [PATCH 17/18] Fix import --- src/renault_api/helpers.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/renault_api/helpers.py b/src/renault_api/helpers.py index 74b80893..bef168b5 100644 --- a/src/renault_api/helpers.py +++ b/src/renault_api/helpers.py @@ -2,7 +2,8 @@ import asyncio import functools import logging -from typing import Dict, Optional +from typing import Dict +from typing import Optional from aiohttp import ClientSession from aiohttp.client_exceptions import ClientResponseError From 592f5012555d85c44ac119f810e9d2440908b55b Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Fri, 6 Nov 2020 10:07:14 +0100 Subject: [PATCH 18/18] Remove aiohttp_session from renault_client fixture --- tests/test_api_keys.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_api_keys.py b/tests/test_api_keys.py index ddc2f989..d39ff2dd 100644 --- a/tests/test_api_keys.py +++ b/tests/test_api_keys.py @@ -18,7 +18,7 @@ @pytest.fixture -def renault_client(aiohttp_session: ClientSession) -> RenaultClient: +def renault_client() -> RenaultClient: """Fixture for testing RenaultClient.""" client = RenaultClient() return client