bgg_search

 1from importlib.metadata import version
 2
 3from bgg_search._protocol import BggClientProtocol
 4from bgg_search.exceptions import BggApiError, BggNotFoundError, BggParseError, BggSearchError
 5from bgg_search.models import GameDetails, GameSummary
 6from bgg_search.search import get_game, search_games
 7
 8__version__ = version("bgg-search")
 9
10__all__ = [
11    "__version__",
12    "BggClientProtocol",
13    "BggApiError",
14    "BggNotFoundError",
15    "BggParseError",
16    "BggSearchError",
17    "GameDetails",
18    "GameSummary",
19    "get_game",
20    "search_games",
21]
__version__ = '0.6.0'
@runtime_checkable
class BggClientProtocol(typing.Protocol):
 7@runtime_checkable
 8class BggClientProtocol(Protocol):
 9    """Contract for BGG API client implementations.
10
11    Pass any conforming object to `search_games` or `get_game`.
12    The bundled `BggClient` satisfies this protocol.
13    """
14
15    def search(self, query: str) -> list[GameSummary]:
16        """Search BGG for board games matching `query`.
17
18        Returns results in BGG API order; returns an empty list when no games match.
19        """
20        ...
21
22    def get_game(self, game_id: int) -> GameDetails:
23        """Fetch full details for the game identified by `game_id`.
24
25        Raises `BggNotFoundError` when the ID does not exist on BGG.
26        """
27        ...

Contract for BGG API client implementations.

Pass any conforming object to search_games or get_game. The bundled BggClient satisfies this protocol.

BggClientProtocol(*args, **kwargs)
1960def _no_init_or_replace_init(self, *args, **kwargs):
1961    cls = type(self)
1962
1963    if cls._is_protocol:
1964        raise TypeError('Protocols cannot be instantiated')
1965
1966    # Already using a custom `__init__`. No need to calculate correct
1967    # `__init__` to call. This can lead to RecursionError. See bpo-45121.
1968    if cls.__init__ is not _no_init_or_replace_init:
1969        return
1970
1971    # Initially, `__init__` of a protocol subclass is set to `_no_init_or_replace_init`.
1972    # The first instantiation of the subclass will call `_no_init_or_replace_init` which
1973    # searches for a proper new `__init__` in the MRO. The new `__init__`
1974    # replaces the subclass' old `__init__` (ie `_no_init_or_replace_init`). Subsequent
1975    # instantiation of the protocol subclass will thus use the new
1976    # `__init__` and no longer call `_no_init_or_replace_init`.
1977    for base in cls.__mro__:
1978        init = base.__dict__.get('__init__', _no_init_or_replace_init)
1979        if init is not _no_init_or_replace_init:
1980            cls.__init__ = init
1981            break
1982    else:
1983        # should not happen
1984        cls.__init__ = object.__init__
1985
1986    cls.__init__(self, *args, **kwargs)
def search(self, query: str) -> list[GameSummary]:
15    def search(self, query: str) -> list[GameSummary]:
16        """Search BGG for board games matching `query`.
17
18        Returns results in BGG API order; returns an empty list when no games match.
19        """
20        ...

Search BGG for board games matching query.

Returns results in BGG API order; returns an empty list when no games match.

def get_game(self, game_id: int) -> GameDetails:
22    def get_game(self, game_id: int) -> GameDetails:
23        """Fetch full details for the game identified by `game_id`.
24
25        Raises `BggNotFoundError` when the ID does not exist on BGG.
26        """
27        ...

Fetch full details for the game identified by game_id.

Raises BggNotFoundError when the ID does not exist on BGG.

class BggApiError(bgg_search.BggSearchError):
 6class BggApiError(BggSearchError):
 7    """Raised when the BGG API returns an HTTP error.
 8
 9    ``status_code`` holds the HTTP status code, or ``None`` if the error
10    occurred before a response was received.
11    """
12
13    def __init__(self, message: str, status_code: int | None = None) -> None:
14        super().__init__(message)
15        self.status_code = status_code

