diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..afbf253 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,61 @@ +name: CI + +on: + push: + branches: + - main + pull_request: + branches: + - main + +jobs: + ci: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + id: setup-python + with: + python-version: '3.12' + + - name: Install Poetry + uses: snok/install-poetry@v1 + with: + virtualenvs-create: true + virtualenvs-in-project: true + + - name: Load cached venv + id: cached-poetry-dependencies + uses: actions/cache@v4 + with: + path: .venv + key: venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('**/poetry.lock') }} + + - name: Install dependencies + if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' + run: poetry install --no-interaction --no-root + + - name: Install library + run: poetry install --no-interaction + + - name: Lint + run: | + source .venv/bin/activate + poetry run flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + poetry run flake8 . --count --exit-zero --max-complexity=10 --statistics + poetry run black . --check + poetry run isort . + + - name: Create .env file + run: | + echo "TOKEN=${{ secrets.BLAGUES_API_TOKEN }}" > .env + + - name: Run tests + run: poetry run pytest --cov --cov-report=xml + + - name: Upload coverage + uses: codecov/codecov-action@v4.0.1 + with: + token: ${{ secrets.CODECOV_TOKEN }} + file: ./coverage.xml + fail_ci_if_error: true \ No newline at end of file diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..a741580 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,52 @@ +name: Publish to PyPI + +on: + push: + branches: + - main + +jobs: + publish: + runs-on: ubuntu-latest + + if: github.repository_owner == 'Blagues-API' + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 2 + + - name: Check if version changed + id: check_version + run: | + git diff HEAD^ HEAD -- pyproject.toml | grep '+version' && echo "version_changed=true" >> $GITHUB_OUTPUT || echo "version_changed=false" >> $GITHUB_OUTPUT + + - uses: actions/setup-python@v5 + if: steps.check_version.outputs.version_changed == 'true' + id: setup-python + with: + python-version: '3.12' + + - name: Install Poetry + if: steps.check_version.outputs.version_changed == 'true' + uses: snok/install-poetry@v1 + with: + virtualenvs-create: true + virtualenvs-in-project: true + + - name: Load cached venv + if: steps.check_version.outputs.version_changed == 'true' + id: cached-poetry-dependencies + uses: actions/cache@v4 + with: + path: .venv + key: venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('**/poetry.lock') }} + + - name: Build + if: steps.check_version.outputs.version_changed == 'true' + run: poetry build + + - name: Publish package distributions to PyPI + if: steps.check_version.outputs.version_changed == 'true' + uses: pypa/gh-action-pypi-publish@release/v1 + with: + packages-dir: dist/ \ No newline at end of file diff --git a/.gitignore b/.gitignore index c608a32..59294d3 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,6 @@ __pycache__/ dist/ poetry.lock .env -.pytest_cache/ \ No newline at end of file +.pytest_cache/ +.venv/ +coverage.xml \ No newline at end of file diff --git a/blagues_api/__init__.py b/blagues_api/__init__.py index de2a718..da3134a 100644 --- a/blagues_api/__init__.py +++ b/blagues_api/__init__.py @@ -1 +1,3 @@ -from .main import BlaguesAPI, BlagueType, CountJoke, Blague \ No newline at end of file +from .main import Blague, BlaguesAPI, BlagueType, CountJoke + +__all__ = ["BlaguesAPI", "BlagueType", "CountJoke", "Blague"] diff --git a/blagues_api/main.py b/blagues_api/main.py index 98e6a99..db83228 100644 --- a/blagues_api/main.py +++ b/blagues_api/main.py @@ -1,7 +1,9 @@ +from enum import Enum +from typing import List + import aiohttp import pydantic -from typing import List -from enum import Enum + class BlagueType(str, Enum): GLOBAL = "global" @@ -14,51 +16,52 @@ class BlagueType(str, Enum): def __str__(self): return str(self.value) + class Blague(pydantic.BaseModel): id: int type: BlagueType joke: str answer: str + class CountJoke(pydantic.BaseModel): count: int + class BlaguesAPI: def __init__(self, token: str): self.token = token self.base_url = "https://www.blagues-api.fr/api" - self.headers = {'Authorization': 'Bearer ' + self.token} - + self.headers = {"Authorization": f"Bearer {self.token}"} async def _get(self, url: str, params: dict = None) -> dict: async with aiohttp.ClientSession(raise_for_status=True) as session: - async with session.get(self.base_url+url, headers=self.headers, params=params) as resp: + async with session.get( + self.base_url + url, headers=self.headers, params=params + ) as resp: return await resp.json() async def random(self, *, disallow: List[str] = None) -> Blague: endpoint = "/random" params = {"disallow": disallow} if disallow else {} data = await self._get(endpoint, params) - - return Blague.model_validate(data) + return Blague.model_validate(data) async def random_categorized(self, category: str) -> Blague: endpoint = f"/type/{category}/random" data = await self._get(endpoint) - - return Blague.model_validate(data) + return Blague.model_validate(data) async def from_id(self, id: int) -> Blague: endpoint = f"/id/{id}" data = await self._get(endpoint) - + return Blague.model_validate(data) async def count(self) -> CountJoke: endpoint = "/count" data = await self._get(endpoint) - - return CountJoke.model_validate(data) + return CountJoke.model_validate(data) diff --git a/pyproject.toml b/pyproject.toml index a820467..91e108c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,7 +13,7 @@ readme = "README.md" repository = "https://github.com/Blagues-API/package-py" [tool.poetry.dependencies] -python = "^3.8" +python = "^3.8.1" aiohttp = "^3.9.5" pydantic = "^2.8.2" @@ -21,6 +21,11 @@ pydantic = "^2.8.2" pytest = "^7.1.2" pytest-asyncio = "^0.18.3" python-dotenv = "^0.20.0" +flake8 = "^7.1.0" +flake8-pyproject = "^1.2.3" +black = "^24.4.2" +isort = "^5.13.2" +pytest-cov = "^5.0.0" [build-system] requires = ["poetry-core>=1.0.0"] @@ -29,3 +34,9 @@ build-backend = "poetry.core.masonry.api" [tool.pytest.ini_options] asyncio_mode="auto" +[tool.flake8] +max-line-length = 120 +exclude = [".venv"] + +[tool.isort] +profile = "black" diff --git a/tests/test_blagues_api.py b/tests/test_blagues_api.py index 95f977e..4f35915 100644 --- a/tests/test_blagues_api.py +++ b/tests/test_blagues_api.py @@ -1,7 +1,7 @@ import pytest - from dotenv import dotenv_values -from blagues_api import BlaguesAPI, BlagueType, CountJoke, Blague + +from blagues_api import Blague, BlaguesAPI, BlagueType, CountJoke pytestmark = pytest.mark.asyncio @@ -11,10 +11,12 @@ def token(): env = dotenv_values(".env") return env["TOKEN"] + @pytest.fixture def client(token): return BlaguesAPI(token) + async def test_random_joke(client): response = await client.random() assert isinstance(response, Blague)