baseball-api-wrapper 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,102 @@
1
+ Metadata-Version: 2.4
2
+ Name: baseball-api-wrapper
3
+ Version: 0.1.0
4
+ Summary: A Python wrapper for the official MLB Stats API (https://statsapi.mlb.com)
5
+ License-Expression: MIT
6
+ Requires-Python: >=3.9
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE
9
+ Requires-Dist: requests>=2.28
10
+ Provides-Extra: dev
11
+ Requires-Dist: pytest>=7.0; extra == "dev"
12
+ Requires-Dist: pytest-cov>=4.0; extra == "dev"
13
+ Requires-Dist: responses>=0.23; extra == "dev"
14
+ Dynamic: license-file
15
+
16
+ # baseball-api-wrapper
17
+
18
+ A Python wrapper for the official [MLB Stats API](https://statsapi.mlb.com).
19
+
20
+ ## Installation
21
+
22
+ Clone the repo and install in editable mode so changes to the source are reflected immediately:
23
+
24
+ ```bash
25
+ git clone <your-repo-url>
26
+ cd baseball-api-wrapper
27
+ pip install -e ".[dev]" # includes pytest and test dependencies
28
+ ```
29
+
30
+ For use in another project without dev tools:
31
+
32
+ ```bash
33
+ pip install -e /path/to/baseball-api-wrapper
34
+ ```
35
+
36
+ ## Quick Start
37
+
38
+ ```python
39
+ from baseball_api_wrapper import get_teams, get_roster
40
+
41
+ # List all MLB teams for the 2024 season
42
+ teams = get_teams(2024)
43
+ for team in teams:
44
+ print(team["id"], team["name"])
45
+
46
+ # Get the active roster for the New York Yankees (teamId=147)
47
+ roster = get_roster(147, season=2024)
48
+ for player in roster:
49
+ print(player["person"]["fullName"], player["position"]["name"])
50
+ ```
51
+
52
+ ## Using the Low-Level Client
53
+
54
+ For endpoints not yet covered by a module, use `MLBStatsClient` directly:
55
+
56
+ ```python
57
+ from baseball_api_wrapper import MLBStatsClient
58
+
59
+ with MLBStatsClient() as client:
60
+ data = client.get("/api/v1/standings", params={"leagueId": 103, "season": 2024})
61
+ print(data)
62
+ ```
63
+
64
+ ## Project Structure
65
+
66
+ ```
67
+ baseball_api_wrapper/ # Installable package
68
+ __init__.py # Public API surface
69
+ client.py # Low-level HTTP client (MLBStatsClient, MLBStatsAPIError)
70
+ modules/
71
+ teams.py # get_teams()
72
+ roster.py # get_roster()
73
+ tests/ # pytest test suite
74
+ test_teams.py
75
+ test_roster.py
76
+ pyproject.toml # Build & dependency config
77
+ ```
78
+
79
+ ## Running Tests
80
+
81
+ ```bash
82
+ pytest # Run all tests
83
+ pytest --cov=baseball_api_wrapper # Run with coverage report
84
+ ```
85
+
86
+ ## Error Handling
87
+
88
+ Network or API errors raise `MLBStatsAPIError`:
89
+
90
+ ```python
91
+ from baseball_api_wrapper import MLBStatsClient, MLBStatsAPIError
92
+
93
+ try:
94
+ with MLBStatsClient() as client:
95
+ data = client.get("/api/v1/teams/99999") # Non-existent team
96
+ except MLBStatsAPIError as e:
97
+ print(f"API error {e.status_code}: {e.message}")
98
+ ```
99
+
100
+ ## License
101
+
102
+ MIT — see [LICENSE](LICENSE) for details.
@@ -0,0 +1,87 @@
1
+ # baseball-api-wrapper
2
+
3
+ A Python wrapper for the official [MLB Stats API](https://statsapi.mlb.com).
4
+
5
+ ## Installation
6
+
7
+ Clone the repo and install in editable mode so changes to the source are reflected immediately:
8
+
9
+ ```bash
10
+ git clone <your-repo-url>
11
+ cd baseball-api-wrapper
12
+ pip install -e ".[dev]" # includes pytest and test dependencies
13
+ ```
14
+
15
+ For use in another project without dev tools:
16
+
17
+ ```bash
18
+ pip install -e /path/to/baseball-api-wrapper
19
+ ```
20
+
21
+ ## Quick Start
22
+
23
+ ```python
24
+ from baseball_api_wrapper import get_teams, get_roster
25
+
26
+ # List all MLB teams for the 2024 season
27
+ teams = get_teams(2024)
28
+ for team in teams:
29
+ print(team["id"], team["name"])
30
+
31
+ # Get the active roster for the New York Yankees (teamId=147)
32
+ roster = get_roster(147, season=2024)
33
+ for player in roster:
34
+ print(player["person"]["fullName"], player["position"]["name"])
35
+ ```
36
+
37
+ ## Using the Low-Level Client
38
+
39
+ For endpoints not yet covered by a module, use `MLBStatsClient` directly:
40
+
41
+ ```python
42
+ from baseball_api_wrapper import MLBStatsClient
43
+
44
+ with MLBStatsClient() as client:
45
+ data = client.get("/api/v1/standings", params={"leagueId": 103, "season": 2024})
46
+ print(data)
47
+ ```
48
+
49
+ ## Project Structure
50
+
51
+ ```
52
+ baseball_api_wrapper/ # Installable package
53
+ __init__.py # Public API surface
54
+ client.py # Low-level HTTP client (MLBStatsClient, MLBStatsAPIError)
55
+ modules/
56
+ teams.py # get_teams()
57
+ roster.py # get_roster()
58
+ tests/ # pytest test suite
59
+ test_teams.py
60
+ test_roster.py
61
+ pyproject.toml # Build & dependency config
62
+ ```
63
+
64
+ ## Running Tests
65
+
66
+ ```bash
67
+ pytest # Run all tests
68
+ pytest --cov=baseball_api_wrapper # Run with coverage report
69
+ ```
70
+
71
+ ## Error Handling
72
+
73
+ Network or API errors raise `MLBStatsAPIError`:
74
+
75
+ ```python
76
+ from baseball_api_wrapper import MLBStatsClient, MLBStatsAPIError
77
+
78
+ try:
79
+ with MLBStatsClient() as client:
80
+ data = client.get("/api/v1/teams/99999") # Non-existent team
81
+ except MLBStatsAPIError as e:
82
+ print(f"API error {e.status_code}: {e.message}")
83
+ ```
84
+
85
+ ## License
86
+
87
+ MIT — see [LICENSE](LICENSE) for details.
@@ -0,0 +1,32 @@
1
+ """
2
+ baseball_api_wrapper
3
+ ====================
4
+ A Python wrapper for the official MLB Stats API (https://statsapi.mlb.com).
5
+
6
+ Quick start::
7
+
8
+ from baseball_api_wrapper import get_teams
9
+
10
+ teams = get_teams(2024)
11
+ for team in teams:
12
+ print(team["id"], team["name"])
13
+ """
14
+
15
+ from .client import MLBStatsAPIError, MLBStatsClient
16
+ from .modules.teams import get_teams
17
+ from .modules.roster import get_roster
18
+ from .modules.players import get_player_info, get_player_stats, get_player_career_splits
19
+ from .modules.games import get_schedule, get_boxscore, get_game_by_pk
20
+
21
+ __all__ = [
22
+ "MLBStatsClient",
23
+ "MLBStatsAPIError",
24
+ "get_teams",
25
+ "get_roster",
26
+ "get_player_info",
27
+ "get_player_stats",
28
+ "get_player_career_splits",
29
+ "get_schedule",
30
+ "get_boxscore",
31
+ "get_game_by_pk",
32
+ ]
@@ -0,0 +1,86 @@
1
+ """
2
+ MLB Stats API Client
3
+ ====================
4
+ A Python wrapper for the official MLB Stats API (https://statsapi.mlb.com).
5
+
6
+ This module provides a low-level HTTP client that handles request construction,
7
+ error handling, and response parsing for the MLB Stats API.
8
+ """
9
+
10
+ import requests
11
+ from typing import Any, Dict, Optional
12
+
13
+
14
+ class MLBStatsAPIError(Exception):
15
+ """Raised when the MLB Stats API returns an error response."""
16
+
17
+ def __init__(self, status_code: int, message: str):
18
+ self.status_code = status_code
19
+ self.message = message
20
+ super().__init__(f"MLB Stats API error {status_code}: {message}")
21
+
22
+
23
+ class MLBStatsClient:
24
+ """
25
+ Low-level HTTP client for the MLB Stats API.
26
+
27
+ Handles base URL configuration, session management, and common
28
+ request/response logic. Higher-level endpoint wrappers build on
29
+ top of this class.
30
+
31
+ Args:
32
+ base_url: The root URL of the Stats API. Defaults to the
33
+ official production endpoint.
34
+ timeout: Request timeout in seconds. Defaults to 10.
35
+
36
+ Example::
37
+
38
+ client = MLBStatsClient()
39
+ data = client.get("/api/v1/teams", params={"season": "2024", "sportId": 1})
40
+ """
41
+
42
+ DEFAULT_BASE_URL = "https://statsapi.mlb.com"
43
+
44
+ def __init__(
45
+ self,
46
+ base_url: str = DEFAULT_BASE_URL,
47
+ timeout: int = 10,
48
+ ):
49
+ self.base_url = base_url.rstrip("/")
50
+ self.timeout = timeout
51
+ self._session = requests.Session()
52
+ self._session.headers.update({"Accept": "application/json"})
53
+
54
+ def get(self, path: str, params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
55
+ """
56
+ Perform a GET request against the Stats API.
57
+
58
+ Args:
59
+ path: API path, e.g. ``"/api/v1/teams"``.
60
+ params: Optional dictionary of query-string parameters.
61
+
62
+ Returns:
63
+ Parsed JSON response as a Python dictionary.
64
+
65
+ Raises:
66
+ MLBStatsAPIError: If the server returns a non-2xx status code.
67
+ requests.RequestException: On network-level failures.
68
+ """
69
+ url = f"{self.base_url}{path}"
70
+ response = self._session.get(url, params=params, timeout=self.timeout)
71
+
72
+ if not response.ok:
73
+ raise MLBStatsAPIError(response.status_code, response.text)
74
+
75
+ return response.json()
76
+
77
+ def close(self):
78
+ """Close the underlying HTTP session, freeing connection-pool resources."""
79
+ self._session.close()
80
+
81
+ # Support use as a context manager
82
+ def __enter__(self):
83
+ return self
84
+
85
+ def __exit__(self, *_):
86
+ self.close()
@@ -0,0 +1,147 @@
1
+ """
2
+ Games
3
+ =====
4
+ Functions for retrieving MLB game schedule and score data from the Stats API.
5
+
6
+ The primary entry point is :func:`get_schedule`, which returns games for a
7
+ given date. By default it fetches regular-season MLB games only.
8
+ """
9
+
10
+ from typing import Any, Dict, List, Optional
11
+
12
+ from ..client import MLBStatsClient
13
+
14
+ _SCHEDULE_PATH = "/api/v1/schedule"
15
+ _BOXSCORE_PATH = "/api/v1/game/{game_pk}/boxscore"
16
+
17
+ MLB_SPORT_ID = 1
18
+
19
+
20
+ def get_schedule(
21
+ date: str,
22
+ sport_id: int = MLB_SPORT_ID,
23
+ game_type: str = "R",
24
+ client: Optional[MLBStatsClient] = None,
25
+ ) -> List[Dict[str, Any]]:
26
+ """
27
+ Return all games scheduled for the given date.
28
+
29
+ Args:
30
+ date:
31
+ The date to query in ``YYYY-MM-DD`` format, e.g. ``"2024-04-01"``.
32
+ sport_id:
33
+ Top-level sport identifier. Use ``1`` (default) for MLB.
34
+ game_type:
35
+ Game type filter. ``"R"`` (default) returns regular-season games.
36
+ Pass ``"S"`` for spring training, ``"P"`` for playoffs, or ``"A"``
37
+ for the All-Star game.
38
+ client:
39
+ Optional pre-configured :class:`~baseball_api_wrapper.client.MLBStatsClient`.
40
+ If omitted, a default client is created for this single call.
41
+
42
+ Returns:
43
+ A list of game dictionaries as returned by the MLB Stats API
44
+ ``/api/v1/schedule`` endpoint. Returns an empty list when no games
45
+ are scheduled for the requested date.
46
+
47
+ Raises:
48
+ baseball_api_wrapper.client.MLBStatsAPIError:
49
+ If the API returns a non-2xx HTTP status code.
50
+ requests.RequestException:
51
+ On network-level failures.
52
+ """
53
+ params: Dict[str, Any] = {
54
+ "sportId": sport_id,
55
+ "date": date,
56
+ "gameType": game_type,
57
+ }
58
+
59
+ _owns_client = client is None
60
+ if _owns_client:
61
+ client = MLBStatsClient()
62
+
63
+ try:
64
+ data = client.get(_SCHEDULE_PATH, params=params)
65
+ finally:
66
+ if _owns_client:
67
+ client.close()
68
+
69
+ dates = data.get("dates", [])
70
+ if not dates:
71
+ return []
72
+ return dates[0].get("games", [])
73
+
74
+
75
+ def get_game_by_pk(
76
+ game_pk: int,
77
+ client: Optional[MLBStatsClient] = None,
78
+ ) -> Dict[str, Any]:
79
+ """
80
+ Return the schedule entry for a single game by its ``gamePk``.
81
+
82
+ Useful for fetching lightweight metadata (status, date, teams) without
83
+ the full boxscore payload.
84
+
85
+ Args:
86
+ game_pk: The unique game identifier.
87
+ client: Optional pre-configured :class:`~baseball_api_wrapper.client.MLBStatsClient`.
88
+
89
+ Returns:
90
+ The game dictionary for the requested ``gamePk``, or an empty dict
91
+ if the game is not found.
92
+ """
93
+ params: Dict[str, Any] = {"gamePks": game_pk, "sportId": MLB_SPORT_ID}
94
+
95
+ _owns_client = client is None
96
+ if _owns_client:
97
+ client = MLBStatsClient()
98
+
99
+ try:
100
+ data = client.get(_SCHEDULE_PATH, params=params)
101
+ finally:
102
+ if _owns_client:
103
+ client.close()
104
+
105
+ dates = data.get("dates", [])
106
+ if not dates:
107
+ return {}
108
+ games = dates[0].get("games", [])
109
+ return games[0] if games else {}
110
+
111
+
112
+ def get_boxscore(
113
+ game_pk: int,
114
+ client: Optional[MLBStatsClient] = None,
115
+ ) -> Dict[str, Any]:
116
+ """
117
+ Return the box score for a single game.
118
+
119
+ Args:
120
+ game_pk:
121
+ The unique game identifier (``gamePk``) returned by
122
+ :func:`get_schedule`.
123
+ client:
124
+ Optional pre-configured :class:`~baseball_api_wrapper.client.MLBStatsClient`.
125
+ If omitted, a default client is created for this single call.
126
+
127
+ Returns:
128
+ The raw box score dictionary as returned by the MLB Stats API
129
+ ``/api/v1/game/{gamePk}/boxscore`` endpoint.
130
+
131
+ Raises:
132
+ baseball_api_wrapper.client.MLBStatsAPIError:
133
+ If the API returns a non-2xx HTTP status code.
134
+ requests.RequestException:
135
+ On network-level failures.
136
+ """
137
+ path = _BOXSCORE_PATH.format(game_pk=game_pk)
138
+
139
+ _owns_client = client is None
140
+ if _owns_client:
141
+ client = MLBStatsClient()
142
+
143
+ try:
144
+ return client.get(path)
145
+ finally:
146
+ if _owns_client:
147
+ client.close()
@@ -0,0 +1,178 @@
1
+ """
2
+ Players
3
+ =======
4
+ Functions for retrieving player information and statistics from the MLB Stats API.
5
+
6
+ The two primary entry points are:
7
+
8
+ * :func:`get_player_info` – Basic biographical data for a player.
9
+ * :func:`get_player_stats` – Season statistics for a player, split by group
10
+ (``"hitting"`` or ``"pitching"``).
11
+ """
12
+
13
+ from typing import Any, Dict, List, Optional
14
+
15
+ from ..client import MLBStatsClient
16
+
17
+ _PLAYER_INFO_PATH = "/api/v1/people/{player_id}"
18
+ _PLAYER_STATS_PATH = "/api/v1/people/{player_id}/stats"
19
+
20
+
21
+ def get_player_career_splits(
22
+ player_id: int,
23
+ group: str = "hitting",
24
+ client: Optional[MLBStatsClient] = None,
25
+ ) -> List[Dict[str, Any]]:
26
+ """
27
+ Return year-by-year career splits for a player.
28
+
29
+ Each element in the returned list is a split dict with at minimum:
30
+ * ``season`` – The season year as a string, e.g. ``"2024"``.
31
+ * ``stat`` – Dict of raw stat fields for that season.
32
+
33
+ Args:
34
+ player_id: The player's unique MLB identifier.
35
+ group: ``"hitting"`` or ``"pitching"``. Defaults to ``"hitting"``.
36
+ client: Optional pre-configured MLBStatsClient.
37
+
38
+ Returns:
39
+ A list of split dicts, one per season, or an empty list if none found.
40
+ """
41
+ path = _PLAYER_STATS_PATH.format(player_id=player_id)
42
+ params: Dict[str, Any] = {"stats": "yearByYear", "group": group, "hydrate": "team"}
43
+
44
+ _owns_client = client is None
45
+ if _owns_client:
46
+ client = MLBStatsClient()
47
+
48
+ try:
49
+ data = client.get(path, params=params)
50
+ finally:
51
+ if _owns_client:
52
+ client.close()
53
+
54
+ for stat_block in data.get("stats", []):
55
+ splits = stat_block.get("splits", [])
56
+ if splits:
57
+ return splits
58
+
59
+ return []
60
+
61
+
62
+ def get_player_info(
63
+ player_id: int,
64
+ client: Optional[MLBStatsClient] = None,
65
+ ) -> Dict[str, Any]:
66
+ """
67
+ Return biographical information for a single player.
68
+
69
+ The returned dict contains at minimum:
70
+
71
+ * ``id`` – Player's unique MLB identifier.
72
+ * ``fullName`` – Full display name.
73
+ * ``primaryPosition`` – Nested dict with ``code``, ``name``, ``type``,
74
+ ``abbreviation``.
75
+ * ``active`` – Boolean indicating whether the player is active.
76
+
77
+ Args:
78
+ player_id:
79
+ The player's unique MLB identifier, e.g. ``660271`` for Juan Soto.
80
+ client:
81
+ Optional pre-configured :class:`~baseball_api_wrapper.client.MLBStatsClient`.
82
+ If omitted, a default client is created for the single call.
83
+
84
+ Returns:
85
+ A dict of player attributes as returned by the MLB Stats API.
86
+
87
+ Raises:
88
+ mlb_statsapi.client.MLBStatsAPIError:
89
+ If the API returns a non-2xx HTTP status code.
90
+ requests.RequestException:
91
+ On network-level failures.
92
+ KeyError:
93
+ If the response contains no ``people`` entry for the given ID.
94
+ """
95
+ path = _PLAYER_INFO_PATH.format(player_id=player_id)
96
+
97
+ _owns_client = client is None
98
+ if _owns_client:
99
+ client = MLBStatsClient()
100
+
101
+ try:
102
+ data = client.get(path)
103
+ finally:
104
+ if _owns_client:
105
+ client.close()
106
+
107
+ people: List[Dict[str, Any]] = data.get("people", [])
108
+ if not people:
109
+ raise KeyError(f"No player found with id {player_id}")
110
+
111
+ return people[0]
112
+
113
+
114
+ def get_player_stats(
115
+ player_id: int,
116
+ season: int | str,
117
+ group: str = "hitting",
118
+ client: Optional[MLBStatsClient] = None,
119
+ ) -> Optional[Dict[str, Any]]:
120
+ """
121
+ Return season statistics for a player for a specific stat group.
122
+
123
+ Args:
124
+ player_id:
125
+ The player's unique MLB identifier.
126
+ season:
127
+ The MLB season year, e.g. ``2024`` or ``"2024"``.
128
+ group:
129
+ The stat group to retrieve: ``"hitting"`` or ``"pitching"``.
130
+ Defaults to ``"hitting"``.
131
+ client:
132
+ Optional pre-configured :class:`~baseball_api_wrapper.client.MLBStatsClient`.
133
+ If omitted, a default client is created for the single call.
134
+
135
+ Returns:
136
+ A dict of raw stat fields as returned by the MLB Stats API (the
137
+ ``stat`` object from the first split), or ``None`` if no stats are
138
+ available for this player/season/group combination.
139
+
140
+ Raises:
141
+ mlb_statsapi.client.MLBStatsAPIError:
142
+ If the API returns a non-2xx HTTP status code.
143
+ requests.RequestException:
144
+ On network-level failures.
145
+
146
+ Example::
147
+
148
+ from baseball_api_wrapper.modules.players import get_player_stats
149
+
150
+ # Juan Soto's 2024 hitting stats
151
+ stats = get_player_stats(660271, 2024, group="hitting")
152
+ if stats:
153
+ print(stats["avg"], stats["homeRuns"], stats["rbi"])
154
+ """
155
+ path = _PLAYER_STATS_PATH.format(player_id=player_id)
156
+
157
+ params: Dict[str, Any] = {
158
+ "stats": "season",
159
+ "season": str(season),
160
+ "group": group,
161
+ }
162
+
163
+ _owns_client = client is None
164
+ if _owns_client:
165
+ client = MLBStatsClient()
166
+
167
+ try:
168
+ data = client.get(path, params=params)
169
+ finally:
170
+ if _owns_client:
171
+ client.close()
172
+
173
+ for stat_block in data.get("stats", []):
174
+ splits = stat_block.get("splits", [])
175
+ if splits:
176
+ return splits[0].get("stat")
177
+
178
+ return None