Raised when the BGG API returns an HTTP error.

status_code holds the HTTP status code, or None if the error occurred before a response was received.

BggApiError(message: str, status_code: int | None = None)
13    def __init__(self, message: str, status_code: int | None = None) -> None:
14        super().__init__(message)
15        self.status_code = status_code
status_code
class BggNotFoundError(bgg_search.BggSearchError):
18class BggNotFoundError(BggSearchError):
19    """Raised when the requested game ID does not exist on BGG."""

Raised when the requested game ID does not exist on BGG.

class BggParseError(bgg_search.BggSearchError):
22class BggParseError(BggSearchError):
23    """Raised when the BGG API response cannot be parsed."""

Raised when the BGG API response cannot be parsed.

class BggSearchError(builtins.Exception):
2class BggSearchError(Exception):
3    """Base class for all bgg-search exceptions."""

Base class for all bgg-search exceptions.

@dataclass(frozen=True)
class GameDetails:
15@dataclass(frozen=True)
16class GameDetails:
17    """Full details for a board game retrieved from BGG."""
18
19    id: int
20    """BGG game ID."""
21    name: str
22    """Primary game title."""
23    year_published: int | None
24    """Year of first publication, or ``None`` if unknown."""
25    min_players: int | None
26    """Minimum number of players, or ``None`` if unknown."""
27    max_players: int | None
28    """Maximum number of players, or ``None`` if unknown."""
29    min_playtime: int | None
30    """Minimum play time in minutes, or ``None`` if unknown."""
31    max_playtime: int | None
32    """Maximum play time in minutes, or ``None`` if unknown."""
33    weight: float | None
34    """BGG complexity weight on a 1.0–5.0 scale, or ``None`` if unrated."""
35    bgg_rating: float | None
36    """BGG community rating on a 1.0–10.0 scale, or ``None`` if unrated."""

Full details for a board game retrieved from BGG.

GameDetails( id: int, name: str, year_published: int | None, min_players: int | None, max_players: int | None, min_playtime: int | None, max_playtime: int | None, weight: float | None, bgg_rating: float | None)
id: int

BGG game ID.

name: str

Primary game title.

year_published: int | None

Year of first publication, or None if unknown.

min_players: int | None

Minimum number of players, or None if unknown.

max_players: int | None

Maximum number of players, or None if unknown.

min_playtime: int | None

Minimum play time in minutes, or None if unknown.

max_playtime: int | None

Maximum play time in minutes, or None if unknown.

weight: float | None

BGG complexity weight on a 1.0–5.0 scale, or None if unrated.

bgg_rating: float | None

BGG community rating on a 1.0–10.0 scale, or None if unrated.

@dataclass(frozen=True)
class GameSummary:
 5@dataclass(frozen=True)
 6class GameSummary:
 7    """A board game entry returned from a BGG search."""
 8
 9    id: int
10    """BGG game ID."""
11    name: str
12    """Primary game title."""

A board game entry returned from a BGG search.

GameSummary(id: int, name: str)
id: int

BGG game ID.

name: str

Primary game title.

def get_game( game_id: int, client: BggClientProtocol) -> GameDetails:
14def get_game(game_id: int, client: BggClientProtocol) -> GameDetails:
15    """Fetch full details for the game identified by `game_id` using `client`.
16
17    Raises `BggNotFoundError` when the ID does not exist on BGG.
18    """
19    return client.get_game(game_id)

Fetch full details for the game identified by game_id using client.

Raises BggNotFoundError when the ID does not exist on BGG.

def search_games( query: str, client: BggClientProtocol) -> list[GameSummary]:
 6def search_games(query: str, client: BggClientProtocol) -> list[GameSummary]:
 7    """Search BGG for board games matching `query` using `client`.
 8
 9    Returns results in BGG API order; returns an empty list when no games match.
10    """
11    return client.search(query)

Search BGG for board games matching query using client.

Returns results in BGG API order; returns an empty list when no games match.