zpdatafetch 2.3.1__tar.gz → 2.4.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.
Files changed (85) hide show
  1. {zpdatafetch-2.3.1/src/zpdatafetch.egg-info → zpdatafetch-2.4.0}/PKG-INFO +36 -6
  2. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/README.md +35 -5
  3. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/pyproject.toml +1 -1
  4. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zpdatafetch/cli.py +80 -1
  5. zpdatafetch-2.4.0/src/zpdatafetch/zpleague.py +1153 -0
  6. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zpdatafetch/zpleaguefetch.py +248 -47
  7. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0/src/zpdatafetch.egg-info}/PKG-INFO +36 -6
  8. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zrdatafetch/async_zr.py +46 -2
  9. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zrdatafetch/cli.py +2 -0
  10. zpdatafetch-2.3.1/src/zpdatafetch/zpleague.py +0 -496
  11. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/LICENSE +0 -0
  12. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/setup.cfg +0 -0
  13. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/shared/__init__.py +0 -0
  14. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/shared/cli.py +0 -0
  15. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/shared/config.py +0 -0
  16. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/shared/error_helpers.py +0 -0
  17. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/shared/exceptions.py +0 -0
  18. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/shared/http_client.py +0 -0
  19. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/shared/json_helpers.py +0 -0
  20. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/shared/logging.py +0 -0
  21. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/shared/validation.py +0 -0
  22. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zdatafetch/__init__.py +0 -0
  23. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zdatafetch/activity.py +0 -0
  24. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zdatafetch/auth.py +0 -0
  25. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zdatafetch/cli.py +0 -0
  26. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zdatafetch/config.py +0 -0
  27. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zdatafetch/followers.py +0 -0
  28. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zdatafetch/logging_config.py +0 -0
  29. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zdatafetch/profile.py +0 -0
  30. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zdatafetch/rideons.py +0 -0
  31. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zdatafetch/ridersinworld.py +0 -0
  32. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zdatafetch/worlds.py +0 -0
  33. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zpdatafetch/__init__.py +0 -0
  34. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zpdatafetch/async_zp.py +0 -0
  35. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zpdatafetch/config.py +0 -0
  36. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zpdatafetch/logging_config.py +0 -0
  37. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zpdatafetch/zp.py +0 -0
  38. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zpdatafetch/zp_obj.py +0 -0
  39. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zpdatafetch/zp_utils.py +0 -0
  40. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zpdatafetch/zpcyclist.py +0 -0
  41. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zpdatafetch/zpcyclistfetch.py +0 -0
  42. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zpdatafetch/zpprime.py +0 -0
  43. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zpdatafetch/zpprimesfetch.py +0 -0
  44. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zpdatafetch/zpracefinish.py +0 -0
  45. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zpdatafetch/zpracelog.py +0 -0
  46. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zpdatafetch/zpraceresult.py +0 -0
  47. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zpdatafetch/zpracesignup.py +0 -0
  48. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zpdatafetch/zpracesprint.py +0 -0
  49. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zpdatafetch/zpresultfetch.py +0 -0
  50. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zpdatafetch/zpsignupfetch.py +0 -0
  51. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zpdatafetch/zpsprintsfetch.py +0 -0
  52. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zpdatafetch/zpteam.py +0 -0
  53. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zpdatafetch/zpteamfetch.py +0 -0
  54. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zpdatafetch.egg-info/SOURCES.txt +0 -0
  55. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zpdatafetch.egg-info/dependency_links.txt +0 -0
  56. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zpdatafetch.egg-info/entry_points.txt +0 -0
  57. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zpdatafetch.egg-info/requires.txt +0 -0
  58. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zpdatafetch.egg-info/top_level.txt +0 -0
  59. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zrdatafetch/__init__.py +0 -0
  60. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zrdatafetch/config.py +0 -0
  61. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zrdatafetch/logging_config.py +0 -0
  62. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zrdatafetch/rate_limiter.py +0 -0
  63. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zrdatafetch/zr.py +0 -0
  64. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zrdatafetch/zr_utils.py +0 -0
  65. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zrdatafetch/zrraceresult.py +0 -0
  66. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zrdatafetch/zrresultfetch.py +0 -0
  67. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zrdatafetch/zrrider.py +0 -0
  68. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zrdatafetch/zrriderfetch.py +0 -0
  69. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zrdatafetch/zrteamfetch.py +0 -0
  70. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zrdatafetch/zrteamroster.py +0 -0
  71. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zsdatafetch/__init__.py +0 -0
  72. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zsdatafetch/async_zs.py +0 -0
  73. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zsdatafetch/cli.py +0 -0
  74. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zsdatafetch/logging_config.py +0 -0
  75. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zsdatafetch/models/__init__.py +0 -0
  76. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zsdatafetch/models/component.py +0 -0
  77. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zsdatafetch/models/incident.py +0 -0
  78. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zsdatafetch/models/maintenance.py +0 -0
  79. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zsdatafetch/models/page.py +0 -0
  80. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zsdatafetch/models/status.py +0 -0
  81. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zsdatafetch/models/summary.py +0 -0
  82. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zsdatafetch/zs.py +0 -0
  83. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zsdatafetch/zsincidentfetch.py +0 -0
  84. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zsdatafetch/zsmaintenancefetch.py +0 -0
  85. {zpdatafetch-2.3.1 → zpdatafetch-2.4.0}/src/zsdatafetch/zssummaryfetch.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zpdatafetch
