Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
5 changes: 4 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Expand All @@ -20,6 +22,7 @@ lint = [
"black",
"mypy",
"ruff",
"types-requests",
]
test = [
"pytest",
Expand Down
2 changes: 2 additions & 0 deletions src/gitmojis/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from .core import fetch_guide
from .model import Gitmoji, Guide

__all__ = [
"Gitmoji",
"Guide",
"fetch_guide",
]
27 changes: 27 additions & 0 deletions src/gitmojis/core.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import requests

from . import defaults
from .exceptions import ResponseJsonError
from .model import Gitmoji, Guide


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:
raise ResponseJsonError

guide = Guide(gitmojis=[Gitmoji(**gitmoji_json) for gitmoji_json in gitmojis_json])

return guide
5 changes: 5 additions & 0 deletions src/gitmojis/defaults.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from typing import Final

GITMOJI_API_URL: Final = "https://gitmoji.dev/api/gitmojis"

GITMOJI_API_KEY: Final = "gitmojis"
13 changes: 13 additions & 0 deletions src/gitmojis/exceptions.py
Original file line number Diff line number Diff line change
@@ -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"
31 changes: 31 additions & 0 deletions tests/test_core.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import pytest
import requests

from gitmojis import defaults
from gitmojis.core import fetch_guide
from gitmojis.exceptions import ResponseJsonError
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 = {defaults.GITMOJI_API_KEY: []}

mocker.patch("requests.get", return_value=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()