sharpapi 0.2.5__py3-none-any.whl → 0.3.2__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.
sharpapi/__init__.py CHANGED
@@ -38,6 +38,7 @@ from .models import (
38
38
  ArbitrageOpportunity,
39
39
  ClosingOddsLine,
40
40
  ClosingSnapshot,
41
+ EntityRef,
41
42
  Event,
42
43
  EVOpportunity,
43
44
  GameState,
@@ -53,11 +54,14 @@ from .models import (
53
54
  RateLimitInfo,
54
55
  ResponseMeta,
55
56
  Sport,
57
+ SportRef,
56
58
  Sportsbook,
59
+ Team,
60
+ TeamRef,
57
61
  )
58
62
  from .streaming import EventStream
59
63
 
60
- __version__ = "0.2.5"
64
+ __version__ = "0.3.1"
61
65
 
62
66
  __all__ = [
63
67
  # Clients
@@ -71,6 +75,7 @@ __all__ = [
71
75
  "ArbitrageOpportunity",
72
76
  "ClosingOddsLine",
73
77
  "ClosingSnapshot",
78
+ "EntityRef",
74
79
  "EVOpportunity",
75
80
  "Event",
76
81
  "GameState",
@@ -86,7 +91,10 @@ __all__ = [
86
91
  "RateLimitInfo",
87
92
  "ResponseMeta",
88
93
  "Sport",
94
+ "SportRef",
89
95
  "Sportsbook",
96
+ "Team",
97
+ "TeamRef",
90
98
  # Streaming
91
99
  "EventStream",
92
100
  # Exceptions
sharpapi/async_client.py CHANGED
@@ -29,6 +29,7 @@ from .models import (
29
29
  ClosingSnapshot,
30
30
  Event,
31
31
  EVOpportunity,
32
+ GameState,
32
33
  League,
33
34
  LowHoldOpportunity,
34
35
  Market,
@@ -103,6 +104,7 @@ class AsyncSharpAPI:
103
104
  self.arbitrage = _AsyncArbitrageResource(self)
104
105
  self.middles = _AsyncMiddlesResource(self)
105
106
  self.low_hold = _AsyncLowHoldResource(self)
107
+ self.gamestate = _AsyncGameStateResource(self)
106
108
  self.sports = _AsyncSportsResource(self)
107
109
  self.leagues = _AsyncLeaguesResource(self)
108
110
  self.sportsbooks = _AsyncSportsbooksResource(self)
@@ -426,6 +428,41 @@ class _AsyncLowHoldResource:
426
428
  return parse_response(data, LowHoldOpportunity)
427
429
 
428
430
 
431
+ class _AsyncGameStateResource:
432
+ """Async access to live game state — scores, period, clock —
433
+ merged across sportsbooks.
434
+
435
+ Requires the Game State add-on ($79/mo) or Enterprise tier.
436
+ """
437
+
438
+ def __init__(self, client: AsyncSharpAPI):
439
+ self._client = client
440
+
441
+ async def get(self, sport: str | None = None) -> dict[str, dict[str, GameState]]:
442
+ """Fetch the current game state.
443
+
444
+ Args:
445
+ sport: Limit to a single sport (e.g. ``"basketball"``).
446
+ Omit to fetch every sport at once.
447
+
448
+ Returns:
449
+ Nested mapping ``{sport: {event_id: GameState}}``.
450
+ """
451
+ path = f"/gamestate/{sport}" if sport else "/gamestate"
452
+ data = await self._client._get(path)
453
+ raw = data.get("data", {}) or {}
454
+ result: dict[str, dict[str, GameState]] = {}
455
+ for sport_key, events in raw.items():
456
+ if not isinstance(events, dict):
457
+ continue
458
+ result[sport_key] = {
459
+ eid: GameState.model_validate(state)
460
+ for eid, state in events.items()
461
+ if isinstance(state, dict)
462
+ }
463
+ return result
464
+
465
+
429
466
  class _AsyncSportsResource:
430
467
  def __init__(self, client: AsyncSharpAPI):
431
468
  self._client = client
sharpapi/client.py CHANGED
@@ -29,6 +29,7 @@ from .models import (
29
29
  ClosingSnapshot,
30
30
  Event,
31
31
  EVOpportunity,
32
+ GameState,
32
33
  League,
33
34
  LowHoldOpportunity,
34
35
  Market,
@@ -111,6 +112,7 @@ class SharpAPI:
111
112
  self.arbitrage = _ArbitrageResource(self)
112
113
  self.middles = _MiddlesResource(self)
113
114
  self.low_hold = _LowHoldResource(self)
115
+ self.gamestate = _GameStateResource(self)
114
116
  self.sports = _SportsResource(self)
115
117
  self.leagues = _LeaguesResource(self)
116
118
  self.sportsbooks = _SportsbooksResource(self)
@@ -542,6 +544,44 @@ class _LowHoldResource:
542
544
  return _parse_response(data, LowHoldOpportunity)
543
545
 
544
546
 
547
+ class _GameStateResource:
548
+ """Live game state — scores, period, clock — merged across sportsbooks.
549
+
550
+ Requires the Game State add-on ($79/mo) or Enterprise tier.
551
+ Pair with EV / arb / low-hold rows: those endpoints no longer carry
552
+ ``game_state`` themselves — look up the row's ``event_id`` here.
553
+ """
554
+
555
+ def __init__(self, client: SharpAPI):
556
+ self._client = client
557
+
558
+ def get(self, sport: str | None = None) -> dict[str, dict[str, GameState]]:
559
+ """Fetch the current game state.
560
+
561
+ Args:
562
+ sport: Limit to a single sport (e.g. ``"basketball"``,
563
+ ``"football"``). Omit to fetch every sport at once.
564
+
565
+ Returns:
566
+ Nested mapping ``{sport: {event_id: GameState}}``. Look up an
567
+ opportunity's state with
568
+ ``result.get(opp.sport, {}).get(opp.event_id)``.
569
+ """
570
+ path = f"/gamestate/{sport}" if sport else "/gamestate"
571
+ data = self._client._get(path)
572
+ raw = data.get("data", {}) or {}
573
+ result: dict[str, dict[str, GameState]] = {}
574
+ for sport_key, events in raw.items():
575
+ if not isinstance(events, dict):
576
+ continue
577
+ result[sport_key] = {
578
+ eid: GameState.model_validate(state)
579
+ for eid, state in events.items()
580
+ if isinstance(state, dict)
581
+ }
582
+ return result
583
+
584
+
545
585
  class _SportsResource:
546
586
  def __init__(self, client: SharpAPI):
547
587
  self._client = client
@@ -781,6 +821,15 @@ class _StreamResource:
781
821
  "market": market,
782
822
  })
783
823
 
824
+ def gamestate(self) -> EventStream:
825
+ """Stream live game state updates (scores, period, clock).
826
+
827
+ Emits ``gamestate:snapshot`` (initial dump on connect) and
828
+ ``gamestate:update`` / ``gamestate:removed`` events. Requires the
829
+ Game State add-on or Enterprise tier.
830
+ """
831
+ return self._build_stream("/stream/gamestate")
832
+
784
833
 
785
834
  # =============================================================================
786
835
  # Helpers
sharpapi/exceptions.py CHANGED
@@ -1,8 +1,7 @@
1
1
  """SharpAPI exceptions and canonical error-code registry.
2
2
 
3
- The error codes here mirror ``pkg/errcodes/errcodes.go`` in sharp-api-go, which
4
- is the single source of truth for every code the API emits. Keep this file in
5
- sync when new codes are added upstream.
3
+ The codes here mirror the canonical set the SharpAPI server emits.
4
+ Keep this file in sync when new codes are added upstream.
6
5
  """
7
6
 
8
7
  from __future__ import annotations
@@ -65,9 +64,10 @@ class StreamError(SharpAPIError):
65
64
  # =============================================================================
66
65
  # Canonical error-code registry
67
66
  #
68
- # Mirrors sharp-api-go/pkg/errcodes/errcodes.go. When upstream adds a new code,
69
- # add it here too and update the matching description. Each code maps to the
70
- # Python exception class that ``handle_errors`` (in ``_base.py``) raises for it.
67
+ # Mirrors the canonical SharpAPI server error-code set. When upstream adds
68
+ # a new code, add it here too and update the matching description. Each
69
+ # code maps to the Python exception class that ``handle_errors`` (in
70
+ # ``_base.py``) raises for it.
71
71
  # =============================================================================
72
72
 
73
73
  # HTTP error codes — emitted via REST handlers (httputil.WriteJSONError).
@@ -82,6 +82,8 @@ INVALID_TOKEN = "invalid_token"
82
82
  METHOD_NOT_ALLOWED = "method_not_allowed"
83
83
  MISSING_API_KEY = "missing_api_key"
84
84
  NOT_FOUND = "not_found"
85
+ NOT_READY = "not_ready"
86
+ OFFSET_TOO_LARGE = "offset_too_large"
85
87
  RATE_LIMITED = "rate_limited"
86
88
  SERVICE_UNAVAILABLE = "service_unavailable"
87
89
  TIER_RESTRICTED = "tier_restricted"
@@ -113,6 +115,11 @@ ERROR_CODE_DESCRIPTIONS: dict[str, str] = {
113
115
  METHOD_NOT_ALLOWED: "HTTP method not allowed on this endpoint.",
114
116
  MISSING_API_KEY: "No API key provided.",
115
117
  NOT_FOUND: "Resource not found.",
118
+ NOT_READY: "A required backing store is not yet ready to serve this request; retry shortly.",
119
+ OFFSET_TOO_LARGE: (
120
+ "offset exceeds the per-endpoint maximum; "
121
+ "use cursor-based pagination or advance `since`."
122
+ ),
116
123
  RATE_LIMITED: "Rate limit exceeded; see Retry-After header.",
117
124
  SERVICE_UNAVAILABLE: "Service is temporarily unavailable.",
118
125
  TIER_RESTRICTED: "Current subscription tier does not include this feature.",
@@ -148,6 +155,7 @@ ERROR_CODE_TO_EXCEPTION: dict[str, type[SharpAPIError]] = {
148
155
  TOO_MANY_STREAMS: RateLimitedError,
149
156
  # Validation
150
157
  VALIDATION_ERROR: ValidationError,
158
+ OFFSET_TOO_LARGE: ValidationError,
151
159
  # Streaming frames
152
160
  WS_ALREADY_AUTHENTICATED: StreamError,
153
161
  WS_INVALID_MESSAGE: StreamError,
@@ -160,15 +168,16 @@ ERROR_CODE_TO_EXCEPTION: dict[str, type[SharpAPIError]] = {
160
168
  INTERNAL_ERROR: SharpAPIError,
161
169
  METHOD_NOT_ALLOWED: SharpAPIError,
162
170
  NOT_FOUND: SharpAPIError,
171
+ NOT_READY: SharpAPIError,
163
172
  SERVICE_UNAVAILABLE: SharpAPIError,
164
173
  UNKNOWN_ENDPOINT: SharpAPIError,
165
174
  UPSTREAM_ERROR: SharpAPIError,
166
175
  }
167
176
 
168
- # Deprecated aliases. ``bad_request`` and ``invalid_request`` were both collapsed
169
- # into ``validation_error`` in sharp-api-go. Kept here so that older API
170
- # responses (or user code still checking these strings) resolve correctly.
171
- # TODO: remove after 2026-10.
177
+ # Deprecated aliases. ``bad_request`` and ``invalid_request`` were both
178
+ # collapsed into ``validation_error`` server-side. Kept here so that older
179
+ # API responses (or user code still checking these strings) resolve
180
+ # correctly. Will be removed after 2026-10.
172
181
  DEPRECATED_CODE_ALIASES: dict[str, str] = {
173
182
  "bad_request": VALIDATION_ERROR,
174
183
  "invalid_request": VALIDATION_ERROR,
sharpapi/models.py CHANGED
@@ -22,6 +22,67 @@ class OddsValue(BaseModel):
22
22
  probability: float
23
23
 
24
24
 
25
+ # =============================================================================
26
+ # Nested reference objects
27
+ # =============================================================================
28
+ #
29
+ # These structured ref objects ship alongside the legacy flat fields on every
30
+ # odds row, opportunity row, and reference-list row. All fields are optional
31
+ # and additive — clients on older API versions simply receive ``None``.
32
+ #
33
+ # Wire format uses snake_case (``sport_ref``, ``league_ref``, ``market_ref``,
34
+ # ``sportsbook_ref``) which Python attribute names match directly.
35
+
36
+
37
+ class TeamRef(BaseModel):
38
+ """Structured team reference attached to ``home`` / ``away``.
39
+
40
+ ``abbreviation`` is only present for ~1500 team-sport entities; absent
41
+ for individual-sport competitors (tennis players, MMA fighters, etc).
42
+
43
+ Optional metadata fields (``logo``, ``city``, ``mascot``, ``conference``,
44
+ ``division``) are populated for the majority of major-league teams
45
+ (~93% coverage on ``logo``, similar on the rest). Unmapped rows simply
46
+ leave the field absent rather than emitting null.
47
+ """
48
+
49
+ id: str | None = None
50
+ numerical_id: int | None = None
51
+ name: str | None = None
52
+ abbreviation: str | None = None
53
+ logo: str | None = None
54
+ city: str | None = None
55
+ mascot: str | None = None
56
+ conference: str | None = None
57
+ division: str | None = None
58
+
59
+ model_config = {"extra": "allow"}
60
+
61
+
62
+ class SportRef(BaseModel):
63
+ """Structured sport reference attached to ``sport_ref``."""
64
+
65
+ id: str | None = None
66
+ name: str | None = None
67
+ numerical_id: int | None = None
68
+
69
+ model_config = {"extra": "allow"}
70
+
71
+
72
+ class EntityRef(BaseModel):
73
+ """Structured reference for league / market / sportsbook objects.
74
+
75
+ Used by ``league_ref``, ``market_ref``, and ``sportsbook_ref`` on
76
+ every odds, opportunity, and reference row.
77
+ """
78
+
79
+ id: str | None = None
80
+ label: str | None = None
81
+ numerical_id: int | None = None
82
+
83
+ model_config = {"extra": "allow"}
84
+
85
+
25
86
  class Pagination(BaseModel):
26
87
  limit: int
27
88
  offset: int
@@ -60,9 +121,9 @@ class APIResponse(BaseModel, Generic[T]):
60
121
  Requires ``pip install sharpapi[pandas]``.
61
122
 
62
123
  Args:
63
- flatten: If True (default), flatten nested objects like
64
- ``game_state.period`` into ``game_state_period`` columns.
65
- Nested lists (like ``legs``) remain as-is.
124
+ flatten: If True (default), flatten nested objects into
125
+ underscore-joined columns. Nested lists (like ``legs``)
126
+ remain as-is.
66
127
 
67
128
  Returns:
68
129
  pandas.DataFrame with one row per item in ``data``.
@@ -109,12 +170,29 @@ def _flatten_dict(d: dict, parent_key: str = "", sep: str = "_") -> dict:
109
170
 
110
171
 
111
172
  class GameState(BaseModel):
112
- """Live game state."""
173
+ """Live game state for a single event, merged across sportsbooks.
113
174
 
114
- period: str | None = None
115
- clock: str | None = None
116
- score_home: int | None = None
117
- score_away: int | None = None
175
+ Returned by ``/api/v1/gamestate`` and the ``gamestate`` stream channel.
176
+ Scores are consensus-merged with period-guarded outlier rejection;
177
+ period/clock are picked from the most-advanced book. Not present on
178
+ EV / arb / low-hold opportunity rows — correlate by ``event_id``.
179
+
180
+ ``extra="allow"`` lets adapter-specific fields pass through unchanged.
181
+ """
182
+
183
+ home_score: int | None = None
184
+ away_score: int | None = None
185
+ game_period: str | None = None
186
+ game_clock: str | None = None
187
+ home_team: str | None = None
188
+ away_team: str | None = None
189
+ sport: str | None = None
190
+ primary_book: str | None = None
191
+ book_count: int | None = None
192
+ stale: bool = False
193
+ aggregator_stale: bool = False
194
+
195
+ model_config = {"extra": "allow"}
118
196
 
119
197
 
120
198
  # =============================================================================
@@ -146,10 +224,13 @@ class OddsLine(BaseModel):
146
224
  deep_link: str | None = None
147
225
  player_name: str | None = None
148
226
  stat_category: str | None = None
149
- home_score: int | None = None
150
- away_score: int | None = None
151
- game_period: str | None = None
152
- game_clock: str | None = None
227
+ # Optional structured refs (additive, non-breaking).
228
+ home: TeamRef | None = None
229
+ away: TeamRef | None = None
230
+ sport_ref: SportRef | None = None
231
+ league_ref: EntityRef | None = None
232
+ market_ref: EntityRef | None = None
233
+ sportsbook_ref: EntityRef | None = None
153
234
 
154
235
 
155
236
  # =============================================================================
@@ -205,6 +286,13 @@ class EVOpportunity(BaseModel):
205
286
  detected_at: str | None = None
206
287
  external_event_id: str | None = None
207
288
  selection_id: str | None = None
289
+ # Optional structured refs (additive, non-breaking).
290
+ home: TeamRef | None = None
291
+ away: TeamRef | None = None
292
+ sport_ref: SportRef | None = None
293
+ league_ref: EntityRef | None = None
294
+ market_ref: EntityRef | None = None
295
+ sportsbook_ref: EntityRef | None = None
208
296
 
209
297
  model_config = {"populate_by_name": True}
210
298
 
@@ -227,6 +315,8 @@ class ArbitrageLeg(BaseModel):
227
315
  external_event_id: str | None = None
228
316
  selection_id: str | None = None
229
317
  market_id: str | None = None
318
+ # Optional structured book ref on each leg.
319
+ sportsbook_ref: EntityRef | None = None
230
320
 
231
321
 
232
322
  class ArbitrageOpportunity(BaseModel):
@@ -248,7 +338,6 @@ class ArbitrageOpportunity(BaseModel):
248
338
  possibly_stale: bool = False
249
339
  oldest_odds_age_seconds: float | None = None
250
340
  warnings: list[str] = Field(default_factory=list)
251
- game_state: GameState | None = None
252
341
  ev_available: bool | None = None
253
342
  ev_percentage: float | None = None
254
343
  is_player_prop: bool = False
@@ -256,6 +345,12 @@ class ArbitrageOpportunity(BaseModel):
256
345
  stat_category: str | None = None
257
346
  legs: list[ArbitrageLeg]
258
347
  detected_at: str | None = None
348
+ # Optional structured refs (additive, non-breaking).
349
+ home: TeamRef | None = None
350
+ away: TeamRef | None = None
351
+ sport_ref: SportRef | None = None
352
+ league_ref: EntityRef | None = None
353
+ market_ref: EntityRef | None = None
259
354
 
260
355
 
261
356
  # =============================================================================
@@ -304,7 +399,6 @@ class MiddleOpportunity(BaseModel):
304
399
  quality_score: float | None = None
305
400
  market_overround: float | None = None
306
401
  is_live: bool = False
307
- game_state: GameState | None = None
308
402
  is_player_prop: bool = False
309
403
  player_name: str | None = None
310
404
  stat_category: str | None = None
@@ -315,6 +409,12 @@ class MiddleOpportunity(BaseModel):
315
409
  gap_size: float | None = Field(None, alias="gapSize")
316
410
  potential_profit: float | None = Field(None, alias="potentialProfit")
317
411
  legs: list[ArbitrageLeg] | None = None
412
+ # Optional structured refs (additive, non-breaking).
413
+ home: TeamRef | None = None
414
+ away: TeamRef | None = None
415
+ sport_ref: SportRef | None = None
416
+ league_ref: EntityRef | None = None
417
+ market_ref: EntityRef | None = None
318
418
 
319
419
  model_config = {"populate_by_name": True}
320
420
 
@@ -352,7 +452,6 @@ class LowHoldOpportunity(BaseModel):
352
452
  side2: LowHoldSide | None = None
353
453
  side3: LowHoldSide | None = None
354
454
  is_live: bool = False
355
- game_state: GameState | None = None
356
455
  is_alternate_line: bool = False
357
456
  all_books: list[str] | None = None
358
457
  confidence: float | None = None
@@ -362,6 +461,12 @@ class LowHoldOpportunity(BaseModel):
362
461
  player_name: str | None = None
363
462
  stat_category: str | None = None
364
463
  detected_at: str | None = None
464
+ # Optional structured refs (additive, non-breaking).
465
+ home: TeamRef | None = None
466
+ away: TeamRef | None = None
467
+ sport_ref: SportRef | None = None
468
+ league_ref: EntityRef | None = None
469
+ market_ref: EntityRef | None = None
365
470
 
366
471
 
367
472
  # =============================================================================
@@ -375,6 +480,8 @@ class Sport(BaseModel):
375
480
  slug: str
376
481
  active: bool
377
482
  event_count: int | None = None
483
+ # Optional integer numerical ID, additive.
484
+ numerical_id: int | None = None
378
485
 
379
486
 
380
487
  class League(BaseModel):
@@ -384,6 +491,8 @@ class League(BaseModel):
384
491
  sport_id: str | None = None
385
492
  country: str | None = None
386
493
  active: bool
494
+ # Optional integer numerical ID, additive.
495
+ numerical_id: int | None = None
387
496
 
388
497
 
389
498
  class Sportsbook(BaseModel):
@@ -393,6 +502,25 @@ class Sportsbook(BaseModel):
393
502
  active: bool
394
503
  regions: list[str] | None = None
395
504
  features: list[str] | None = None
505
+ # Optional integer numerical ID, additive.
506
+ numerical_id: int | None = None
507
+
508
+
509
+ class Team(BaseModel):
510
+ """A team / competitor returned by the ``/teams`` reference endpoint.
511
+
512
+ ``abbreviation`` is only present for ~1500 team-sport entities and is
513
+ absent for individual-sport competitors.
514
+ """
515
+
516
+ id: str
517
+ name: str | None = None
518
+ sport: str | None = None
519
+ league: str | None = None
520
+ abbreviation: str | None = None
521
+ numerical_id: int | None = None
522
+
523
+ model_config = {"extra": "allow"}
396
524
 
397
525
 
398
526
  class Event(BaseModel):
@@ -404,6 +532,11 @@ class Event(BaseModel):
404
532
  start_time: str | None = None
405
533
  is_live: bool = False
406
534
  status: str | None = None
535
+ # Optional structured refs (additive, non-breaking).
536
+ home: TeamRef | None = None
537
+ away: TeamRef | None = None
538
+ sport_ref: SportRef | None = None
539
+ league_ref: EntityRef | None = None
407
540
 
408
541
 
409
542
  class Market(BaseModel):
@@ -414,6 +547,8 @@ class Market(BaseModel):
414
547
  selection_count: int | None = None
415
548
  book_count: int | None = None
416
549
  books: list[str] | None = None
550
+ # Optional integer numerical ID, additive.
551
+ numerical_id: int | None = None
417
552
 
418
553
 
419
554
  # =============================================================================
@@ -433,6 +568,9 @@ class ClosingOddsLine(BaseModel):
433
568
  line: float | None = None
434
569
  player_name: str | None = None
435
570
  stat_category: str | None = None
571
+ # Optional structured refs (additive, non-breaking).
572
+ market_ref: EntityRef | None = None
573
+ sportsbook_ref: EntityRef | None = None
436
574
 
437
575
 
438
576
  class ClosingSnapshot(BaseModel):
@@ -446,6 +584,11 @@ class ClosingSnapshot(BaseModel):
446
584
  event_start_time: str | None = None
447
585
  captured_at: str | None = None
448
586
  books: dict[str, list[ClosingOddsLine]] = Field(default_factory=dict)
587
+ # Optional structured refs (additive, non-breaking).
588
+ home: TeamRef | None = None
589
+ away: TeamRef | None = None
590
+ sport_ref: SportRef | None = None
591
+ league_ref: EntityRef | None = None
449
592
 
450
593
 
451
594
  # =============================================================================
@@ -1,13 +1,14 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sharpapi
3
- Version: 0.2.5
3
+ Version: 0.3.2
4
4
  Summary: Official Python SDK for the SharpAPI real-time sports betting odds API
5
5
  Project-URL: Homepage, https://sharpapi.io
6
6
  Project-URL: Documentation, https://docs.sharpapi.io/sdks/python
7
- Project-URL: Repository, https://github.com/Sharp-API/sharpapi-python
8
- Project-URL: Changelog, https://github.com/Sharp-API/sharpapi-python/releases
9
- Author-email: SharpAPI <support@sharpapi.io>
7
+ Project-URL: Repository, https://github.com/Sharp-API/SharpAPI-Python
8
+ Project-URL: Changelog, https://github.com/Sharp-API/SharpAPI-Python/releases
9
+ Author-email: SharpAPI <hello@sharpapi.io>
10
10
  License-Expression: MIT
11
+ License-File: LICENSE
11
12
  Keywords: api,arbitrage,ev,odds,pinnacle,real-time,sports-betting
12
13
  Classifier: Development Status :: 4 - Beta
13
14
  Classifier: Intended Audience :: Developers
@@ -0,0 +1,13 @@
1
+ sharpapi/__init__.py,sha256=7m3CaUCg8wxNBihnmEsdflKCuTryceJnn-eW8zund3Y,2372
2
+ sharpapi/_base.py,sha256=D47zn_qwhD3UlE0Wez7rvbEq2r21ZAnSmmoeAJ4dURA,5841
3
+ sharpapi/_utils.py,sha256=nQU1gNkzepAIr93HDYX455aRO2yhc6BeBbaWDnpI5lw,1143
4
+ sharpapi/async_client.py,sha256=s_lkwvOctMSEE3WkNGXiZk1ulnrkVm5LVsrkOiqsCkw,19757
5
+ sharpapi/client.py,sha256=823nvQwsQ1k9vzQz5_zwXzie6FvrfAzaiqBaOcN6pss,27833
6
+ sharpapi/exceptions.py,sha256=AqZmr5ceXKyEVKdVA8ua-D0klH6zrXEMgs9Rxn7O2eE,7095
7
+ sharpapi/models.py,sha256=TIRbb7uaW9yTAk6kKZuCSkCILqQaoYyA289N_3ettrQ,19325
8
+ sharpapi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ sharpapi/streaming.py,sha256=sSdVE9HzuiDYnYH_Lmr4NHq0CKvwbUIELJvbSdqaTCw,8940
10
+ sharpapi-0.3.2.dist-info/METADATA,sha256=cFrChp78mFzbdLl3DpxzEIP_-wexOi-OCIZ7kByGz7U,5735
11
+ sharpapi-0.3.2.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
12
+ sharpapi-0.3.2.dist-info/licenses/LICENSE,sha256=EfZuzcYtp0eJC9ky4Nei3os5r0cFBYQmc-TpamV5OPw,1069
13
+ sharpapi-0.3.2.dist-info/RECORD,,
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 SharpAPI LLC
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.
@@ -1,12 +0,0 @@
1
- sharpapi/__init__.py,sha256=zAGsy2BLJmqNZ76cxD2sk9WD1U1bvTM83MkkRHU-LWo,2260
2
- sharpapi/_base.py,sha256=D47zn_qwhD3UlE0Wez7rvbEq2r21ZAnSmmoeAJ4dURA,5841
3
- sharpapi/_utils.py,sha256=nQU1gNkzepAIr93HDYX455aRO2yhc6BeBbaWDnpI5lw,1143
4
- sharpapi/async_client.py,sha256=xi5ueJGe09jSrsQ2Bb203-gfYVJGSoWX4l7-m2sySuY,18514
5
- sharpapi/client.py,sha256=vjsWjE36s-TisG0xAb9eors2lqq-9sQLoZKno3xrMHc,26006
6
- sharpapi/exceptions.py,sha256=0wRzrDEFhqP2_lWAbUJ5IcQaa7pi-QKB6TgNYuoYnVU,6790
7
- sharpapi/models.py,sha256=CW8p2VDyZo60bFaJoY5OCYnvCg5OqRYaA0xLLf0pR88,14240
8
- sharpapi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- sharpapi/streaming.py,sha256=sSdVE9HzuiDYnYH_Lmr4NHq0CKvwbUIELJvbSdqaTCw,8940
10
- sharpapi-0.2.5.dist-info/METADATA,sha256=Wdu3-Ka4F_GmE985GOf6kufl303PwHfKPAsm-OBjVvY,5715
11
- sharpapi-0.2.5.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
12
- sharpapi-0.2.5.dist-info/RECORD,,