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
14 changes: 3 additions & 11 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,11 @@ jobs:
- name: Checkout
uses: actions/checkout@v4

- name: Install Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install PDM
- name: Setup Python ${{ matrix.python-version }} & PDM
uses: pdm-project/setup-pdm@v4

- name: Cache the Virtual Env
uses: actions/cache@v4
with:
path: ./.venv
key: venv-${{ matrix.python-version }}-${{ hashFiles('pdm.lock') }}
python-version: ${{ matrix.python-version }}
cache: true

- name: Install the project dependencies
run: pdm install -d
Expand Down
12 changes: 6 additions & 6 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ on:
tags:
- "*"

env:
PYTHON_VERSION: 3.13

jobs:
release:
runs-on: ubuntu-latest
Expand All @@ -18,13 +21,10 @@ jobs:
- name: Checkout
uses: actions/checkout@v4

- name: Install Python
uses: actions/setup-python@v5
with:
python-version: "3.13"

- name: Install PDM
- name: Setup Python & PDM
uses: pdm-project/setup-pdm@v4
with:
python-version: ${{ env.PYTHON_VERSION }}

- name: Install the project dependencies
run: pdm install -d
Expand Down
33 changes: 33 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Run tests
on:
push:
branches:
- master
tags:
- v*
pull_request:
branches:
- master

env:
PYTHON_VERSION: 3.13

jobs:
lint:
name: Validate Linter
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Python & PDM
uses: pdm-project/setup-pdm@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: true

- name: Install the project dependencies
run: pdm install -d

- name: Lint the project
run: pdm check
5 changes: 4 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,13 @@ path = "src/tcgdexsdk/__init__.py"
# Ruff #
########
[tool.ruff]
line-length = 80
line-length = 120
respect-gitignore = true
include = ["src/**/*.py"]

[tool.ruff.lint.pycodestyle]
ignore-overlong-task-comments = true

[tool.ruff.lint]
select = ["E", "F", "UP", "B", "SIM", "I"]

Expand Down
2 changes: 2 additions & 0 deletions src/tcgdexsdk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from tcgdexsdk.models.Set import Set
from tcgdexsdk.models.SetResume import SetResume
from tcgdexsdk.models.StringEndpoint import StringEndpoint
from tcgdexsdk.query import Query
from tcgdexsdk.tcgdex import TCGdex

__all__ = [
Expand All @@ -23,4 +24,5 @@
"Set",
"SetResume",
"StringEndpoint",
"Query",
]
14 changes: 11 additions & 3 deletions src/tcgdexsdk/endpoints/Endpoint.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from typing import Generic, List, Optional, Type, TypeVar, Union

from tcgdexsdk.models.Model import Model
from tcgdexsdk.utils import fetch, fetch_list
from tcgdexsdk.query import Query
from tcgdexsdk.utils import fetch, fetch_list

# Generic type variables
Item = TypeVar('Item', bound=Model)
Expand All @@ -20,7 +20,11 @@ def __init__(self,
self.endpoint = endpoint

async def get(self, id: str) -> Optional[Item]:
return fetch(self.tcgdex, f"{self.tcgdex.getEndpoint()}/{self.tcgdex.language}/{self.endpoint}/{id.replace(' ', '%20')}", self.item_model)
return fetch(
self.tcgdex,
f"{self.tcgdex.getEndpoint()}/{self.tcgdex.language}/{self.endpoint}/{id.replace(' ', '%20')}",
self.item_model
)

async def list(self, query: Optional[Query] = None) -> List[ListModel]:
url = f"{self.tcgdex.getEndpoint()}/{self.tcgdex.language}/{self.endpoint}"
Expand All @@ -29,7 +33,11 @@ async def list(self, query: Optional[Query] = None) -> List[ListModel]:
return fetch_list(self.tcgdex, url, self.list_model)

def getSync(self, id: str) -> Optional[Item]:
return fetch(self.tcgdex, f"{self.tcgdex.getEndpoint()}/{self.tcgdex.language}/{self.endpoint}/{id.replace(' ', '%20')}", self.item_model)
return fetch(
self.tcgdex,
f"{self.tcgdex.getEndpoint()}/{self.tcgdex.language}/{self.endpoint}/{id.replace(' ', '%20')}",
self.item_model
)

def listSync(self, query: Optional[Query] = None) -> List[ListModel]:
url = f"{self.tcgdex.getEndpoint()}/{self.tcgdex.language}/{self.endpoint}"
Expand Down
10 changes: 8 additions & 2 deletions src/tcgdexsdk/query.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from urllib.parse import quote


class Query:
def __init__(self):
self.params = []
Expand All @@ -12,7 +13,9 @@ def encode(self, value):
)

