polymarket-apis 0.3.1__py3-none-any.whl → 0.3.3__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.

Potentially problematic release.


This version of polymarket-apis might be problematic. Click here for more details.

@@ -7,7 +7,18 @@ from urllib.parse import urljoin
7
7
 
8
8
  import httpx
9
9
 
10
- from ..types.gamma_types import Event, EventList, GammaMarket
10
+ from ..types.common import EthAddress
11
+ from ..types.gamma_types import (
12
+ Comment,
13
+ Event,
14
+ GammaMarket,
15
+ SearchResult,
16
+ Series,
17
+ Sport,
18
+ Tag,
19
+ TagRelation,
20
+ Team,
21
+ )
11
22
 
12
23
 
13
24
  def generate_random_id(length=16):
@@ -24,6 +35,73 @@ class PolymarketGammaClient:
24
35
  def _build_url(self, endpoint: str) -> str:
25
36
  return urljoin(self.base_url, endpoint)
26
37
 
38
+ def search(
39
+ self,
40
+ query: str,
41
+ cache: Optional[bool] = None,
42
+ status: Optional[Literal["active", "resolved"]] = None,
43
+ limit_per_type: Optional[int] = None, # max is 50
44
+ page: Optional[int] = None,
45
+ tags: Optional[list[str]] = None,
46
+ keep_closed_markets: Optional[bool] = None,
47
+ sort: Optional[
48
+ Literal[
49
+ "volume",
50
+ "volume_24hr",
51
+ "liquidity",
52
+ "start_date",
53
+ "end_date",
54
+ "competitive",
55
+ ]
56
+ ] = None,
57
+ ascending: Optional[bool] = None,
58
+ search_tags: Optional[bool] = None,
59
+ search_profiles: Optional[bool] = None,
60
+ recurrence: Optional[
61
+ Literal["hourly", "daily", "weekly", "monthly", "annual"]
62
+ ] = None,
63
+ exclude_tag_ids: Optional[list[int]] = None,
64
+ optimized: Optional[bool] = None,
65
+ ) -> SearchResult:
66
+ params: dict[str, str | list[str] | int | bool] = {
67
+ "q": query,
68
+ }
69
+ if cache is not None:
70
+ params["cache"] = str(cache).lower()
71
+ if status:
72
+ params["events_status"] = status
73
+ if limit_per_type:
74
+ params["limit_per_type"] = limit_per_type
75
+ if page:
76
+ params["page"] = page
77
+ if tags:
78
+ params["events_tag"] = json.dumps([json.dumps(item) for item in tags])
79
+ if keep_closed_markets is not None:
80
+ params["keep_closed_markets"] = keep_closed_markets
81
+ if sort:
82
+ params["sort"] = sort
83
+ if ascending is not None:
84
+ params["ascending"] = str(ascending).lower()
85
+ if search_tags is not None:
86
+ params["search_tags"] = str(search_tags).lower()
87
+ if search_profiles is not None:
88
+ params["search_profiles"] = str(search_profiles).lower()
89
+ if recurrence:
90
+ params["recurrence"] = recurrence
91
+ if exclude_tag_ids:
92
+ params["exclude_tag_id"] = [str(i) for i in exclude_tag_ids]
93
+ if optimized is not None:
94
+ params["optimized"] = str(optimized).lower()
95
+ response = self.client.get(self._build_url("/public-search"), params=params)
96
+ response.raise_for_status()
97
+ return SearchResult(**response.json())
98
+
99
+ def get_market(self, market_id: str) -> GammaMarket:
100
+ """Get a GammaMarket by market_id."""
101
+ response = self.client.get(self._build_url(f"/markets/{market_id}"))
102
+ response.raise_for_status()
103
+ return GammaMarket(**response.json())
104
+
27
105
  def get_markets(
28
106
  self,
29
107
  limit: Optional[int] = None,
@@ -95,16 +173,39 @@ class PolymarketGammaClient:
95
173
  response.raise_for_status()
96
174
  return [GammaMarket(**market) for market in response.json()]
97
175
 
98
- def get_market(self, market_id: str) -> GammaMarket:
99
- """Get a GammaMarket by market_id."""
100
- response = self.client.get(self._build_url(f"/markets/{market_id}"))
176
+ def get_market_by_id(
177
+ self, market_id: str, include_tag: Optional[bool] = None
178
+ ) -> GammaMarket:
179
+ params = {}
180
+ if include_tag:
181
+ params["include_tag"] = include_tag
182
+ response = self.client.get(
183
+ self._build_url(f"/markets/{market_id}"), params=params
184
+ )
185
+ response.raise_for_status()
186
+ return GammaMarket(**response.json())
187
+
188
+ def get_market_tags(self, market_id: str) -> list[Tag]:
189
+ response = self.client.get(self._build_url(f"/markets/{market_id}/tags"))
190
+ response.raise_for_status()
191
+ return [Tag(**tag) for tag in response.json()]
192
+
193
+ def get_market_by_slug(
194
+ self, slug: str, include_tag: Optional[bool] = None
195
+ ) -> GammaMarket:
196
+ params = {}
197
+ if include_tag:
198
+ params["include_tag"] = include_tag
199
+ response = self.client.get(
200
+ self._build_url(f"/markets/slug/{slug}"), params=params
201
+ )
101
202
  response.raise_for_status()
102
203
  return GammaMarket(**response.json())
103
204
 
104
205
  def get_events(
105
206
  self,
106
- limit: Optional[int] = None,
107
- offset: Optional[int] = None,
207
+ limit: int = 500,
208
+ offset: int = 0,
108
209
  order: Optional[str] = None,
109
210
  ascending: bool = True,
110
211
  event_ids: Optional[Union[str, list[str]]] = None,
@@ -125,11 +226,10 @@ class PolymarketGammaClient:
125
226
  tag_slug: Optional[str] = None,
126
227
  related_tags: bool = False,
127
228
  ) -> list[Event]:
128
- params = {}
129
- if limit:
130
- params["limit"] = limit
131
- if offset:
132
- params["offset"] = offset
229
+ params: dict[str, int | str | list[str] | float] = {
230
+ "limit": limit,
231
+ "offset": offset,
232
+ }
133
233
  if order:
134
234
  params["order"] = order
135
235
  params["ascending"] = ascending
@@ -172,11 +272,6 @@ class PolymarketGammaClient:
172
272
  response.raise_for_status()
173
273
  return [Event(**event) for event in response.json()]
174
274
 
175
- def get_event(self, event_id: int) -> Event:
176
- response = self.client.get(self._build_url(f"/events/{event_id}"))
177
- response.raise_for_status()
178
- return Event(**response.json())
179
-
180
275
  def get_all_events(
181
276
  self,
182
277
  order: Optional[str] = None,
@@ -204,7 +299,6 @@ class PolymarketGammaClient:
204
299
 
205
300
  while True:
206
301
  part = self.get_events(
207
- limit=500,
208
302
  offset=offset,
209
303
  order=order,
210
304
  ascending=ascending,
@@ -235,43 +329,419 @@ class PolymarketGammaClient:
235
329
 
236
330
  return events
237
331
 
238
- def search_events(
332
+ def get_event_by_id(
239
333
  self,
240
- query: str,
241
- active: bool = True,
242
- status: Optional[Literal["active", "resolved"]] = "active",
243
- sort: Literal[
244
- "volume",
245
- "volume_24hr",
246
- "liquidity",
247
- "start_date",
248
- "end_date",
249
- "competitive",
250
- ] = "volume_24hr",
251
- page: int = 1,
252
- limit_per_type: int = 50, # max is 50
253
- presets: Optional[
254
- Literal["EventsHybrid", "EventsTitle"]
255
- | list[Literal["EventsHybrid", "EventsTitle"]]
334
+ event_id: int,
335
+ include_chat: Optional[bool] = None,
336
+ include_template: Optional[bool] = None,
337
+ ) -> Event:
338
+ params = {}
339
+ if include_chat:
340
+ params["include_chat"] = include_chat
341
+ if include_template:
342
+ params["include_template"] = include_template
343
+ response = self.client.get(
344
+ self._build_url(f"/events/{event_id}"), params=params
345
+ )
346
+ response.raise_for_status()
347
+ return Event(**response.json())
348
+
349
+ def get_event_by_slug(
350
+ self,
351
+ slug: str,
352
+ include_chat: Optional[bool] = None,
353
+ include_template: Optional[bool] = None,
354
+ ) -> Event:
355
+ params = {}
356
+ if include_chat:
357
+ params["include_chat"] = include_chat
358
+ if include_template:
359
+ params["include_template"] = include_template
360
+ response = self.client.get(
361
+ self._build_url(f"/events/slug/{slug}"), params=params
362
+ )
363
+ response.raise_for_status()
364
+ return Event(**response.json())
365
+
366
+ def get_event_tags(self, event_id: int) -> list[Tag]:
367
+ response = self.client.get(self._build_url(f"/events/{event_id}/tags"))
368
+ response.raise_for_status()
369
+ return [Tag(**tag) for tag in response.json()]
370
+
371
+ def get_teams(
372
+ self,
373
+ limit: int = 500,
374
+ offset: int = 0,
375
+ order: Optional[
376
+ Literal[
377
+ "id",
378
+ "name",
379
+ "league",
380
+ "record",
381
+ "logo",
382
+ "abbreviation",
383
+ "alias",
384
+ "createdAt",
385
+ "updatedAt",
386
+ ]
256
387
  ] = None,
257
- ) -> EventList:
258
- """Search for events by query. Should emulate the website search function."""
259
- params = {
260
- "q": query,
261
- "page": page,
262
- "limit_per_type": limit_per_type,
263
- "events_status": status,
264
- "active": active,
388
+ ascending: bool = True,
389
+ league: Optional[str] = None,
390
+ name: Optional[str] = None,
391
+ abbreviation: Optional[str] = None,
392
+ ) -> list[Team]:
393
+ params: dict[str, int | str] = {
394
+ "limit": limit,
395
+ "offset": offset,
265
396
  }
266
- if sort:
267
- params["sort"] = sort
268
- if sort == "end_date":
269
- params["ascending"] = "true"
270
- if presets:
271
- params["presets"] = presets
272
- response = self.client.get(self._build_url("/public-search"), params=params)
397
+ if order:
398
+ params["order"] = order
399
+ params["ascending"] = str(ascending).lower()
400
+ if league:
401
+ params["league"] = league.lower()
402
+ if name:
403
+ params["name"] = name
404
+ if abbreviation:
405
+ params["abbreviation"] = abbreviation.lower()
406
+ response = self.client.get(self._build_url("/teams"), params=params)
407
+ response.raise_for_status()
408
+ return [Team(**team) for team in response.json()]
409
+
410
+ def get_all_teams(
411
+ self,
412
+ order: Optional[
413
+ Literal[
414
+ "id",
415
+ "name",
416
+ "league",
417
+ "record",
418
+ "logo",
419
+ "abbreviation",
420
+ "alias",
421
+ "createdAt",
422
+ "updatedAt",
423
+ ]
424
+ ] = None,
425
+ ascending: bool = True,
426
+ league: Optional[str] = None,
427
+ name: Optional[str] = None,
428
+ abbreviation: Optional[str] = None,
429
+ ) -> list[Team]:
430
+ offset = 0
431
+ teams = []
432
+
433
+ while True:
434
+ part = self.get_teams(
435
+ offset=offset,
436
+ order=order,
437
+ ascending=ascending,
438
+ league=league,
439
+ name=name,
440
+ abbreviation=abbreviation,
441
+ )
442
+ teams.extend(part)
443
+
444
+ if len(part) < 500:
445
+ break
446
+
447
+ offset += 500
448
+
449
+ return teams
450
+
451
+ def get_sports_metadata(
452
+ self,
453
+ ) -> list[Sport]:
454
+ response = self.client.get(self._build_url("/sports"))
455
+ response.raise_for_status()
456
+ return [Sport(**sport) for sport in response.json()]
457
+
458
+ def get_tags(
459
+ self,
460
+ limit: int = 300,
461
+ offset: int = 0,
462
+ order: Optional[
463
+ Literal[
464
+ "id",
465
+ "label",
466
+ "slug",
467
+ "forceShow",
468
+ "forceHide",
469
+ "isCarousel",
470
+ "createdAt",
471
+ "updatedAt",
472
+ "createdBy",
473
+ "updatedBy",
474
+ ]
475
+ ] = None,
476
+ ascending: bool = True,
477
+ include_templates: Optional[bool] = None,
478
+ is_carousel: Optional[bool] = None,
479
+ ) -> list[Tag]:
480
+ params: dict[str, int | str] = {
481
+ "limit": limit,
482
+ "offset": offset,
483
+ }
484
+ if order:
485
+ params["order"] = order
486
+ params["ascending"] = str(ascending).lower()
487
+ if include_templates is not None:
488
+ params["include_templates"] = str(include_templates).lower()
489
+ if is_carousel is not None:
490
+ params["is_carousel"] = str(is_carousel).lower()
491
+ response = self.client.get(self._build_url("/tags"), params=params)
492
+ response.raise_for_status()
493
+ return [Tag(**tag) for tag in response.json()]
494
+
495
+ def get_all_tags(
496
+ self,
497
+ order: Optional[
498
+ Literal[
499
+ "id",
500
+ "label",
501
+ "slug",
502
+ "forceShow",
503
+ "forceHide",
504
+ "isCarousel",
505
+ "createdAt",
506
+ "updatedAt",
507
+ "createdBy",
508
+ "updatedBy",
509
+ ]
510
+ ] = None,
511
+ ascending: bool = True,
512
+ include_templates: Optional[bool] = None,
513
+ is_carousel: Optional[bool] = None,
514
+ ) -> list[Tag]:
515
+ offset = 0
516
+ tags = []
517
+
518
+ while True:
519
+ part = self.get_tags(
520
+ offset=offset,
521
+ order=order,
522
+ ascending=ascending,
523
+ include_templates=include_templates,
524
+ is_carousel=is_carousel,
525
+ )
526
+ tags.extend(part)
527
+
528
+ if len(part) < 300:
529
+ break
530
+
531
+ offset += 300
532
+
533
+ return tags
534
+
535
+ def get_tag(self, tag_id: str, include_template: Optional[bool] = None) -> Tag:
536
+ params = {}
537
+ if include_template is not None:
538
+ params = {"include_template": str(include_template).lower()}
539
+ response = self.client.get(self._build_url(f"/tags/{tag_id}"), params=params)
540
+ response.raise_for_status()
541
+ return Tag(**response.json())
542
+
543
+ def get_related_tag_ids_by_tag_id(
544
+ self,
545
+ tag_id: int,
546
+ omit_empty: Optional[bool] = None,
547
+ status: Optional[Literal["active", "closed", "all"]] = None,
548
+ ) -> list[TagRelation]:
549
+ params = {}
550
+ if omit_empty is not None:
551
+ params["omit_empty"] = str(omit_empty).lower()
552
+ if status:
553
+ params["status"] = status
554
+ response = self.client.get(
555
+ self._build_url(f"/tags/{tag_id}/related-tags"), params=params
556
+ )
557
+ response.raise_for_status()
558
+ return [TagRelation(**tag) for tag in response.json()]
559
+
560
+ def get_related_tag_ids_by_slug(
561
+ self,
562
+ slug: str,
563
+ omit_empty: Optional[bool] = None,
564
+ status: Optional[Literal["active", "closed", "all"]] = None,
565
+ ) -> list[TagRelation]:
566
+ params = {}
567
+ if omit_empty is not None:
568
+ params["omit_empty"] = str(omit_empty).lower()
569
+ if status:
570
+ params["status"] = status
571
+ response = self.client.get(
572
+ self._build_url(f"/tags/slug/{slug}/related-tags"), params=params
573
+ )
574
+ response.raise_for_status()
575
+ return [TagRelation(**tag) for tag in response.json()]
576
+
577
+ def get_related_tags_by_tag_id(
578
+ self,
579
+ tag_id: int,
580
+ omit_empty: Optional[bool] = None,
581
+ status: Optional[Literal["active", "closed", "all"]] = None,
582
+ ) -> list[Tag]:
583
+ params = {}
584
+ if omit_empty is not None:
585
+ params["omit_empty"] = str(omit_empty).lower()
586
+ if status:
587
+ params["status"] = status
588
+ response = self.client.get(
589
+ self._build_url(f"/tags/{tag_id}/related-tags/tags"), params=params
590
+ )
591
+ response.raise_for_status()
592
+ return [Tag(**tag) for tag in response.json()]
593
+
594
+ def get_related_tags_by_slug(
595
+ self,
596
+ slug: str,
597
+ omit_empty: Optional[bool] = None,
598
+ status: Optional[Literal["active", "closed", "all"]] = None,
599
+ ) -> list[Tag]:
600
+ params = {}
601
+ if omit_empty is not None:
602
+ params["omit_empty"] = str(omit_empty).lower()
603
+ if status:
604
+ params["status"] = status
605
+ response = self.client.get(
606
+ self._build_url(f"/tags/slug/{slug}/related-tags/tags"), params=params
607
+ )
608
+ response.raise_for_status()
609
+ return [Tag(**tag) for tag in response.json()]
610
+
611
+ def get_series(
612
+ self,
613
+ limit: int = 300,
614
+ offset: int = 0,
615
+ order: Optional[str] = None,
616
+ ascending: bool = True,
617
+ slug: Optional[str] = None,
618
+ closed: Optional[bool] = None,
619
+ include_chat: Optional[bool] = None,
620
+ recurrence: Optional[
621
+ Literal[
622
+ "hourly", "daily", "weekly", "monthly", "annual"
623
+ ] # results also contain "15m" but the server returns a 422 Unprocessable Content
624
+ ] = None,
625
+ ) -> list[Series]:
626
+ params: dict[str, str | int | list[int]] = {
627
+ "limit": limit,
628
+ "offset": offset,
629
+ }
630
+ if order:
631
+ params["order"] = order
632
+ params["ascending"] = str(ascending).lower()
633
+ if slug:
634
+ params["slug"] = slug
635
+ if closed is not None:
636
+ params["closed"] = str(closed).lower()
637
+ if include_chat is not None:
638
+ params["include_chat"] = str(include_chat).lower()
639
+ if recurrence is not None:
640
+ params["recurrence"] = str(recurrence).lower()
641
+
642
+ response = self.client.get(self._build_url("/series"), params=params)
643
+ response.raise_for_status()
644
+ return [Series(**series) for series in response.json()]
645
+
646
+ def get_all_series(
647
+ self,
648
+ order: Optional[str] = None,
649
+ ascending: bool = True,
650
+ slug: Optional[str] = None,
651
+ closed: Optional[bool] = None,
652
+ include_chat: Optional[bool] = None,
653
+ recurrence: Optional[
654
+ Literal["hourly", "daily", "weekly", "monthly", "annual"]
655
+ ] = None,
656
+ ) -> list[Series]:
657
+ offset = 0
658
+ series = []
659
+
660
+ while True:
661
+ part = self.get_series(
662
+ offset=offset,
663
+ order=order,
664
+ ascending=ascending,
665
+ slug=slug,
666
+ closed=closed,
667
+ include_chat=include_chat,
668
+ recurrence=recurrence,
669
+ )
670
+ series.extend(part)
671
+
672
+ if len(part) < 300:
673
+ break
674
+
675
+ offset += 300
676
+ return series
677
+
678
+ def get_series_by_id(self, series_id: str) -> Series:
679
+ response = self.client.get(self._build_url(f"/series/{series_id}"))
680
+ response.raise_for_status()
681
+ return Series(**response.json())
682
+
683
+ def get_comments(
684
+ self,
685
+ parent_entity_type: Literal["Event", "Series", "market"],
686
+ parent_entity_id: int,
687
+ limit=500,
688
+ offset=0,
689
+ order: Optional[str] = None,
690
+ ascending: bool = True,
691
+ get_positions: Optional[bool] = None,
692
+ holders_only: Optional[bool] = None,
693
+ ) -> list[Comment]:
694
+ """Warning, the server doesn't give back the right amount of comments you asked for."""
695
+ params: dict[str, str | int] = {
696
+ "parent_entity_type": parent_entity_type,
697
+ "parent_entity_id": parent_entity_id,
698
+ "limit": limit,
699
+ "offset": offset,
700
+ }
701
+ if order:
702
+ params["order"] = order
703
+ params["ascending"] = str(ascending).lower()
704
+ if get_positions is not None:
705
+ params["get_positions"] = str(get_positions).lower()
706
+ if holders_only is not None:
707
+ params["holders_only"] = str(holders_only).lower()
708
+ response = self.client.get(self._build_url("/comments"), params=params)
709
+ response.raise_for_status()
710
+ return [Comment(**comment) for comment in response.json()]
711
+
712
+ def get_comments_by_id(
713
+ self, comment_id: str, get_positions: Optional[bool] = None
714
+ ) -> list[Comment]:
715
+ """Returns all comments that belong to the comment's thread."""
716
+ params = {}
717
+ if get_positions is not None:
718
+ params["get_positions"] = str(get_positions).lower()
719
+ response = self.client.get(
720
+ self._build_url(f"/comments/{comment_id}"), params=params
721
+ )
722
+ response.raise_for_status()
723
+ return [Comment(**comment) for comment in response.json()]
724
+
725
+ def get_comments_by_user_address(
726
+ self,
727
+ user_address: EthAddress, # warning, this is the base address, not the proxy address
728
+ limit=500,
729
+ offset=0,
730
+ order: Optional[str] = None,
731
+ ascending: bool = True,
732
+ ) -> list[Comment]:
733
+ params: dict[str, str | int] = {
734
+ "limit": limit,
735
+ "offset": offset,
736
+ }
737
+ if order:
738
+ params["order"] = order
739
+ params["ascending"] = str(ascending).lower()
740
+ response = self.client.get(
741
+ self._build_url(f"/comments/user_address/{user_address}"), params=params
742
+ )
273
743
  response.raise_for_status()
274
- return EventList(**response.json())
744
+ return [Comment(**comment) for comment in response.json()]
275
745
 
276
746
  def grok_event_summary(self, event_slug: str):
277
747
  json_payload = {