rivalsdata-api 1.2.1__tar.gz → 1.2.3__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.
- {rivalsdata_api-1.2.1 → rivalsdata_api-1.2.3}/PKG-INFO +13 -3
- {rivalsdata_api-1.2.1 → rivalsdata_api-1.2.3}/README.md +12 -2
- {rivalsdata_api-1.2.1 → rivalsdata_api-1.2.3}/docs/API.md +14 -2
- {rivalsdata_api-1.2.1 → rivalsdata_api-1.2.3}/docs/PROJECT_CONTEXT.md +13 -3
- {rivalsdata_api-1.2.1 → rivalsdata_api-1.2.3}/pyproject.toml +1 -1
- {rivalsdata_api-1.2.1 → rivalsdata_api-1.2.3}/src/rivalsdata/__init__.py +1 -1
- {rivalsdata_api-1.2.1 → rivalsdata_api-1.2.3}/src/rivalsdata/mcp_server.py +10 -3
- {rivalsdata_api-1.2.1 → rivalsdata_api-1.2.3}/src/rivalsdata/models.py +7 -2
- {rivalsdata_api-1.2.1 → rivalsdata_api-1.2.3}/src/rivalsdata/resources.py +32 -3
- {rivalsdata_api-1.2.1 → rivalsdata_api-1.2.3}/.github/workflows/publish-pypi.yml +0 -0
- {rivalsdata_api-1.2.1 → rivalsdata_api-1.2.3}/.gitignore +0 -0
- {rivalsdata_api-1.2.1 → rivalsdata_api-1.2.3}/CONTRIBUTING.md +0 -0
- {rivalsdata_api-1.2.1 → rivalsdata_api-1.2.3}/LICENSE +0 -0
- {rivalsdata_api-1.2.1 → rivalsdata_api-1.2.3}/src/rivalsdata/client.py +0 -0
- {rivalsdata_api-1.2.1 → rivalsdata_api-1.2.3}/src/rivalsdata/exceptions.py +0 -0
- {rivalsdata_api-1.2.1 → rivalsdata_api-1.2.3}/src/rivalsdata/hero_ids.py +0 -0
- {rivalsdata_api-1.2.1 → rivalsdata_api-1.2.3}/tests/test_class_stats.py +0 -0
- {rivalsdata_api-1.2.1 → rivalsdata_api-1.2.3}/tests/test_hero_names.py +0 -0
- {rivalsdata_api-1.2.1 → rivalsdata_api-1.2.3}/tests/test_typed_responses.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: rivalsdata-api
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.3
|
|
4
4
|
Summary: Python client and MCP server for public Marvel Rivals stats from RivalsData
|
|
5
5
|
Project-URL: Homepage, https://github.com/GS-Rionnag/rivalsdata-api
|
|
6
6
|
Project-URL: Repository, https://github.com/GS-Rionnag/rivalsdata-api
|
|
@@ -64,6 +64,7 @@ print(hero_id("Loki")) # 1016
|
|
|
64
64
|
with RivalsDataClient() as rd:
|
|
65
65
|
player = rd.get_player("GS-") # numeric UID works too
|
|
66
66
|
print(player.name, player.level, player.rank_game_season)
|
|
67
|
+
print(player.win_rate) # Current-season competitive win rate
|
|
67
68
|
|
|
68
69
|
# Player profile sections are lazy resource managers.
|
|
69
70
|
hero_season = player.heroes.fetch(season=20)
|
|
@@ -85,6 +86,11 @@ with RivalsDataClient() as rd:
|
|
|
85
86
|
print(hero_season[0].win_rate) # integer percent when wins/losses are present
|
|
86
87
|
```
|
|
87
88
|
|
|
89
|
+
The player overview's overall win rate (`player.win_rate`) is the **current-season
|
|
90
|
+
competitive win rate**. It uses the latest available competitive season with
|
|
91
|
+
usable counts when a direct source rate is absent; it does not combine seasons.
|
|
92
|
+
Hero and class stats use the season selector supplied to their own methods.
|
|
93
|
+
|
|
88
94
|
Calculated player class statistics are available through
|
|
89
95
|
`player.stats.classes(season=20)` and the MCP `get_player_stats` tool with
|
|
90
96
|
`category="classes"`. Pass a numeric season ID for that season, or
|
|
@@ -110,8 +116,12 @@ the same class response structure.
|
|
|
110
116
|
|
|
111
117
|
Win rates are `total wins / (total wins + total losses)`, rounded to an integer
|
|
112
118
|
percent. They are weighted by hero records, rather than averaging hero win
|
|
113
|
-
rates.
|
|
114
|
-
|
|
119
|
+
rates. The response's `metadata` identifies the source, formula, and requested
|
|
120
|
+
season scope. Upstream hero-switch attribution is unknown; hero records may
|
|
121
|
+
overlap within a match, so these totals cannot establish distinct match counts
|
|
122
|
+
or the player's overall match win rate. All-seasons coverage is limited to
|
|
123
|
+
records returned by the source; complete lifetime coverage is unverified.
|
|
124
|
+
Excluded rows also produce a metadata warning. Empty modes
|
|
115
125
|
have a `None` win rate. Role mappings were observed on RivalsData on
|
|
116
126
|
2026-09-30, including Deadpool's separate role IDs; generic Deadpool and unknown
|
|
117
127
|
IDs are excluded rather than assigned a guessed class.
|
|
@@ -28,6 +28,7 @@ print(hero_id("Loki")) # 1016
|
|
|
28
28
|
with RivalsDataClient() as rd:
|
|
29
29
|
player = rd.get_player("GS-") # numeric UID works too
|
|
30
30
|
print(player.name, player.level, player.rank_game_season)
|
|
31
|
+
print(player.win_rate) # Current-season competitive win rate
|
|
31
32
|
|
|
32
33
|
# Player profile sections are lazy resource managers.
|
|
33
34
|
hero_season = player.heroes.fetch(season=20)
|
|
@@ -49,6 +50,11 @@ with RivalsDataClient() as rd:
|
|
|
49
50
|
print(hero_season[0].win_rate) # integer percent when wins/losses are present
|
|
50
51
|
```
|
|
51
52
|
|
|
53
|
+
The player overview's overall win rate (`player.win_rate`) is the **current-season
|
|
54
|
+
competitive win rate**. It uses the latest available competitive season with
|
|
55
|
+
usable counts when a direct source rate is absent; it does not combine seasons.
|
|
56
|
+
Hero and class stats use the season selector supplied to their own methods.
|
|
57
|
+
|
|
52
58
|
Calculated player class statistics are available through
|
|
53
59
|
`player.stats.classes(season=20)` and the MCP `get_player_stats` tool with
|
|
54
60
|
`category="classes"`. Pass a numeric season ID for that season, or
|
|
@@ -74,8 +80,12 @@ the same class response structure.
|
|
|
74
80
|
|
|
75
81
|
Win rates are `total wins / (total wins + total losses)`, rounded to an integer
|
|
76
82
|
percent. They are weighted by hero records, rather than averaging hero win
|
|
77
|
-
rates.
|
|
78
|
-
|
|
83
|
+
rates. The response's `metadata` identifies the source, formula, and requested
|
|
84
|
+
season scope. Upstream hero-switch attribution is unknown; hero records may
|
|
85
|
+
overlap within a match, so these totals cannot establish distinct match counts
|
|
86
|
+
or the player's overall match win rate. All-seasons coverage is limited to
|
|
87
|
+
records returned by the source; complete lifetime coverage is unverified.
|
|
88
|
+
Excluded rows also produce a metadata warning. Empty modes
|
|
79
89
|
have a `None` win rate. Role mappings were observed on RivalsData on
|
|
80
90
|
2026-09-30, including Deadpool's separate role IDs; generic Deadpool and unknown
|
|
81
91
|
IDs are excluded rather than assigned a guessed class.
|
|
@@ -48,6 +48,12 @@ integer percentage from a direct win-rate field, `wins`/`losses`, or the
|
|
|
48
48
|
competitive profile row's `win_count`/`battle_count`. If the source provides
|
|
49
49
|
none of these, it returns `None`.
|
|
50
50
|
|
|
51
|
+
The player overview's overall win rate (`Player.win_rate`) refers to the current
|
|
52
|
+
competitive season, using the latest available competitive season with usable
|
|
53
|
+
counts when a direct source rate is absent. It does not sum historical seasons.
|
|
54
|
+
MCP overview/dashboard descriptions identify this scope, and the dashboard labels
|
|
55
|
+
the value as a season win rate. Hero and class rates follow their season selectors.
|
|
56
|
+
|
|
51
57
|
## Observed UI and routes
|
|
52
58
|
|
|
53
59
|
`player.stats.classes(season=...)` derives tank (Vanguard), support (Strategist),
|
|
@@ -59,8 +65,14 @@ omitting the season keeps the endpoint default. `player.stats.heroes` and MCP
|
|
|
59
65
|
`get_player_stats` support the same selector. The method also sums
|
|
60
66
|
MVP/SVP counts when every included row supplies them. Win rate is calculated
|
|
61
67
|
from summed wins and losses. Unknown classes and incomplete win/loss rows appear
|
|
62
|
-
in `excluded`.
|
|
63
|
-
|
|
68
|
+
in `excluded`. The response includes `metadata` with `source`, `counts_basis`,
|
|
69
|
+
`win_rate_formula`, `unique_matches_verified`, `hero_switch_attribution`,
|
|
70
|
+
`season`, `season_scope`, and `warnings`. Numeric seasons have scope `season`,
|
|
71
|
+
`"all"` and `-1` normalize to season/scope `"all"`, and an omitted season has
|
|
72
|
+
scope `endpoint_default` with season `None`. Hero-switch attribution is unknown,
|
|
73
|
+
so summed hero records cannot establish unique match counts or a player's
|
|
74
|
+
overall match win rate. Complete lifetime coverage for all-seasons data is
|
|
75
|
+
unverified. Warnings flag those limitations and any excluded records.
|
|
64
76
|
|
|
65
77
|
The roster at `/stats` on 2026-09-30 identifies Deadpool variants as 10571
|
|
66
78
|
(tank), 10572 (DPS), and 10573 (support), Daredevil as 1055, and Angela as 1056.
|
|
@@ -15,7 +15,7 @@ as public, stable methods. Keep requests respectful and conservative.
|
|
|
15
15
|
## Current package
|
|
16
16
|
|
|
17
17
|
- Distribution: `rivalsdata-api`; import: `rivalsdata`.
|
|
18
|
-
- Version: `1.2.
|
|
18
|
+
- Version: `1.2.2`.
|
|
19
19
|
- Python `>=3.10`, Hatchling build, `src/` layout.
|
|
20
20
|
- Runtime HTTP dependency: `curl-cffi`; optional browser fallback: Camoufox.
|
|
21
21
|
- Public entry point: `RivalsDataClient`.
|
|
@@ -54,6 +54,12 @@ Favorites requires numeric UIDs and returns player summary rows.
|
|
|
54
54
|
Rows offer `.win_rate` and `.winrate` integer-percent access when data supports
|
|
55
55
|
it; all original data remains in mapping access.
|
|
56
56
|
|
|
57
|
+
The player overview's overall win rate (`player.win_rate`) is for the current
|
|
58
|
+
competitive season (latest available season with usable counts when there is no
|
|
59
|
+
direct source rate), not an all-seasons aggregate. Keep this scope explicit in
|
|
60
|
+
docs, MCP descriptions, and dashboard labels. Hero/class stats have separate
|
|
61
|
+
season selectors.
|
|
62
|
+
|
|
57
63
|
`player.stats.classes(season=...)` groups observed hero IDs into tank, support,
|
|
58
64
|
and DPS. Supply a numeric season ID for one season or `season="all"` for
|
|
59
65
|
combined all-seasons stats; the latter sends `season=-1` to the upstream API.
|
|
@@ -63,8 +69,12 @@ It sums games, wins, losses, and available MVP/SVP counts separately
|
|
|
63
69
|
for competitive and quickplay, with win rates calculated from summed wins and
|
|
64
70
|
losses. The response has typed `classes` rows and an `excluded` list for unknown
|
|
65
71
|
roles or incomplete win/loss data. MCP exposes it through `get_player_stats`
|
|
66
|
-
with `category="classes"`.
|
|
67
|
-
|
|
72
|
+
with `category="classes"`. Response `metadata` describes the source, formula,
|
|
73
|
+
season scope, and limitations. Upstream hero-switch attribution and distinct
|
|
74
|
+
match counts are unverified; do not derive player overall win rate from class
|
|
75
|
+
totals. All-seasons coverage is limited to returned records, with complete
|
|
76
|
+
lifetime coverage unverified. Excluded rows produce a metadata warning.
|
|
77
|
+
Role IDs and the corrected Angela/Daredevil IDs were
|
|
68
78
|
verified against RivalsData's roster on 2026-09-30; Deadpool has separate role
|
|
69
79
|
variants (10571/10572/10573), while generic 1057 remains unclassified.
|
|
70
80
|
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "rivalsdata-api"
|
|
7
|
-
version = "1.2.
|
|
7
|
+
version = "1.2.3"
|
|
8
8
|
description = "Python client and MCP server for public Marvel Rivals stats from RivalsData"
|
|
9
9
|
keywords = ["marvel-rivals", "rivalsdata", "game-stats", "api-client", "mcp"]
|
|
10
10
|
readme = "README.md"
|
|
@@ -108,7 +108,11 @@ def search_players(name: str) -> dict[str, Any]:
|
|
|
108
108
|
|
|
109
109
|
@mcp.tool()
|
|
110
110
|
def get_player(uid_or_name: str) -> dict[str, Any]:
|
|
111
|
-
"""Get a public player overview by numeric UID or in-game name.
|
|
111
|
+
"""Get a public player overview by numeric UID or in-game name.
|
|
112
|
+
|
|
113
|
+
The overview's overall win rate refers to the current competitive season
|
|
114
|
+
(latest available season with usable counts), not all seasons combined.
|
|
115
|
+
"""
|
|
112
116
|
return _call(lambda client, value: client.get_player(value).raw, uid_or_name)
|
|
113
117
|
|
|
114
118
|
|
|
@@ -141,6 +145,7 @@ def show_player_dashboard(
|
|
|
141
145
|
combining live-match, hero, and match-history pulls. MCP Apps hosts can
|
|
142
146
|
render the returned dashboard resource; all values are escaped before HTML
|
|
143
147
|
output.
|
|
148
|
+
The competitive record and win rate are for the latest available season.
|
|
144
149
|
"""
|
|
145
150
|
with RivalsDataClient() as client:
|
|
146
151
|
player = client.get_player(uid_or_name)
|
|
@@ -168,7 +173,7 @@ def show_player_dashboard(
|
|
|
168
173
|
competitive_summary = (
|
|
169
174
|
f'<div class="competitive-line">'
|
|
170
175
|
f'<span>{battles:,} competitive games</span>'
|
|
171
|
-
+ (f'<span>{rate}% win rate</span>' if rate is not None else "")
|
|
176
|
+
+ (f'<span>{rate}% season win rate</span>' if rate is not None else "")
|
|
172
177
|
+ (f'<span>{escape(str(score))} RP</span>' if score is not None else "")
|
|
173
178
|
+ '</div>'
|
|
174
179
|
)
|
|
@@ -414,7 +419,9 @@ def get_player_stats(
|
|
|
414
419
|
"""Get player stats: heroes, maps, bans, or calculated classes.
|
|
415
420
|
|
|
416
421
|
Classes sum hero wins/losses by tank/support/dps and game mode; these are
|
|
417
|
-
hero
|
|
422
|
+
summed hero records, which may overlap within a match. The response metadata
|
|
423
|
+
explains the calculation and scope; class totals cannot establish a player's
|
|
424
|
+
overall match win rate. Upstream hero-switch attribution is unknown.
|
|
418
425
|
Supply a season ID or "all" for combined all-seasons totals. Omitting the
|
|
419
426
|
season uses the endpoint default.
|
|
420
427
|
"""
|
|
@@ -428,10 +428,11 @@ class ClassStatsRecord(DataModel):
|
|
|
428
428
|
|
|
429
429
|
|
|
430
430
|
class ClassStatsResponse(DataModel):
|
|
431
|
-
"""Derived class totals
|
|
431
|
+
"""Derived class totals, excluded rows, and calculation metadata."""
|
|
432
432
|
|
|
433
433
|
classes: list[ClassStatsRecord]
|
|
434
434
|
excluded: list[DataModel]
|
|
435
|
+
metadata: DataModel
|
|
435
436
|
|
|
436
437
|
def __init__(self, data: Mapping[str, Any] | None = None, **values: Any) -> None:
|
|
437
438
|
super().__init__(data, **values)
|
|
@@ -983,7 +984,11 @@ class Player(DataModel):
|
|
|
983
984
|
|
|
984
985
|
@property
|
|
985
986
|
def win_rate(self) -> int | None:
|
|
986
|
-
"""
|
|
987
|
+
"""Current-season competitive win rate when profile counts are available.
|
|
988
|
+
|
|
989
|
+
Uses a direct source rate or the latest available competitive season
|
|
990
|
+
with usable counts. This property does not aggregate across seasons.
|
|
991
|
+
"""
|
|
987
992
|
direct = StatRecord(self._data).win_rate
|
|
988
993
|
if direct is not None:
|
|
989
994
|
return direct
|
|
@@ -225,8 +225,10 @@ class PlayerStats(PlayerResource):
|
|
|
225
225
|
Supply a season ID or ``season="all"`` for combined all-seasons totals.
|
|
226
226
|
Omitting ``season`` preserves the endpoint default.
|
|
227
227
|
Win rate uses total wins / (wins + losses), not the average of hero
|
|
228
|
-
percentages. Counts
|
|
229
|
-
|
|
228
|
+
percentages. Counts are summed upstream hero records. The upstream
|
|
229
|
+
attribution rule for hero switches is unknown, so distinct match
|
|
230
|
+
counts cannot be established from these rows. ``metadata`` describes
|
|
231
|
+
the calculation and requested season scope.
|
|
230
232
|
Unknown roles and incomplete win/loss rows are listed in ``excluded``.
|
|
231
233
|
"""
|
|
232
234
|
groups = {
|
|
@@ -271,7 +273,34 @@ class PlayerStats(PlayerResource):
|
|
|
271
273
|
total = totals["wins"] + totals["losses"]
|
|
272
274
|
totals["win_rate"] = round(totals["wins"] * 100 / total) if total else None
|
|
273
275
|
group[mode] = totals
|
|
274
|
-
|
|
276
|
+
all_seasons = season in ("all", -1)
|
|
277
|
+
warnings = [
|
|
278
|
+
"Hero records may overlap within a match. Class totals must not "
|
|
279
|
+
"be used to calculate the player's overall match win rate."
|
|
280
|
+
]
|
|
281
|
+
if all_seasons:
|
|
282
|
+
warnings.append(
|
|
283
|
+
"All-seasons results cover the records returned by the source; "
|
|
284
|
+
"complete lifetime coverage is not verified."
|
|
285
|
+
)
|
|
286
|
+
if excluded:
|
|
287
|
+
warnings.append(
|
|
288
|
+
"Some hero or mode records were excluded; see excluded for details."
|
|
289
|
+
)
|
|
290
|
+
metadata = {
|
|
291
|
+
"source": "/player/stats/heroes",
|
|
292
|
+
"counts_basis": "summed_hero_records",
|
|
293
|
+
"win_rate_formula": "wins / (wins + losses) * 100",
|
|
294
|
+
"unique_matches_verified": False,
|
|
295
|
+
"hero_switch_attribution": "unknown",
|
|
296
|
+
"season": "all" if all_seasons else season,
|
|
297
|
+
"season_scope": "all" if all_seasons else (
|
|
298
|
+
"endpoint_default" if season is None else "season"
|
|
299
|
+
),
|
|
300
|
+
"warnings": warnings,
|
|
301
|
+
}
|
|
302
|
+
return ClassStatsResponse({"classes": list(groups.values()), "excluded": excluded,
|
|
303
|
+
"metadata": metadata})
|
|
275
304
|
|
|
276
305
|
def maps(self, *, season: int | None = None) -> list[MapRecord]:
|
|
277
306
|
payload = {"season": season} if season is not None else {}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|