3
- Version: 2.3.1
3
+ Version: 2.4.0
4
4
  Summary: A package for fetching data from Zwiftpower and Zwiftracing.app
5
5
  Author-email: Doug Morris <doug@mhost.com>
6
6
  License-Expression: MIT
@@ -77,7 +77,7 @@ required).
77
77
  - **Primes** - Prime results for Fastest Through Segment (FTS) and First Across the Line (FAL)
78
78
  - **Sprints** - Sprint data including sprint details and positions
79
79
  - **Team data** - Team rosters and member information
80
- - **League data** - League standings and Zwift Racing Score (ZRS) information
80
+ - **League data** - League standings, events, team standings, and league metadata (name, categories, contact)
81
81
 
82
82
  ### For zrdata (Zwiftracing)
83
83
 
@@ -312,7 +312,25 @@ available classes are as follows:
312
312
  - Signup: fetch signups for a particular event by event id
313
313
  - Sprints: fetch sprints from one or more races using event id
314
314
  - Team: fetch team data by team id
315
- - League: fetch league standings by league id
315
+ - League: fetch league standings, events, team standings, team-event results and metadata by league id
316
+
317
+ **League data example:**
318
+
319
+ ```python
320
+ from zpdatafetch import ZPLeagueFetch
321
+
322
+ lf = ZPLeagueFetch()
323
+ league = lf.fetch(3379)[3379]
324
+
325
+ league.info() # ZPLeagueInfo: name, contact, categories, ...
326
+ league.events() # list[ZPLeagueEvent]: event_id, title, start_datetime
327
+ league.team_standings() # list[ZPLeagueTeamStanding]
328
+ league.team_event_results() # list[ZPLeagueTeamEventResult]
329
+ print(league.json()) # all collections as JSON (keys omitted when empty)
330
+ ```
331
+
332
+ Each source is fetched independently: a league without a standings file (e.g.
333
+ 3388) still returns its events and metadata, and vice versa.
316
334
 
317
335
  ## Zwiftracing Data (zrdata)
318
336
 
@@ -704,7 +722,8 @@ status = ZRRider().rate_limiter.get_status() if hasattr(ZRRider(), 'rate_limiter
704
722
 
705
723
  #### Async Rate Limiting
706
724
 
707
- Async operations also respect rate limits with automatic throttling:
725
+ Async operations also respect rate limits with automatic throttling. As with
726
+ the sync API, the tier can be set globally and per call:
708
727
 
709
728
  ```python
710
729
  import anyio
@@ -717,12 +736,23 @@ async def main():
717
736
  rider.set_session(zr)
718
737
  await rider.fetch(12345) # Auto-throttled to standard limits
719
738
 
720
- # Premium tier
721
- async with AsyncZR_obj(premium=True) as zr:
739
+ # Premium tier - set globally (applies to existing and new instances)
740
+ AsyncZR_obj.set_premium_mode(True)
741
+ async with AsyncZR_obj() as zr:
722
742
  rider = AsyncZRRider()
723
743
  rider.set_session(zr)
724
744
  await rider.fetch(12345) # Auto-throttled to premium limits
725
745
 
746
+ # Premium tier - per call
747
+ async with AsyncZR_obj() as zr:
748
+ await zr.fetch_json('/public/riders/12345', premium=True)
749
+
750
+ # Premium tier - per instance
751
+ async with AsyncZR_obj(premium=True) as zr:
752
+ rider = AsyncZRRider()
753
+ rider.set_session(zr)
754
+ await rider.fetch(12345)
755
+
726
756
  anyio.run(main)
727
757
  ```
728
758
 
@@ -48,7 +48,7 @@ required).
48
48
  - **Primes** - Prime results for Fastest Through Segment (FTS) and First Across the Line (FAL)
