From 061e36ef6a450caac5c5527f8addf76376f9e747 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Paduszyn=CC=81ski?= Date: Thu, 2 Nov 2023 17:20:26 +0100 Subject: [PATCH 1/7] =?UTF-8?q?=E2=9E=95=20Add=20`requests`=20and=20`types?= =?UTF-8?q?-requests`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyproject.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 7dd16d2..37c885f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,9 @@ build-backend = "setuptools.build_meta" name = "python-gitmojis" version = "0.0.0" requires-python = ">= 3.10" -dependencies = [] +dependencies = [ + "requests", +] [project.optional-dependencies] dev = [ @@ -20,6 +22,7 @@ lint = [ "black", "mypy", "ruff", + "types-requests", ] test = [ "pytest", From f72142524a3850371ecd651d3898d8facff063d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Paduszyn=CC=81ski?= Date: Thu, 2 Nov 2023 17:21:34 +0100 Subject: [PATCH 2/7] =?UTF-8?q?=F0=9F=94=A7=20Update=20`mypy`=20Pre-commit?= =?UTF-8?q?=20hook=20config=20to=20handle=20`requests`=20library?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .pre-commit-config.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 91e3af9..f93e67d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,6 +20,8 @@ repos: hooks: - id: mypy exclude: '^(?:(?!src).)*$' + additional_dependencies: + - types-requests - repo: https://github.com/astral-sh/ruff-pre-commit rev: 'v0.1.3' hooks: From e4fc2a0960a64ebe90b291cae80e795a4263c0ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Paduszyn=CC=81ski?= Date: Thu, 2 Nov 2023 17:53:00 +0100 Subject: [PATCH 3/7] =?UTF-8?q?=E2=9C=A8=20Enable=20fetching=20the=20Gitmo?= =?UTF-8?q?ji=20data=20from=20the=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/gitmojis/core.py | 19 +++++++++++++++++++ tests/test_core.py | 20 ++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 src/gitmojis/core.py create mode 100644 tests/test_core.py diff --git a/src/gitmojis/core.py b/src/gitmojis/core.py new file mode 100644 index 0000000..7c7d33e --- /dev/null +++ b/src/gitmojis/core.py @@ -0,0 +1,19 @@ +from typing import Final + +import requests + +from .model import Gitmoji, Guide + +GITMOJI_API_URL: Final = "https://gitmoji.dev/api/gitmojis" + +GITMOJI_API_KEY: Final = "gitmojis" + + +def fetch_guide() -> Guide: + response = requests.get(GITMOJI_API_URL) + + gitmojis_json = response.json()[GITMOJI_API_KEY] + + guide = Guide(gitmojis=[Gitmoji(**gitmoji_json) for gitmoji_json in gitmojis_json]) + + return guide diff --git a/tests/test_core.py b/tests/test_core.py new file mode 100644 index 0000000..b664f74 --- /dev/null +++ b/tests/test_core.py @@ -0,0 +1,20 @@ +import pytest +import requests + +from gitmojis.core import GITMOJI_API_KEY, fetch_guide +from gitmojis.model import Guide + + +@pytest.fixture() +def response(mocker): + return mocker.Mock(spec_set=requests.Response) + + +def test_fetch_guide_creates_guide_from_api_response_json(mocker, response): + response.json.return_value = {GITMOJI_API_KEY: []} + + mocker.patch("requests.get", return_value=response) + + guide = fetch_guide() + + assert isinstance(guide, Guide) From 813112208b9ea02438b038657ba129f57fde6040 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Paduszyn=CC=81ski?= Date: Thu, 2 Nov 2023 18:19:51 +0100 Subject: [PATCH 4/7] =?UTF-8?q?=F0=9F=A5=85=20Handle=20errors=20due=20to?= =?UTF-8?q?=20invalid=20API=20response=20JSON=20format?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/gitmojis/core.py | 4 +++- src/gitmojis/exceptions.py | 13 +++++++++++++ tests/test_core.py | 10 ++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 src/gitmojis/exceptions.py diff --git a/src/gitmojis/core.py b/src/gitmojis/core.py index 7c7d33e..64dd874 100644 --- a/src/gitmojis/core.py +++ b/src/gitmojis/core.py @@ -2,6 +2,7 @@ import requests +from .exceptions import ResponseJsonError from .model import Gitmoji, Guide GITMOJI_API_URL: Final = "https://gitmoji.dev/api/gitmojis" @@ -12,7 +13,8 @@ def fetch_guide() -> Guide: response = requests.get(GITMOJI_API_URL) - gitmojis_json = response.json()[GITMOJI_API_KEY] + if (gitmojis_json := response.json().get(GITMOJI_API_KEY)) is None: + raise ResponseJsonError guide = Guide(gitmojis=[Gitmoji(**gitmoji_json) for gitmoji_json in gitmojis_json]) diff --git a/src/gitmojis/exceptions.py b/src/gitmojis/exceptions.py new file mode 100644 index 0000000..75f4ad3 --- /dev/null +++ b/src/gitmojis/exceptions.py @@ -0,0 +1,13 @@ +class GitmojisException(Exception): + message: str + + def __init__(self, message: str | None = None) -> None: + super().__init__(message or getattr(self.__class__, "message", "")) + + +class ApiError(GitmojisException): + pass + + +class ResponseJsonError(ApiError): + message = "unsupported format of the JSON data returned by the API" diff --git a/tests/test_core.py b/tests/test_core.py index b664f74..5169f3c 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -2,6 +2,7 @@ import requests from gitmojis.core import GITMOJI_API_KEY, fetch_guide +from gitmojis.exceptions import ResponseJsonError from gitmojis.model import Guide @@ -18,3 +19,12 @@ def test_fetch_guide_creates_guide_from_api_response_json(mocker, response): guide = fetch_guide() assert isinstance(guide, Guide) + + +def test_fetch_guide_raises_error_if_gitmoji_api_key_not_in_response_json(mocker, response): # fmt: skip + response.json.return_value = {} # `GITMOJI_API_KEY` not in the response's JSON + + mocker.patch("requests.get", return_value=response) + + with pytest.raises(ResponseJsonError): + fetch_guide() From 0ceecb39d92f86a1ae63acd34632df8602a98c4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Paduszyn=CC=81ski?= Date: Thu, 2 Nov 2023 18:22:43 +0100 Subject: [PATCH 5/7] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Move=20constants=20to?= =?UTF-8?q?=20`gitmojis.defaults`=20module?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/gitmojis/core.py | 11 +++-------- src/gitmojis/defaults.py | 5 +++++ tests/test_core.py | 5 +++-- 3 files changed, 11 insertions(+), 10 deletions(-) create mode 100644 src/gitmojis/defaults.py diff --git a/src/gitmojis/core.py b/src/gitmojis/core.py index 64dd874..a30b3a6 100644 --- a/src/gitmojis/core.py +++ b/src/gitmojis/core.py @@ -1,19 +1,14 @@ -from typing import Final - import requests +from . import defaults from .exceptions import ResponseJsonError from .model import Gitmoji, Guide -GITMOJI_API_URL: Final = "https://gitmoji.dev/api/gitmojis" - -GITMOJI_API_KEY: Final = "gitmojis" - def fetch_guide() -> Guide: - response = requests.get(GITMOJI_API_URL) + response = requests.get(defaults.GITMOJI_API_URL) - if (gitmojis_json := response.json().get(GITMOJI_API_KEY)) is None: + if (gitmojis_json := response.json().get(defaults.GITMOJI_API_KEY)) is None: raise ResponseJsonError guide = Guide(gitmojis=[Gitmoji(**gitmoji_json) for gitmoji_json in gitmojis_json]) diff --git a/src/gitmojis/defaults.py b/src/gitmojis/defaults.py new file mode 100644 index 0000000..e735cab --- /dev/null +++ b/src/gitmojis/defaults.py @@ -0,0 +1,5 @@ +from typing import Final + +GITMOJI_API_URL: Final = "https://gitmoji.dev/api/gitmojis" + +GITMOJI_API_KEY: Final = "gitmojis" diff --git a/tests/test_core.py b/tests/test_core.py index 5169f3c..cf28e9b 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -1,7 +1,8 @@ import pytest import requests -from gitmojis.core import GITMOJI_API_KEY, fetch_guide +from gitmojis import defaults +from gitmojis.core import fetch_guide from gitmojis.exceptions import ResponseJsonError from gitmojis.model import Guide @@ -12,7 +13,7 @@ def response(mocker): def test_fetch_guide_creates_guide_from_api_response_json(mocker, response): - response.json.return_value = {GITMOJI_API_KEY: []} + response.json.return_value = {defaults.GITMOJI_API_KEY: []} mocker.patch("requests.get", return_value=response) From 36afc700ea759056416a9585c08f88f6169af0f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Paduszyn=CC=81ski?= Date: Thu, 2 Nov 2023 18:28:53 +0100 Subject: [PATCH 6/7] =?UTF-8?q?=F0=9F=93=9D=20Document=20`gitmojis.core.fe?= =?UTF-8?q?tch=5Fguide()`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/gitmojis/core.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/gitmojis/core.py b/src/gitmojis/core.py index a30b3a6..5bec8b6 100644 --- a/src/gitmojis/core.py +++ b/src/gitmojis/core.py @@ -6,6 +6,17 @@ def fetch_guide() -> Guide: + """Fetch the Gitmoji guide from the official Gitmoji API. + + This function sends a GET request to the Gitmoji API to retrieve the current state + of the Gitmoji guide. + + Returns: + A `Guide` object representing the current state of the Gitmoji API. + + Raises: + ResponseJsonError: If the API response doesn't contain the expected JSON data. + """ response = requests.get(defaults.GITMOJI_API_URL) if (gitmojis_json := response.json().get(defaults.GITMOJI_API_KEY)) is None: From 9b499c0ac9254a4b7a55f7f16701e58299dbf5b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Paduszyn=CC=81ski?= Date: Thu, 2 Nov 2023 18:29:53 +0100 Subject: [PATCH 7/7] =?UTF-8?q?=F0=9F=A7=B1=20Add=20`fetch=5Fguide()`=20fu?= =?UTF-8?q?nction=20to=20the=20package=20index?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/gitmojis/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gitmojis/__init__.py b/src/gitmojis/__init__.py index faf89ac..55e7de1 100644 --- a/src/gitmojis/__init__.py +++ b/src/gitmojis/__init__.py @@ -1,6 +1,8 @@ +from .core import fetch_guide from .model import Gitmoji, Guide __all__ = [ "Gitmoji", "Guide", + "fetch_guide", ]