def build(self):
return '?' + '&'.join(f"{self.encode(item['key'])}={self.encode(item['value'])}" for item in self.params)
return '?' + '&'.join(
f"{self.encode(item['key'])}={self.encode(item['value'])}" for item in self.params
)

def includes(self, key: str, value: str):
return self.contains(key, value)
Expand Down Expand Up @@ -67,7 +70,10 @@ def isNull(self, key: str):

def paginate(self, page: int, itemsPerPage: int):
self.params.append({'key': 'pagination:page', 'value': page})
self.params.append({'key': 'pagination:itemsPerPage', 'value': itemsPerPage})
self.params.append({
'key': 'pagination:itemsPerPage',
'value': itemsPerPage
})
return self

def notEqual(self, key: str, value: str):
Expand Down
9 changes: 3 additions & 6 deletions src/tcgdexsdk/tcgdex.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from typing import Union
from warnings import deprecated

from tcgdexsdk.endpoints.Endpoint import Endpoint
from tcgdexsdk.enums import Language
Expand All @@ -10,6 +9,7 @@
from tcgdexsdk.models.Set import Set
from tcgdexsdk.models.SetResume import SetResume
from tcgdexsdk.models.StringEndpoint import StringEndpoint
from tcgdexsdk.utils import deprecated


class TCGdex:
Expand All @@ -28,7 +28,7 @@ def getEndpoint(self) -> str:
@deprecated("use (get|set)endpoint instead")
def URI(self):
"""
@Deprecated: use `getEndpoint()` or `setEndpoint()` instead.
@Deprecated: use `getEndpoint()` or `setEndpoint()` instead.
"""
return self.getEndpoint()

Expand Down Expand Up @@ -58,9 +58,7 @@ def __init__(self, language: Union[str, Language] = Language.EN):
self.trainerType = Endpoint(self, StringEndpoint, str, "trainer-types")
self.suffix = Endpoint(self, StringEndpoint, str, "suffixes")
self.stage = Endpoint(self, StringEndpoint, str, "stages")
self.regulationMark = Endpoint(
self, StringEndpoint, str, "regulation-marks"
)
self.regulationMark = Endpoint(self, StringEndpoint, str, "regulation-marks")
self.energyType = Endpoint(self, StringEndpoint, str, "energy-types")
self.dexId = Endpoint(self, StringEndpoint, int, "dex-ids")
self.type = Endpoint(self, StringEndpoint, str, "types")
Expand All @@ -69,4 +67,3 @@ def __init__(self, language: Union[str, Language] = Language.EN):
self.illustrator = Endpoint(self, StringEndpoint, str, "illustrators")
self.hp = Endpoint(self, StringEndpoint, int, "hp")
self.category = Endpoint(self, StringEndpoint, str, "categories")

17 changes: 16 additions & 1 deletion src/tcgdexsdk/utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import json
import time
from functools import lru_cache
import warnings
from functools import lru_cache, wraps
from http.client import HTTPResponse
from typing import List, Optional, Type, TypeVar
from urllib.request import Request, urlopen
Expand Down Expand Up @@ -62,3 +63,17 @@ def fetch_list(tcgdex, url: str, cls: Type[_T]) -> List[_T]:

def download_image(url: str) -> HTTPResponse:
return urlopen(_request(url))


def deprecated(reason):
def decorator(func):
message = f"{func.__name__} is deprecated: {reason}"

@wraps(func)
def wrapper(*args, **kwargs):
warnings.warn(message, category=DeprecationWarning, stacklevel=2)
return func(*args, **kwargs)

return wrapper

return decorator
39 changes: 19 additions & 20 deletions tests/tests.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import unittest
from typing import Callable
from unittest.mock import patch
from warnings import deprecated

import vcr

from tcgdexsdk import Language, TCGdex
Expand All @@ -14,26 +14,25 @@
from tcgdexsdk.models.StringEndpoint import StringEndpoint
from tcgdexsdk.query import Query


def _use_cassette(test: Callable) -> Callable:
return vcr.use_cassette(f"tests/.fixtures/{test.__name__}.yaml")(test)


class APITest(unittest.IsolatedAsyncioTestCase):
def setUp(self):
self.api = TCGdex(Language.EN)


@deprecated("this test is deprecated")

@patch("tcgdexsdk.endpoints.Endpoint.fetch")
@patch("tcgdexsdk.endpoints.Endpoint.fetch_list")
async def test_uri(self, mock_fetch_list, mock_fetch):
api = TCGdex(Language.EN)

api.URI = "http://localhost:3000/v2"

await api.card.get("swsh1-136")
mock_fetch.assert_called_once_with(api, "http://localhost:3000/v2/en/cards/swsh1-136", Card)

await api.card.list()
mock_fetch_list.assert_called_once_with(api, "http://localhost:3000/v2/en/cards", CardResume)

Expand All @@ -55,17 +54,17 @@ async def test_endpoint(self, mock_fetch_list, mock_fetch):
@patch("tcgdexsdk.endpoints.Endpoint.fetch_list")
async def test_language(self, mock_fetch_list, mock_fetch):
api = TCGdex()

# Default language should be english
self.assertEqual(api.getLanguage(), Language.EN)

# Card should be fetched in english
await api.card.get("swsh1-136")
mock_fetch.assert_called_once_with(api, f"{api.getEndpoint()}/en/cards/swsh1-136", Card)

# Card should be fetched in french
api.setLanguage(Language.FR)

# Test that the language is set correctly
self.assertEqual(api.getLanguage(), Language.FR)
await api.card.get("swsh1-136")
Expand All @@ -74,25 +73,25 @@ async def test_language(self, mock_fetch_list, mock_fetch):
@_use_cassette
async def test_fr(self):
tcg = TCGdex(Language.FR)
res = await tcg.card.get('swsh3-136')
self.assertEqual(res.name, 'Fouinar')
tcg2 = TCGdex('fr')
res = await tcg2.card.get('swsh3-136')
self.assertEqual(res.name, 'Fouinar')
res = await tcg.card.get("swsh3-136")
self.assertEqual(res.name, "Fouinar")
tcg2 = TCGdex("fr")
res = await tcg2.card.get("swsh3-136")
self.assertEqual(res.name, "Fouinar")

@_use_cassette
async def test_query_equal(self):
tcg = TCGdex(Language.EN)
res = await tcg.card.list(Query().equal('name', 'Furret'))
res = await tcg.card.list(Query().equal("name", "Furret"))
for card in res:
self.assertEqual(card.name, 'Furret')
self.assertEqual(card.name, "Furret")

@_use_cassette
async def test_query_not_equal(self):
tcg = TCGdex()
res = await tcg.card.list(Query().notEqual('name', 'Furret'))
res = await tcg.card.list(Query().notEqual("name", "Furret"))
for card in res:
self.assertNotEqual(card.name, 'Furret')
self.assertNotEqual(card.name, "Furret")

@_use_cassette
async def test_card_resume(self):
Expand Down