49
49
  - **Sprints** - Sprint data including sprint details and positions
50
50
  - **Team data** - Team rosters and member information
51
- - **League data** - League standings and Zwift Racing Score (ZRS) information
51
+ - **League data** - League standings, events, team standings, and league metadata (name, categories, contact)
52
52
 
53
53
  ### For zrdata (Zwiftracing)
54
54
 
@@ -283,7 +283,25 @@ available classes are as follows:
283
283
  - Signup: fetch signups for a particular event by event id
284
284
  - Sprints: fetch sprints from one or more races using event id
285
285
  - Team: fetch team data by team id
286
- - League: fetch league standings by league id
286
+ - League: fetch league standings, events, team standings, team-event results and metadata by league id
287
+
288
+ **League data example:**
289
+
290
+ ```python
291
+ from zpdatafetch import ZPLeagueFetch
292
+
293
+ lf = ZPLeagueFetch()
294
+ league = lf.fetch(3379)[3379]
295
+
296
+ league.info() # ZPLeagueInfo: name, contact, categories, ...
297
+ league.events() # list[ZPLeagueEvent]: event_id, title, start_datetime
298
+ league.team_standings() # list[ZPLeagueTeamStanding]
299
+ league.team_event_results() # list[ZPLeagueTeamEventResult]
300
+ print(league.json()) # all collections as JSON (keys omitted when empty)
301
+ ```
302
+
303
+ Each source is fetched independently: a league without a standings file (e.g.
304
+ 3388) still returns its events and metadata, and vice versa.
287
305
 
288
306
  ## Zwiftracing Data (zrdata)
289
307
 
