theoddsapi-client 1.0.1__py3-none-any.whl

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.
theoddsapi/__init__.py ADDED
@@ -0,0 +1,12 @@
1
+ """theoddsapi: official Python client for TheOddsAPI (theoddsapi.com).
2
+
3
+ Zero dependencies (standard library only). One class, one method per endpoint.
4
+
5
+ from theoddsapi import TheOddsAPI
6
+ client = TheOddsAPI("YOUR_API_KEY")
7
+ odds = client.odds("baseball_mlb", oddsFormat="decimal")
8
+ """
9
+ from .client import TheOddsAPI, TheOddsAPIError
10
+
11
+ __all__ = ["TheOddsAPI", "TheOddsAPIError"]
12
+ __version__ = "1.0.1"
theoddsapi/client.py ADDED
@@ -0,0 +1,118 @@
1
+ """HTTP client for TheOddsAPI. Standard library only, retries on 5xx."""
2
+ import json
3
+ import time
4
+ import urllib.error
5
+ import urllib.parse
6
+ import urllib.request
7
+
8
+ BASE_URL = "https://api.theoddsapi.com"
9
+ RETRY_STATUSES = {502, 503, 504}
10
+
11
+
12
+ class TheOddsAPIError(Exception):
13
+ """Raised for any non-2xx API response. Carries .status and .detail."""
14
+
15
+ def __init__(self, status, detail):
16
+ self.status = status
17
+ self.detail = detail
18
+ super().__init__(f"HTTP {status}: {detail}")
19
+
20
+
21
+ class TheOddsAPI:
22
+ """Thin client for TheOddsAPI. Docs: https://theoddsapi.com/docs/"""
23
+
24
+ def __init__(self, api_key, base_url=BASE_URL, timeout=15, max_retries=3):
25
+ self.api_key = api_key
26
+ self.base_url = base_url.rstrip("/")
27
+ self.timeout = timeout
28
+ self.max_retries = max_retries
29
+
30
+ # ------------------------------------------------------------- core ----
31
+ def _get(self, path, params=None):
32
+ query = urllib.parse.urlencode(
33
+ {k: v for k, v in (params or {}).items() if v is not None})
34
+ url = f"{self.base_url}{path}" + (f"?{query}" if query else "")
35
+ req = urllib.request.Request(url, headers={
36
+ "x-api-key": self.api_key,
37
+ "User-Agent": "theoddsapi-python/1.0.1",
38
+ })
39
+ delay = 1.0
40
+ for attempt in range(self.max_retries + 1):
41
+ try:
42
+ with urllib.request.urlopen(req, timeout=self.timeout) as resp:
43
+ return json.loads(resp.read().decode("utf-8"))
44
+ except urllib.error.HTTPError as e:
45
+ if e.code in RETRY_STATUSES and attempt < self.max_retries:
46
+ time.sleep(delay)
47
+ delay = min(delay * 2, 30)
48
+ continue
49
+ try:
50
+ detail = json.loads(e.read().decode("utf-8")).get("detail", e.reason)
51
+ except Exception:
52
+ detail = e.reason
53
+ raise TheOddsAPIError(e.code, detail) from None
54
+ except urllib.error.URLError as e:
55
+ if attempt < self.max_retries:
56
+ time.sleep(delay)
57
+ delay = min(delay * 2, 30)
58
+ continue
59
+ raise TheOddsAPIError(0, f"connection failed: {e.reason}") from None
60
+
61
+ # -------------------------------------------------------- core data ----
62
+ def sports(self):
63
+ """List the sports available on your plan."""
64
+ return self._get("/sports/")
65
+
66
+ def odds(self, sport_key, **params):
67
+ """Current multi-book odds for a sport. Params: markets, regions,
68
+ bookmakers, event_id, commenceTimeFrom, commenceTimeTo, oddsFormat."""
69
+ return self._get("/odds/", {"sport_key": sport_key, **params})
70
+
71
+ def events(self, sport_key, **params):
72
+ """Upcoming events for a sport."""
73
+ return self._get("/events/", {"sport_key": sport_key, **params})
74
+
75
+ def best_lines(self, sport_key, **params):
76
+ """Best available price per outcome across all tracked books."""
77
+ return self._get("/best-lines/", {"sport_key": sport_key, **params})
78
+
79
+ # ---------------------------------------------- business endpoints ----
80
+ def props(self, sport_key, **params):
81
+ """Player props (Business plan)."""
82
+ return self._get("/props/", {"sport_key": sport_key, **params})
83
+
84
+ def edges(self, sport_key, **params):
85
+ """Pinnacle-anchored cross-book edges (Business plan)."""
86
+ return self._get("/edges/", {"sport_key": sport_key, **params})
87
+
88
+ def fair_odds(self, sport_key, **params):
89
+ """Vig-removed fair odds from sharp-anchored consensus (Business)."""
90
+ return self._get("/intelligence/fair-odds", {"sport_key": sport_key, **params})
91
+
92
+ def consensus(self, sport_key, **params):
93
+ """Median/mean market center per outcome (Business)."""
94
+ return self._get("/intelligence/consensus", {"sport_key": sport_key, **params})
95
+
96
+ def arbitrage(self, sport_key, **params):
97
+ """Precomputed cross-book arbitrage opportunities (Business)."""
98
+ return self._get("/intelligence/arbitrage", {"sport_key": sport_key, **params})
99
+
100
+ def value_bets(self, sport_key, **params):
101
+ """Value bets vs vig-removed consensus (Business)."""
102
+ return self._get("/intelligence/value", {"sport_key": sport_key, **params})
103
+
104
+ def historical_odds(self, sport_key, **params):
105
+ """Historical odds snapshots (Business). Params: from/to (use
106
+ from_/to_ or pass via dict), event_id, bookmakers, market,
107
+ limit, offset, oddsFormat."""
108
+ clean = {k.rstrip("_"): v for k, v in params.items()}
109
+ return self._get("/historical/odds", {"sport_key": sport_key, **clean})
110
+
111
+ def historical_settlements(self, sport_key, **params):
112
+ """Graded edge settlements joined with final scores (Business)."""
113
+ return self._get("/historical/settlements", {"sport_key": sport_key, **params})
114
+
115
+ # ------------------------------------------------------------ account --
116
+ def me(self):
117
+ """Your key's tier and usage."""
118
+ return self._get("/me/")
@@ -0,0 +1,70 @@
1
+ Metadata-Version: 2.4
2
+ Name: theoddsapi-client
3
+ Version: 1.0.1
4
+ Summary: Official Python client for TheOddsAPI: real-time sports odds from 50+ sportsbooks across 26 sports, plus player props, Pinnacle-anchored edges, fair odds, and historical snapshots.
5
+ Project-URL: Homepage, https://theoddsapi.com
6
+ Project-URL: Documentation, https://theoddsapi.com/docs/
7
+ Project-URL: Changelog, https://theoddsapi.com/changelog
8
+ License: MIT
9
+ Keywords: api,arbitrage,betting,odds,props,sports,sportsbook
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Topic :: Software Development :: Libraries
15
+ Requires-Python: >=3.8
16
+ Description-Content-Type: text/markdown
17
+
18
+ # theoddsapi
19
+
20
+ Official Python client for [TheOddsAPI](https://theoddsapi.com): real-time sports odds from 50+ sportsbooks across 26 sports, normalized into one JSON shape, plus player props, Pinnacle-anchored edge detection, fair odds, and historical snapshots.
21
+
22
+ Zero dependencies. Python 3.8+.
23
+
24
+ ## Install
25
+
26
+ ```
27
+ pip install theoddsapi
28
+ ```
29
+
30
+ ## Quick start
31
+
32
+ ```python
33
+ from theoddsapi import TheOddsAPI
34
+
35
+ client = TheOddsAPI("YOUR_API_KEY")
36
+
37
+ for sport in client.sports()["data"]:
38
+ print(sport)
39
+
40
+ odds = client.odds("baseball_mlb", oddsFormat="decimal")
41
+ ```
42
+
43
+ Get a free key in minutes at [theoddsapi.com/start](https://theoddsapi.com/start). No credit card.
44
+
45
+ ## Endpoints
46
+
47
+ Every endpoint is one method. Core data: `sports()`, `odds()`, `events()`, `best_lines()`. Business plan: `props()`, `edges()`, `fair_odds()`, `consensus()`, `arbitrage()`, `value_bets()`, `historical_odds()`, `historical_settlements()`. Account: `me()`.
48
+
49
+ ```python
50
+ edges = client.edges("basketball_nba", min_edge=50)
51
+ history = client.historical_odds("baseball_mlb", bookmakers="pinnacle", limit=500)
52
+ ```
53
+
54
+ ## Errors
55
+
56
+ Non-2xx responses raise `TheOddsAPIError` with `.status` and `.detail`. Transient 5xx responses are retried with exponential backoff automatically.
57
+
58
+ ```python
59
+ from theoddsapi import TheOddsAPI, TheOddsAPIError
60
+
61
+ try:
62
+ client.props("baseball_mlb")
63
+ except TheOddsAPIError as e:
64
+ if e.status == 403:
65
+ print("Props require the Business plan:", e.detail)
66
+ ```
67
+
68
+ ## Links
69
+
70
+ Full reference: [theoddsapi.com/docs](https://theoddsapi.com/docs/) · Guides: [theoddsapi.com/guides](https://theoddsapi.com/guides/) · Free calculators: [theoddsapi.com/tools](https://theoddsapi.com/tools/)
@@ -0,0 +1,5 @@
1
+ theoddsapi/__init__.py,sha256=VpPSodf0JpJR4RDo4sYpp4BYKq8ZpBqg8cvT9VxsoJE,410
2
+ theoddsapi/client.py,sha256=FlFjVZWkwPBkkZIilZcLtuygWm6mKB5954YDA4d1PeU,5098
3
+ theoddsapi_client-1.0.1.dist-info/METADATA,sha256=eLxPnsNYqxtW4KvT1LcfpoEBrHPEXHmD4MIrGC-WbNc,2464
4
+ theoddsapi_client-1.0.1.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
5
+ theoddsapi_client-1.0.1.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.31.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any