diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 074db52..a6cd8dd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,24 +14,31 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.8", "3.9", "3.10", "3.11"] + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - name: Checkout + uses: actions/checkout@v4 + - name: Install Python uses: actions/setup-python@v4 - # see details (matrix, python-version, python-version-file, etc.) - # https://github.com/actions/setup-python + with: + python-version: ${{ matrix.python-version }} + - name: Install PDM uses: pdm-project/setup-pdm@v4 + - name: Cache the Virtual Env uses: actions/cache@v3 with: path: ./.venv - key: venv-${{ hashFiles('pdm.lock') }} + key: venv-${{ matrix.python-version }}-${{ hashFiles('pdm.lock') }} + - name: Install the project dependencies run: pdm install -d + - name: Build the project run: pdm build - - name: Run the automated tests (for example) + + - name: Run the Unit tests run: pdm run test -- -v diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..8a4e0db --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,25 @@ +name: Release + +on: + push: + tags: + - "*" + +jobs: + release: + runs-on: ubuntu-latest + permissions: + # This permission is needed for private repositories. + contents: read + # IMPORTANT: this permission is mandatory for trusted publishing + id-token: write + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install PDM + uses: pdm-project/setup-pdm@v4 + + - name: Build & Publish package to PyPI + run: pdm publish diff --git a/pyproject.toml b/pyproject.toml index 475d54a..d8f8c32 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,8 @@ [project] name = "tcgdex-sdk" -version = "0.10.0" +# version = "0.0.0" +dynamic = ["version"] description = "" authors = [{ name = "Avior", email = "git@avior.me" }, { name = "HellLord77" }] dependencies = ["dacite>=1.8.1"] @@ -10,17 +11,17 @@ readme = "README.md" license = { text = "MIT" } maintainers = [{ name = "Avior", email = "git@avior.me" }] classifiers = [ - "Development Status :: 3 - Alpha", - "Intended Audience :: Developers", - "Operating System :: OS Independent", - "License :: OSI Approved :: MIT License", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - "Programming Language :: Python :: 3 :: Only", + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "Operating System :: OS Independent", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3 :: Only", ] [project.urls] @@ -34,6 +35,9 @@ documentation = "https://tcgdex.dev" requires = ["pdm-backend"] build-backend = "pdm.backend" +####### +# PDM # +####### [tool.pdm] distribution = true @@ -48,13 +52,34 @@ test = "python -m unittest discover -s tests" [tool.pdm.build] includes = ["src/tcgdexsdk"] +# [tool.pdm.version] +# source = "scm" +# fallback_version = "0.0.0" +# write_to = "tcgdexsdk/version.py" +# write_template = "__version__ = '{}'" + +[tool.pdm.version] +source = "file" +path = "src/tcgdexsdk/__init__.py" + +######## +# Ruff # +######## [tool.ruff] -line-length = 120 -# exclude = ["build/", "docs/"] +line-length = 80 +respect-gitignore = true +include = ["src/**/*.py"] [tool.ruff.lint] select = ["E", "F", "UP", "B", "SIM", "I"] +[tool.ruff.format] +docstring-code-format = true +line-ending = "lf" + +########### +# Pyright # +########### [tool.pyright] exclude = [".venv"] venvPath = "." diff --git a/scripts/load_version.py b/scripts/load_version.py index 878e829..eed7216 100644 --- a/scripts/load_version.py +++ b/scripts/load_version.py @@ -1,17 +1,20 @@ """ - Load the current version into the project +Load the current version into the project """ -import toml import re import subprocess +import toml + + def run_command(command): """ run a command on the system """ return subprocess.run(command, stdout=subprocess.PIPE, text=True).stdout + # Load the pyproject.toml file pyproject = toml.load("pyproject.toml") @@ -24,13 +27,16 @@ def run_command(command): if version == "": version = pyproject["project"]["version"] + # replace in file -with open("src/tcgdexsdk/__init__.py", 'r+') as file: +with open("src/tcgdexsdk/__init__.py", "r+") as file: content = file.read() file.seek(0) # Use a regex to replace the existing __version__ variable - new_content = re.sub(r'__version__ = ".*?"', f'__version__ = "{version}"', content) + new_content = re.sub( + r'__version__ = ".*?"', f'__version__ = "{version.strip()}"', content + ) file.write(new_content) file.truncate() diff --git a/src/tcgdexsdk/__init__.py b/src/tcgdexsdk/__init__.py index be0d5a2..08cfb13 100644 --- a/src/tcgdexsdk/__init__.py +++ b/src/tcgdexsdk/__init__.py @@ -1,13 +1,16 @@ -from tcgdexsdk.tcgdex import TCGdex +# Do no edit, set automatically on build (Also on top so it can be used by the code) +__version__ = "0.1.0" + from tcgdexsdk.endpoints.Endpoint import Endpoint from tcgdexsdk.enums import Language -from tcgdexsdk.models.CardResume import CardResume from tcgdexsdk.models.Card import Card +from tcgdexsdk.models.CardResume import CardResume from tcgdexsdk.models.Serie import Serie from tcgdexsdk.models.SerieResume import SerieResume from tcgdexsdk.models.Set import Set from tcgdexsdk.models.SetResume import SetResume from tcgdexsdk.models.StringEndpoint import StringEndpoint +from tcgdexsdk.tcgdex import TCGdex __all__ = [ "TCGdex", @@ -19,8 +22,5 @@ "SerieResume", "Set", "SetResume", - "StringEndpoint" + "StringEndpoint", ] - -# Do no edit, set automatically on build -__version__ = "0.10.0" diff --git a/src/tcgdexsdk/enums.py b/src/tcgdexsdk/enums.py index 72b7eda..90e52fd 100644 --- a/src/tcgdexsdk/enums.py +++ b/src/tcgdexsdk/enums.py @@ -3,6 +3,7 @@ # Todo when min is 3.11 # Move to StringEnum and auto + class Language(Enum): EN = "en" """English""" diff --git a/src/tcgdexsdk/models/Card.py b/src/tcgdexsdk/models/Card.py index d3dba02..823b585 100644 --- a/src/tcgdexsdk/models/Card.py +++ b/src/tcgdexsdk/models/Card.py @@ -6,7 +6,14 @@ from tcgdexsdk.enums import Extension, Quality from tcgdexsdk.models.Model import Model from tcgdexsdk.models.SetResume import SetResume -from tcgdexsdk.models.subs import CardAbility, CardAttack, CardItem, CardVariants, CardWeakRes, Legal +from tcgdexsdk.models.subs import ( + CardAbility, + CardAttack, + CardItem, + CardVariants, + CardWeakRes, + Legal, +) @dataclass diff --git a/src/tcgdexsdk/models/CardResume.py b/src/tcgdexsdk/models/CardResume.py index 43b8773..1f6c464 100644 --- a/src/tcgdexsdk/models/CardResume.py +++ b/src/tcgdexsdk/models/CardResume.py @@ -6,6 +6,7 @@ from tcgdexsdk.enums import Extension, Quality from tcgdexsdk.models.Model import Model + @dataclass class CardResume(Model): """Card Resume class, contains basic information about a specific card diff --git a/src/tcgdexsdk/models/IntEndpoint.py b/src/tcgdexsdk/models/IntEndpoint.py index ed53abb..02e4b74 100644 --- a/src/tcgdexsdk/models/IntEndpoint.py +++ b/src/tcgdexsdk/models/IntEndpoint.py @@ -1,14 +1,10 @@ from dataclasses import dataclass -from http.client import HTTPResponse -from typing import List, Optional, Union +from typing import List -from tcgdexsdk import utils -from tcgdexsdk.enums import Extension, Quality -from tcgdexsdk.models.Card import Card from tcgdexsdk.models.CardResume import CardResume -from tcgdexsdk.models.Serie import Serie from tcgdexsdk.models.Model import Model + @dataclass class IntEndpoint(Model): """Generic class that handle a lot of Endpoints""" diff --git a/src/tcgdexsdk/models/Model.py b/src/tcgdexsdk/models/Model.py index 66956dc..cd56258 100644 --- a/src/tcgdexsdk/models/Model.py +++ b/src/tcgdexsdk/models/Model.py @@ -1,6 +1,7 @@ from dataclasses import dataclass, field from typing import Any + @dataclass class Model: - sdk: Any = field(init=False, default=None) + sdk: Any = field(init=False, default=None) diff --git a/src/tcgdexsdk/models/Serie.py b/src/tcgdexsdk/models/Serie.py index c9b9318..6dd2a98 100644 --- a/src/tcgdexsdk/models/Serie.py +++ b/src/tcgdexsdk/models/Serie.py @@ -3,10 +3,11 @@ from typing import List, Optional, Union from tcgdexsdk import utils -from tcgdexsdk.enums import Extension, Quality +from tcgdexsdk.enums import Extension from tcgdexsdk.models.Model import Model from tcgdexsdk.models.SetResume import SetResume + @dataclass class Serie(Model): """Pokémon TCG Serie""" diff --git a/src/tcgdexsdk/models/SerieResume.py b/src/tcgdexsdk/models/SerieResume.py index 30a7e6d..ce8df51 100644 --- a/src/tcgdexsdk/models/SerieResume.py +++ b/src/tcgdexsdk/models/SerieResume.py @@ -3,10 +3,10 @@ from typing import Optional, Union from tcgdexsdk import utils -from tcgdexsdk.enums import Extension, Quality -from tcgdexsdk.models.Card import Card -from tcgdexsdk.models.Serie import Serie +from tcgdexsdk.enums import Extension from tcgdexsdk.models.Model import Model +from tcgdexsdk.models.Serie import Serie + @dataclass class SerieResume(Model): @@ -38,8 +38,8 @@ def get_logo(self, format: Union[str, Extension]) -> Optional[HTTPResponse]: return utils.download_image(url) async def get_full_serie(self) -> Optional[Serie]: - """ - Get the full Card - @return: the full card if available - """ - return await self.sdk.serie.get(self.id) + """ + Get the full Card + @return: the full card if available + """ + return await self.sdk.serie.get(self.id) diff --git a/src/tcgdexsdk/models/Set.py b/src/tcgdexsdk/models/Set.py index fafe778..e4c9e75 100644 --- a/src/tcgdexsdk/models/Set.py +++ b/src/tcgdexsdk/models/Set.py @@ -1,15 +1,15 @@ from dataclasses import dataclass from http.client import HTTPResponse -from typing import List, Optional -from typing_extensions import Union +from typing import List, Optional, Union from tcgdexsdk import utils -from tcgdexsdk.enums import Extension, Quality +from tcgdexsdk.enums import Extension from tcgdexsdk.models.CardResume import CardResume from tcgdexsdk.models.Model import Model from tcgdexsdk.models.SerieResume import SerieResume from tcgdexsdk.models.subs import Legal, SetCardCountResume + @dataclass class Set(Model): """Pokémon TCG Set class""" @@ -25,7 +25,6 @@ class Set(Model): cardCount: SetCardCountResume """the number of card in the set""" - serie: SerieResume """the serie this set is a part of""" tcgOnline: Optional[str] @@ -64,7 +63,9 @@ def get_symbol_url(self, extension: Union[str, Extension]) -> Optional[str]: if self.symbol: return f"{self.symbol}.{extension}" - def get_symbol(self, format: Union[str, Extension]) -> Optional[HTTPResponse]: + def get_symbol( + self, format: Union[str, Extension] + ) -> Optional[HTTPResponse]: """ Get the symbol buffer @param format: the image format diff --git a/src/tcgdexsdk/models/SetResume.py b/src/tcgdexsdk/models/SetResume.py index 3f01480..99c2460 100644 --- a/src/tcgdexsdk/models/SetResume.py +++ b/src/tcgdexsdk/models/SetResume.py @@ -3,10 +3,11 @@ from typing import Optional, Union from tcgdexsdk import utils -from tcgdexsdk.enums import Extension, Quality +from tcgdexsdk.enums import Extension from tcgdexsdk.models.Model import Model from tcgdexsdk.models.subs import SetCardCountResume + @dataclass class SetResume(Model): """Set resume""" @@ -51,7 +52,9 @@ def get_symbol_url(self, extension: Union[str, Extension]) -> Optional[str]: return f"{self.symbol}.{extension}" # noinspection PyShadowingBuiltins - def get_symbol(self, format: Union[str, Extension]) -> Optional[HTTPResponse]: + def get_symbol( + self, format: Union[str, Extension] + ) -> Optional[HTTPResponse]: """ Get the symbol buffer @param format: the image format diff --git a/src/tcgdexsdk/models/StringEndpoint.py b/src/tcgdexsdk/models/StringEndpoint.py index 386c5dd..9dc9057 100644 --- a/src/tcgdexsdk/models/StringEndpoint.py +++ b/src/tcgdexsdk/models/StringEndpoint.py @@ -1,14 +1,10 @@ from dataclasses import dataclass -from http.client import HTTPResponse -from typing import List, Optional, Union +from typing import List -from tcgdexsdk import utils -from tcgdexsdk.enums import Extension, Quality -from tcgdexsdk.models.Card import Card from tcgdexsdk.models.CardResume import CardResume -from tcgdexsdk.models.Serie import Serie from tcgdexsdk.models.Model import Model + @dataclass class StringEndpoint(Model): """Generic class that handle a lot of Endpoints""" diff --git a/src/tcgdexsdk/models/__init__.py b/src/tcgdexsdk/models/__init__.py index 81e7d18..8b13789 100644 --- a/src/tcgdexsdk/models/__init__.py +++ b/src/tcgdexsdk/models/__init__.py @@ -1,232 +1 @@ -# @dataclass -# class CardResume(Model): -# """Card Resume class, contains basic information about a specific card -# to get the full card you can use the `get_full_card()` function""" -# id: str -# """Globally unique card ID based on the set ID and the cards ID within the set""" -# localId: str -# """ID indexing this card within its set, usually just its number""" -# name: str -# """Card name""" -# image: Optional[str] -# """Card image url without the extension and quality""" - -# def get_image_url( -# self, quality: str | Quality, extension: str | Extension -# ) -> Optional[str]: -# """ -# the Card Image full URL -# @param quality: the quality you want your image to be in -# @param extension: extension you want you image to be -# @return: the full card URL with the extension and quality -# """ -# if self.image: -# return f"{self.image}/{quality}.{extension}" - -# # noinspection PyShadowingBuiltins -# def get_image( -# self, quality: str | Quality, format: str | Extension -# ) -> Optional[HTTPResponse]: -# """ -# Get image buffer -# @param quality: the quality you want your image to be in -# @param format: extension you want you image to be -# @return: the full card Buffer in the format you want -# """ -# if url := self.get_image_url(quality, format): -# return utils.download_image(url) - -# def get_full_card(self) -> Optional[Card]: -# """ -# Get the full Card -# @return: the full card if available -# """ -# return self.tcgdex.fetch_card(self.id) - - -# @dataclass -# class Card(CardResume): -# """Pokémon TCG Card, It contains every information about a specific card""" - -# illustrator: Optional[str] -# """Card illustrator""" -# rarity: str -# """Card rarity""" -# category: str -# """Card category""" -# variants: CardVariants -# """The card possible variants""" -# set: SetResume -# """Resume of the set the card belongs to""" -# dexIDs: Optional[list[int]] -# """the Pokémon Pokédex IDs (multiple if multiple pokémon appears on the card)""" -# hp: Optional[int] -# """HP of the pokemon""" -# types: Optional[list[str]] -# """Types of the pokemon (multiple because some have multiple in the older sets)""" -# evolvesFrom: Optional[str] -# """Name of the pokemon this one evolves from""" -# description: Optional[str] -# """the Pokémon Pokédex like description""" -# level: Optional[str] -# """the Pokémon Level (can be "X" if the card is of level X)""" -# stage: Optional[str] -# """the Pokémon Stage (changes depending on the API language)""" -# suffix: Optional[str] -# """the Pokémon Suffix (changes depending on the API language)""" -# item: Optional[CardItem] -# """the Item the Pokémon have""" -# abilities: Optional[list[CardAbility]] -# """the Card abilities (some cards have multiple abilities)""" -# attacks: Optional[list[CardAttack]] -# """the Card Attacks""" -# weaknesses: Optional[list[CardWeakRes]] -# """the Pokémon Weaknesses""" -# resistances: Optional[list[CardWeakRes]] -# """the Pokémon Resistances""" -# retreat: Optional[int] -# """the Pokémon retreat Cost""" -# effect: Optional[str] -# """effect the Card Effect (Trainer/Energy only)""" -# trainerType: Optional[str] -# """the trainer sub type (changes depending on the API language)""" -# energyType: Optional[str] -# """the energy sub type (changes depending on the API language)""" -# regulationMark: Optional[str] -# """the Card Regulation mark""" -# legal: Legal -# """the card ability to be played in tournaments""" - - -# @dataclass -# class SerieResume(Model): -# """Serie Resume""" - -# id: str -# """the Serie unique ID""" -# name: str -# """the Serie name""" -# logo: Optional[str] -# """the Serie Logo (basically also the first set logo)""" - -# def get_logo_url(self, extension: str | Extension) -> Optional[str]: -# """ -# Get the logo full url -# @param extension: the file extension you want to use -# @return: the full URL of the logo -# """ -# if self.logo: -# return f"{self.logo}.{extension}" - -# # noinspection PyShadowingBuiltins -# def get_logo(self, format: str | Extension) -> Optional[HTTPResponse]: -# """ -# Get the logo buffer -# @param format: the image format -# @return: a buffer containing the image -# """ -# if url := self.get_logo_url(format): -# return utils.download_image(url) - -# def get_full_series(self) -> Optional[Serie]: -# """ -# Get the full Serie -# @return: the full serie if available -# """ -# return self.tcgdex.fetch_serie(self.id) - - -# @dataclass -# class Serie(SerieResume): -# """Pokémon TCG Serie""" - -# sets: list[SetResume] -# """the list of sets the Serie contains""" - - -# @dataclass -# class SetResume(Model): -# """Set resume""" - -# id: str -# """Globally unique set ID""" -# name: str -# """the Set mame""" -# logo: Optional[str] -# """the Set Logo incomplete URL (use get_logo_url/get_logo)""" -# symbol: Optional[str] -# """the Set Symbol incomplete URL (use get_symbol_url/get_symbol)""" -# cardCount: SetCardCountResume -# """the number of card in the set""" - -# def get_logo_url(self, extension: str | Extension) -> Optional[str]: -# """ -# Get the logo full url -# @param extension: the file extension you want to use -# @return: the full URL of the logo -# """ -# if self.logo: -# return f"{self.logo}.{extension}" - -# # noinspection PyShadowingBuiltins -# def get_logo(self, format: str | Extension) -> Optional[HTTPResponse]: -# """ -# Get the logo buffer -# @param format: the image format -# @return: a buffer containing the image -# """ -# if url := self.get_logo_url(format): -# return utils.download_image(url) - -# def get_symbol_url(self, extension: str | Extension) -> Optional[str]: -# """ -# Get the symbol full url -# @param extension: the file extension you want to use -# @return: the full URL of the logo -# """ -# if self.symbol: -# return f"{self.symbol}.{extension}" - -# # noinspection PyShadowingBuiltins -# def get_symbol(self, format: str | Extension) -> Optional[HTTPResponse]: -# """ -# Get the symbol buffer -# @param format: the image format -# @return: a buffer containing the image -# """ -# if url := self.get_symbol_url(format): -# return utils.download_image(url) - -# def get_full_set(self) -> Optional[Set]: -# """ -# Get the full set -# @return: the full set if available -# """ -# return self.tcgdex.fetch_set(self.id) - - -# @dataclass -# class Set(SetResume): -# """Pokémon TCG Set class""" - -# serie: SerieResume -# """the serie this set is a part of""" -# tcgOnline: Optional[str] -# """the TCG Online Code""" -# releaseDate: str -# """the Set release date as yyyy-mm-dd""" -# legal: Legal -# """the set legality (won't indicate if a card is banned)""" -# cards: list[CardResume] -# """the cards contained in this set""" - - -# @dataclass -# class StringEndpoint(Model): -# """Generic class that handle a lot of Endpoints""" - -# name: str -# """the endpoint value""" -# cards: list[CardResume] -# """the cards that contain `name` in them""" diff --git a/src/tcgdexsdk/tcgdex.py b/src/tcgdexsdk/tcgdex.py index 25a9b55..27ba08a 100644 --- a/src/tcgdexsdk/tcgdex.py +++ b/src/tcgdexsdk/tcgdex.py @@ -2,14 +2,15 @@ from tcgdexsdk.endpoints.Endpoint import Endpoint from tcgdexsdk.enums import Language -from tcgdexsdk.models.CardResume import CardResume from tcgdexsdk.models.Card import Card +from tcgdexsdk.models.CardResume import CardResume from tcgdexsdk.models.Serie import Serie from tcgdexsdk.models.SerieResume import SerieResume from tcgdexsdk.models.Set import Set from tcgdexsdk.models.SetResume import SetResume from tcgdexsdk.models.StringEndpoint import StringEndpoint + class TCGdex: """The main TCGdex SDK instance""" @@ -26,16 +27,18 @@ def __init__(self, language: Union[str, Language]): self.set = Endpoint(self, Set, SetResume, "sets") self.serie = Endpoint(self, Serie, SerieResume, "series") - self.variant = Endpoint(self, StringEndpoint, str, 'variants') - 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.energyType = Endpoint(self, StringEndpoint, str, 'energy-types') - self.dexId = Endpoint(self, StringEndpoint, int, 'dex-ids') - self.type = Endpoint(self, StringEndpoint, str, 'types') - self.retreat = Endpoint(self, StringEndpoint, int, 'retreats') - self.rarity = Endpoint(self, StringEndpoint, str, 'rarities') - self.illustrator = Endpoint(self, StringEndpoint, str, 'illustrators') - self.hp = Endpoint(self, StringEndpoint, int, 'hp') - self.category = Endpoint(self, StringEndpoint, str, 'categories') + self.variant = Endpoint(self, StringEndpoint, str, "variants") + 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.energyType = Endpoint(self, StringEndpoint, str, "energy-types") + self.dexId = Endpoint(self, StringEndpoint, int, "dex-ids") + self.type = Endpoint(self, StringEndpoint, str, "types") + self.retreat = Endpoint(self, StringEndpoint, int, "retreats") + self.rarity = Endpoint(self, StringEndpoint, str, "rarities") + self.illustrator = Endpoint(self, StringEndpoint, str, "illustrators") + self.hp = Endpoint(self, StringEndpoint, int, "hp") + self.category = Endpoint(self, StringEndpoint, str, "categories") diff --git a/src/tcgdexsdk/utils.py b/src/tcgdexsdk/utils.py index b76a48d..4601ad9 100644 --- a/src/tcgdexsdk/utils.py +++ b/src/tcgdexsdk/utils.py @@ -1,14 +1,13 @@ import json import time -import typing from functools import lru_cache from http.client import HTTPResponse -from typing import List, Optional, Type, TypeVar, Union +from typing import List, Optional, Type, TypeVar from urllib.request import Request, urlopen -from importlib.metadata import version + from dacite import from_dict -import tcgdexsdk +from tcgdexsdk import __version__ from tcgdexsdk.models.Model import Model _T = TypeVar("_T") @@ -18,24 +17,30 @@ def _request(url: str) -> Request: + return Request( + url, + headers={"User-Agent": f"@tcgdex/python-sdk@{__version__}"}, + ) - return Request(url, headers={"User-Agent": f"@tcgdex/python-sdk@{tcgdexsdk.__version__}"}) @lru_cache def _urlopen(url: str, _: float) -> str: return urlopen(_request(url)).read().decode() + def _from_dict(cls: Type[_TM], data: dict, tcgdex) -> _TM: self = from_dict(cls, data) self.sdk = tcgdex return self + def fetch(tcgdex, url: str, cls: Type[_T]) -> Optional[_T]: if not issubclass(cls, Model): return None data = json.loads(_urlopen(url, time.monotonic() // (ttl * 60))) return _from_dict(cls, data, tcgdex) + def fetch_list(tcgdex, url: str, cls: Type[_T]) -> List[_T]: data = json.loads(_urlopen(url, time.monotonic() // (ttl * 60))) res = [] @@ -45,5 +50,6 @@ def fetch_list(tcgdex, url: str, cls: Type[_T]) -> List[_T]: res.append(_from_dict(cls, item, tcgdex)) return res + def download_image(url: str) -> HTTPResponse: return urlopen(_request(url)) diff --git a/tests/tests.py b/tests/tests.py index 660cf01..a09a829 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -1,9 +1,9 @@ -from unittest import IsolatedAsyncioTestCase -from typing import Callable, List +import unittest +from typing import Callable import vcr -from tcgdexsdk import TCGdex, Language +from tcgdexsdk import Language, TCGdex from tcgdexsdk.models.Card import Card from tcgdexsdk.models.CardResume import CardResume from tcgdexsdk.models.Serie import Serie @@ -12,12 +12,12 @@ from tcgdexsdk.models.SetResume import SetResume from tcgdexsdk.models.StringEndpoint import StringEndpoint + def _use_cassette(test: Callable) -> Callable: - return vcr.use_cassette(f"tests/.fixtures/{test.__name__}.yaml")( - test - ) + return vcr.use_cassette(f"tests/.fixtures/{test.__name__}.yaml")(test) + -class APITest(IsolatedAsyncioTestCase): +class APITest(unittest.IsolatedAsyncioTestCase): def setUp(self): self.api = TCGdex(Language.EN) @@ -58,7 +58,7 @@ async def test_variant_list(self): @_use_cassette async def test_variant_item(self): - res = await self.api.variant.get('reverse') + res = await self.api.variant.get("reverse") self.assertIsInstance(res, StringEndpoint) @_use_cassette @@ -68,7 +68,7 @@ async def test_trainerType_list(self): @_use_cassette async def test_trainerType_item(self): - res = await self.api.trainerType.get('trainer') + res = await self.api.trainerType.get("trainer") self.assertIsInstance(res, StringEndpoint) @_use_cassette @@ -78,7 +78,7 @@ async def test_suffix_list(self): @_use_cassette async def test_suffix_item(self): - res = await self.api.suffix.get('ex') + res = await self.api.suffix.get("ex") self.assertIsInstance(res, StringEndpoint) @_use_cassette @@ -88,7 +88,7 @@ async def test_stage_list(self): @_use_cassette async def test_stage_item(self): - res = await self.api.stage.get('stage1') + res = await self.api.stage.get("stage1") self.assertIsInstance(res, StringEndpoint) @_use_cassette @@ -98,7 +98,7 @@ async def test_regulationMark_list(self): @_use_cassette async def test_regulationMark_item(self): - res = await self.api.regulationMark.get('D') + res = await self.api.regulationMark.get("D") self.assertIsInstance(res, StringEndpoint) @_use_cassette @@ -108,7 +108,7 @@ async def test_energyType_list(self): @_use_cassette async def test_energyType_item(self): - res = await self.api.energyType.get('normal') + res = await self.api.energyType.get("normal") self.assertIsInstance(res, StringEndpoint) @_use_cassette @@ -118,7 +118,7 @@ async def test_dexId_list(self): @_use_cassette async def test_dexId_item(self): - res = await self.api.dexId.get('1') + res = await self.api.dexId.get("1") self.assertIsInstance(res, StringEndpoint) @_use_cassette @@ -128,7 +128,7 @@ async def test_type_list(self): @_use_cassette async def test_type_item(self): - res = await self.api.type.get('grass') + res = await self.api.type.get("grass") self.assertIsInstance(res, StringEndpoint) @_use_cassette @@ -138,7 +138,7 @@ async def test_retreat_list(self): @_use_cassette async def test_retreat_item(self): - res = await self.api.retreat.get('1') + res = await self.api.retreat.get("1") self.assertIsInstance(res, StringEndpoint) @_use_cassette @@ -148,7 +148,7 @@ async def test_rarity_list(self): @_use_cassette async def test_rarity_item(self): - res = await self.api.rarity.get('common') + res = await self.api.rarity.get("common") self.assertIsInstance(res, StringEndpoint) @_use_cassette @@ -158,7 +158,7 @@ async def test_illustrator_list(self): @_use_cassette async def test_illustrator_item(self): - res = await self.api.illustrator.get('0313') + res = await self.api.illustrator.get("0313") self.assertIsInstance(res, StringEndpoint) @_use_cassette @@ -168,7 +168,7 @@ async def test_hp_list(self): @_use_cassette async def test_hp_item(self): - res = await self.api.hp.get('10') + res = await self.api.hp.get("10") self.assertIsInstance(res, StringEndpoint) @_use_cassette @@ -178,11 +178,10 @@ async def test_category_list(self): @_use_cassette async def test_category_item(self): - res = await self.api.category.get('pokemon') + res = await self.api.category.get("pokemon") self.assertIsInstance(res, StringEndpoint) - def main(): unittest.main()