@@ -675,7 +693,8 @@ status = ZRRider().rate_limiter.get_status() if hasattr(ZRRider(), 'rate_limiter
675
693
 
676
694
  #### Async Rate Limiting
677
695
 
678
- Async operations also respect rate limits with automatic throttling:
696
+ Async operations also respect rate limits with automatic throttling. As with
697
+ the sync API, the tier can be set globally and per call:
679
698
 
680
699
  ```python
681
700
  import anyio
@@ -688,12 +707,23 @@ async def main():
688
707
  rider.set_session(zr)
689
708
  await rider.fetch(12345) # Auto-throttled to standard limits
690
709
 
691
- # Premium tier
692
- async with AsyncZR_obj(premium=True) as zr:
710
+ # Premium tier - set globally (applies to existing and new instances)
711
+ AsyncZR_obj.set_premium_mode(True)
712
+ async with AsyncZR_obj() as zr:
693
713
  rider = AsyncZRRider()
694
714
  rider.set_session(zr)
695
715
  await rider.fetch(12345) # Auto-throttled to premium limits
696
716
 
717
+ # Premium tier - per call
718
+ async with AsyncZR_obj() as zr:
719
+ await zr.fetch_json('/public/riders/12345', premium=True)
720
+
721
+ # Premium tier - per instance
722
+ async with AsyncZR_obj(premium=True) as zr:
723
+ rider = AsyncZRRider()
724
+ rider.set_session(zr)
725
+ await rider.fetch(12345)
726
+
697
727
  anyio.run(main)
698
728
  ```
699
729
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "zpdatafetch"
3
- version = "2.3.1"
3
+ version = "2.4.0"
4
4
  description = "A package for fetching data from Zwiftpower and Zwiftracing.app"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -32,6 +32,35 @@ from zpdatafetch import (
32
32
  from zpdatafetch.logging_config import setup_logging
33
33
 
34
34
 
35
+ # ==============================================================================
36
+ def _league_raw_sources(obj: object) -> list[tuple[int, str, str]]:
37
+ """Return (league_id, source_label, raw_text) for a league fetch.
38
+
39
+ Empty for non-league fetches. Lets `--raw` print every fetched league
40
+ source instead of only the standings raw text.
41
+
42
+ Args:
43
+ obj: A fetched data object
44
+
45
+ Returns:
46
+ List of tuples, one per available source per league
47
+ """
48
+ if not hasattr(obj, '_events_raw'):
49
+ return []
50
+ sources = (
51
+ ('standings', getattr(obj, '_raw', {})),
52
+ ('team_standings', getattr(obj, '_team_standings_raw', {})),
53
+ ('team_event_results', getattr(obj, '_team_event_results_raw', {})),
54
+ ('events', getattr(obj, '_events_raw', {})),
55
+ )
56
+ out: list[tuple[int, str, str]] = []
57
+ for lid in getattr(obj, '_fetched', {}):
58
+ for label, raws in sources:
59
+ if isinstance(raws, dict) and lid in raws:
60
+ out.append((lid, label, raws[lid]))
61
+ return out
62
+
63
+
35
64
  # ==============================================================================
36
65
  def main() -> int | None:
37
66
  """Main entry point for the zpdatafetch CLI.
@@ -292,7 +321,12 @@ Module for fetching zwiftpower data using the Zwifpower API
292
321
 
293
322
  if args.raw:
294
323
  # Output raw response text
295
- if len(x._raw) == 1:
324
+ league_raw_sources = _league_raw_sources(x)
325
+ if league_raw_sources:
326
+ # League: print the raw text of every source that was fetched
327
+ for lid, label, raw_text in league_raw_sources:
328
+ print(f'{lid} {label}: {raw_text}')
329
+ elif len(x._raw) == 1:
296
330
  # Single ID: print just the raw string
297
331
  print(list(x._raw.values())[0])
298
332
  else:
@@ -358,6 +392,30 @@ Module for fetching zwiftpower data using the Zwifpower API
358
392
  except (TypeError, AttributeError):
359
393
  pass
360
394
 
395
+ # Nested collections on structured objects (e.g. ZPLeague)
396
+ nested: list[Any] = []
397
+ if hasattr(value, 'info'):
398
+ nested_info = getattr(value, 'info')()
399
+ if nested_info is not None:
400
+ nested.append(nested_info)
401
+ for accessor in ('team_standings', 'team_event_results', 'events'):
402
+ if hasattr(value, accessor):
403
+ nested.extend(getattr(value, accessor)())
404
+
405
+ for nested_item in nested:
406
+ if args.excluded and hasattr(nested_item, 'excluded'):
407
+ nested_excluded = nested_item.excluded()
408
+ if nested_excluded:
409
+ print(f' {nested_item!r}')
410
+ print(f' excluded: {nested_excluded}')
411
+ has_excluded = True
412
+ if args.extras and hasattr(nested_item, 'extras'):
413
+ nested_extras = nested_item.extras()
414
+ if nested_extras:
415
+ print(f' {nested_item!r}')
416
+ print(f' extras: {nested_extras}')
417
+ has_extras = True
418
+
361
419
  # Show appropriate "no data" messages for each requested flag
362
420
  if args.excluded and not has_excluded:
363
421
  print(' No excluded')
@@ -407,6 +465,27 @@ Module for fetching zwiftpower data using the Zwifpower API
407
465
  # Not a collection, print on same line
408
466
  print(f' {value!r}')
409
467
 
468
+ # Structured objects (e.g. ZPLeague) with nested collections that are
469
+ # not part of their Sequence iteration.
470
+ league_info = (
471
+ getattr(value, 'info')() if hasattr(value, 'info') else None
472
+ )
473
+ if league_info is not None:
474
+ print(f' league_info: {league_info!r}')
475
+ for label, accessor in (
476
+ ('team_standings', 'team_standings'),
477
+ ('team_event_results', 'team_event_results'),
478
+ ('events', 'events'),
479
+ ):
480
+ if not hasattr(value, accessor):
481
+ continue
482
+ nested_items = getattr(value, accessor)()
483
+ if not nested_items:
484
+ continue
485
+ print(f' {label}:')
486
+ for nested_item in nested_items:
487
+ print_collection(nested_item, indent=2)
488
+
410
489
  return None
411
490
 
412
491