impectPy 2.5.0__tar.gz → 2.5.2__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 (28) hide show
  1. {impectPy-2.5.0 → impectpy-2.5.2}/PKG-INFO +14 -5
  2. {impectPy-2.5.0 → impectpy-2.5.2}/README.md +3 -3
  3. {impectPy-2.5.0 → impectpy-2.5.2}/impectPy/__init__.py +1 -1
  4. {impectPy-2.5.0 → impectpy-2.5.2}/impectPy/events.py +41 -24
  5. {impectPy-2.5.0 → impectpy-2.5.2}/impectPy/helpers.py +9 -4
  6. {impectPy-2.5.0 → impectpy-2.5.2}/impectPy/iteration_averages.py +18 -7
  7. {impectPy-2.5.0 → impectpy-2.5.2}/impectPy/matchsums.py +67 -37
  8. {impectPy-2.5.0 → impectpy-2.5.2}/impectPy/player_scores.py +34 -19
  9. {impectPy-2.5.0 → impectpy-2.5.2}/impectPy/squad_scores.py +34 -19
  10. {impectPy-2.5.0 → impectpy-2.5.2}/impectPy.egg-info/PKG-INFO +14 -5
  11. {impectPy-2.5.0 → impectpy-2.5.2}/setup.py +1 -1
  12. {impectPy-2.5.0 → impectpy-2.5.2}/LICENSE.md +0 -0
  13. {impectPy-2.5.0 → impectpy-2.5.2}/impectPy/access_token.py +0 -0
  14. {impectPy-2.5.0 → impectpy-2.5.2}/impectPy/config.py +0 -0
  15. {impectPy-2.5.0 → impectpy-2.5.2}/impectPy/impect.py +0 -0
  16. {impectPy-2.5.0 → impectpy-2.5.2}/impectPy/iterations.py +0 -0
  17. {impectPy-2.5.0 → impectpy-2.5.2}/impectPy/match_info.py +0 -0
  18. {impectPy-2.5.0 → impectpy-2.5.2}/impectPy/matches.py +0 -0
  19. {impectPy-2.5.0 → impectpy-2.5.2}/impectPy/player_profile_scores.py +0 -0
  20. {impectPy-2.5.0 → impectpy-2.5.2}/impectPy/set_pieces.py +0 -0
  21. {impectPy-2.5.0 → impectpy-2.5.2}/impectPy/squad_coefficients.py +0 -0
  22. {impectPy-2.5.0 → impectpy-2.5.2}/impectPy/squad_ratings.py +0 -0
  23. {impectPy-2.5.0 → impectpy-2.5.2}/impectPy/xml.py +0 -0
  24. {impectPy-2.5.0 → impectpy-2.5.2}/impectPy.egg-info/SOURCES.txt +0 -0
  25. {impectPy-2.5.0 → impectpy-2.5.2}/impectPy.egg-info/dependency_links.txt +0 -0
  26. {impectPy-2.5.0 → impectpy-2.5.2}/impectPy.egg-info/requires.txt +0 -0
  27. {impectPy-2.5.0 → impectpy-2.5.2}/impectPy.egg-info/top_level.txt +0 -0
  28. {impectPy-2.5.0 → impectpy-2.5.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: impectPy
3
- Version: 2.5.0
3
+ Version: 2.5.2
4
4
  Summary: A Python package to facilitate interaction with the Impect customer API
5
5
  Home-page: https://github.com/ImpectAPI/impectPy
6
6
  Author: Impect
@@ -11,14 +11,23 @@ License-File: LICENSE.md
11
11
  Requires-Dist: requests>=2.24.0
12
12
  Requires-Dist: pandas>=2.0.0
13
13
  Requires-Dist: numpy<2.0,>=1.24.2
14
+ Dynamic: author
15
+ Dynamic: author-email
16
+ Dynamic: description
17
+ Dynamic: description-content-type
18
+ Dynamic: home-page
19
+ Dynamic: license
20
+ Dynamic: license-file
21
+ Dynamic: requires-dist
22
+ Dynamic: summary
14
23
 
15
24
  # impectPy <picture><source media="(prefers-color-scheme: dark)" srcset="https://github.com/ImpectAPI/logos/blob/main/impectPy_white.svg"><source media="(prefers-color-scheme: light)" srcset="https://github.com/ImpectAPI/logos/blob/main/impectPy_black.svg"><img alt="ImpectPy Logo" src="https://github.com/ImpectAPI/logos/blob/main/impectPy_black.svg" align="right" height="40"></picture>
16
25
 
17
26
  A package provided by: Impect GmbH
18
27
 
19
- Version: v2.5.0
28
+ Version: v2.5.2
20
29
 
21
- **Updated: October 15th 2025**
30
+ **Updated: October 20th 2025**
22
31
 
23
32
  ---
24
33
 
@@ -49,7 +58,7 @@ pip install impectPy
49
58
  You can also install it from [GitHub](https://github.com/) with:
50
59
 
51
60
  ```cmd
52
- pip install git+https://github.com/ImpectAPI/impectPy.git@v2.5.0
61
+ pip install git+https://github.com/ImpectAPI/impectPy.git@v2.5.2
53
62
  ```
54
63
 
55
64
  ## Usage
@@ -2,9 +2,9 @@
2
2
 
3
3
  A package provided by: Impect GmbH
4
4
 
5
- Version: v2.5.0
5
+ Version: v2.5.2
6
6
 
7
- **Updated: October 15th 2025**
7
+ **Updated: October 20th 2025**
8
8
 
9
9
  ---
10
10
 
@@ -35,7 +35,7 @@ pip install impectPy
35
35
  You can also install it from [GitHub](https://github.com/) with:
36
36
 
37
37
  ```cmd
38
- pip install git+https://github.com/ImpectAPI/impectPy.git@v2.5.0
38
+ pip install git+https://github.com/ImpectAPI/impectPy.git@v2.5.2
39
39
  ```
40
40
 
41
41
  ## Usage
@@ -1,5 +1,5 @@
1
1
  # define version attribute
2
- __version__ = "2.5.0"
2
+ __version__ = "2.5.2"
3
3
 
4
4
  # import modules
5
5
  from .access_token import getAccessToken
@@ -2,10 +2,10 @@
2
2
  import numpy as np
3
3
  import pandas as pd
4
4
  import requests
5
- from impectPy.helpers import RateLimitedAPI
5
+ import re
6
+ from impectPy.helpers import RateLimitedAPI, ForbiddenError
6
7
  from .matches import getMatchesFromHost
7
8
  from .iterations import getIterationsFromHost
8
- import re
9
9
 
10
10
  ######
11
11
  #
@@ -119,16 +119,23 @@ def getEventsFromHost(
119
119
  ignore_index=True)[["id", "name"]].drop_duplicates()
120
120
 
121
121
  # get coaches
122
- coaches = pd.concat(
123
- map(lambda iteration: connection.make_api_request_limited(
124
- url=f"{host}/v5/customerapi/iterations/{iteration}/coaches",
125
- method="GET"
126
- ).process_response(
127
- endpoint="Coaches",
128
- raise_exception=False
129
- ),
130
- iterations),
131
- ignore_index=True)[["id", "name"]].drop_duplicates()
122
+ coaches_blacklisted = False
123
+ try:
124
+ coaches = pd.concat(
125
+ map(lambda iteration: connection.make_api_request_limited(
126
+ url=f"{host}/v5/customerapi/iterations/{iteration}/coaches",
127
+ method="GET"
128
+ ).process_response(
129
+ endpoint="Coaches",
130
+ raise_exception=False
131
+ ),
132
+ iterations),
133
+ ignore_index=True)[["id", "name"]].drop_duplicates()
134
+ except KeyError:
135
+ # no coaches found, create empty df
136
+ coaches = pd.DataFrame(columns=["id", "name"])
137
+ except ForbiddenError:
138
+ coaches_blacklisted = True
132
139
 
133
140
  # get matches
134
141
  matchplan = pd.concat(
@@ -265,18 +272,6 @@ def getEventsFromHost(
265
272
  right_on="id",
266
273
  how="left",
267
274
  suffixes=("", "_right")
268
- ).merge(
269
- coaches[["id", "name"]].rename(columns={"id": "homeCoachId", "name": "homeCoachName"}),
270
- left_on="homeSquadCoachId",
271
- right_on="homeCoachId",
272
- how="left",
273
- suffixes=("", "_right")
274
- ).merge(
275
- coaches[["id", "name"]].rename(columns={"id": "awayCoachId", "name": "awayCoachName"}),
276
- left_on="awaySquadCoachId",
277
- right_on="awayCoachId",
278
- how="left",
279
- suffixes=("", "_right")
280
275
  ).merge(
281
276
  iterations,
282
277
  left_on="iterationId",
@@ -285,6 +280,25 @@ def getEventsFromHost(
285
280
  suffixes=("", "_right")
286
281
  )
287
282
 
283
+ if not coaches_blacklisted:
284
+
285
+ # convert coachId to integer if it is None
286
+ events["homeSquadCoachId"] = events["homeSquadCoachId"].astype("Int64")
287
+ events["awaySquadCoachId"] = events["awaySquadCoachId"].astype("Int64")
288
+ events = events.merge(
289
+ coaches[["id", "name"]].rename(columns={"id": "homeCoachId", "name": "homeCoachName"}),
290
+ left_on="homeSquadCoachId",
291
+ right_on="homeCoachId",
292
+ how="left",
293
+ suffixes=("", "_right")
294
+ ).merge(
295
+ coaches[["id", "name"]].rename(columns={"id": "awayCoachId", "name": "awayCoachName"}),
296
+ left_on="awaySquadCoachId",
297
+ right_on="awayCoachId",
298
+ how="left",
299
+ suffixes=("", "_right")
300
+ )
301
+
288
302
  if include_kpis:
289
303
  # unnest scorings and full join with kpi list to ensure all kpis are present
290
304
  scorings = scorings.merge(kpis, left_on="kpiId", right_on="id", how="outer") \
@@ -532,6 +546,9 @@ def getEventsFromHost(
532
546
  # add kpis
533
547
  order = order + kpi_cols
534
548
 
549
+ if coaches_blacklisted:
550
+ order = [col for col in order if col not in ["homeCoachId", "homeCoachName", "awayCoachId", "awayCoachName"]]
551
+
535
552
  # reorder data
536
553
  events = events[order]
537
554
 
@@ -15,6 +15,11 @@ import math
15
15
  ######
16
16
 
17
17
 
18
+ class ForbiddenError(Exception):
19
+ """Raised when the API returns a 403 Forbidden response."""
20
+ pass
21
+
22
+
18
23
  class RateLimitedAPI:
19
24
  def __init__(self, session: Optional[requests.Session] = None):
20
25
  """
@@ -115,10 +120,10 @@ class RateLimitedAPI:
115
120
  f"Request-ID: {response.headers['x-request-id']} "
116
121
  f"(Make sure to include this in any support request.)")
117
122
  elif response.status_code == 403:
118
- raise Exception(f"Received status code {response.status_code} "
119
- f"(You do not have access to this resource.)\n"
120
- f"Request-ID: {response.headers['x-request-id']} "
121
- f"(Make sure to include this in any support request.)")
123
+ raise ForbiddenError(f"Received status code {response.status_code} "
124
+ f"(You do not have access to this resource.)\n"
125
+ f"Request-ID: {response.headers['x-request-id']} "
126
+ f"(Make sure to include this in any support request.)")
122
127
  # check status code and terminate if other error
123
128
  else:
124
129
  raise Exception(f"Received status code {response.status_code} "
@@ -118,13 +118,16 @@ def getPlayerIterationAveragesFromHost(
118
118
  if len(averages_raw["name"][averages_raw["name"].isnull()]) > 0:
119
119
  averages_raw["name"] = averages_raw["name"].fillna("-1")
120
120
 
121
- # downcast numerics and category types
122
- averages_raw["iterationId"] = averages_raw["iterationId"].astype("Int16")
123
- averages_raw["squadId"] = averages_raw["squadId"].astype("Int16")
124
- averages_raw["playerId"] = averages_raw["playerId"].astype("Int32")
125
- averages_raw["position"] = averages_raw["position"].astype("category")
126
- averages_raw["name"] = averages_raw["name"].astype("category")
127
- averages_raw["value"] = averages_raw["value"].astype("Float32")
121
+ # get KPIs without a scoring
122
+ mask = (
123
+ averages_raw.iterationId.isnull()
124
+ & averages_raw.squadId.isnull()
125
+ & averages_raw.playerId.isnull()
126
+ & averages_raw.position.isnull()
127
+ )
128
+
129
+ # fill join cols with placeholder
130
+ averages_raw.loc[mask] = averages_raw.loc[mask].fillna(-1)
128
131
 
129
132
  # get matchShares
130
133
  match_shares_raw = averages_raw[
@@ -146,6 +149,14 @@ def getPlayerIterationAveragesFromHost(
146
149
  if "-1" in averages_raw.columns:
147
150
  averages_raw.drop(["-1"], inplace=True, axis=1)
148
151
 
152
+ # drop -1 rows
153
+ averages_raw = averages_raw[
154
+ ~(averages_raw.iterationId == -1)
155
+ & ~(averages_raw.squadId == -1)
156
+ & ~(averages_raw.playerId == -1)
157
+ & ~(averages_raw.position == -1)
158
+ ]
159
+
149
160
  # merge with playDuration and matchShare
150
161
  averages_raw = averages_raw.merge(
151
162
  match_shares_raw,
@@ -1,7 +1,7 @@
1
1
  # load packages
2
2
  import pandas as pd
3
3
  import requests
4
- from impectPy.helpers import RateLimitedAPI, unnest_mappings_df
4
+ from impectPy.helpers import RateLimitedAPI, unnest_mappings_df, ForbiddenError
5
5
  from .matches import getMatchesFromHost
6
6
  from .iterations import getIterationsFromHost
7
7
 
@@ -102,16 +102,23 @@ def getPlayerMatchsumsFromHost(matches: list, connection: RateLimitedAPI, host:
102
102
  ignore_index=True)[["id", "name"]].drop_duplicates()
103
103
 
104
104
  # get coaches
105
- coaches = pd.concat(
106
- map(lambda iteration: connection.make_api_request_limited(
107
- url=f"{host}/v5/customerapi/iterations/{iteration}/coaches",
108
- method="GET"
109
- ).process_response(
110
- endpoint="Coaches",
111
- raise_exception=False
112
- ),
113
- iterations),
114
- ignore_index=True)[["id", "name"]].drop_duplicates()
105
+ coaches_blacklisted = False
106
+ try:
107
+ coaches = pd.concat(
108
+ map(lambda iteration: connection.make_api_request_limited(
109
+ url=f"{host}/v5/customerapi/iterations/{iteration}/coaches",
110
+ method="GET"
111
+ ).process_response(
112
+ endpoint="Coaches",
113
+ raise_exception=False
114
+ ),
115
+ iterations),
116
+ ignore_index=True)[["id", "name"]].drop_duplicates()
117
+ except KeyError:
118
+ # no coaches found, create empty df
119
+ coaches = pd.DataFrame(columns=["id", "name"])
120
+ except ForbiddenError:
121
+ coaches_blacklisted = True
115
122
 
116
123
  # get kpis
117
124
  kpis = connection.make_api_request_limited(
@@ -248,14 +255,6 @@ def getPlayerMatchsumsFromHost(matches: list, connection: RateLimitedAPI, host:
248
255
  right_on="id",
249
256
  how="left",
250
257
  suffixes=("", "_right")
251
- ).merge(
252
- coaches[["id", "name"]].rename(
253
- columns={"id": "coachId", "name": "coachName"}
254
- ),
255
- left_on="coachId",
256
- right_on="coachId",
257
- how="left",
258
- suffixes=("", "_right")
259
258
  ).merge(
260
259
  countries.rename(columns={"fifaName": "playerCountry"}),
261
260
  left_on="countryId",
@@ -264,6 +263,18 @@ def getPlayerMatchsumsFromHost(matches: list, connection: RateLimitedAPI, host:
264
263
  suffixes=("", "_right")
265
264
  )
266
265
 
266
+ if not coaches_blacklisted:
267
+ matchsums["coachId"] = matchsums["coachId"].astype("Int64")
268
+ matchsums = matchsums.merge(
269
+ coaches[["id", "name"]].rename(
270
+ columns={"id": "coachId", "name": "coachName"}
271
+ ),
272
+ left_on="coachId",
273
+ right_on="coachId",
274
+ how="left",
275
+ suffixes=("", "_right")
276
+ )
277
+
267
278
  # rename some columns
268
279
  matchsums = matchsums.rename(columns={
269
280
  "scheduledDate": "dateTime",
@@ -304,6 +315,10 @@ def getPlayerMatchsumsFromHost(matches: list, connection: RateLimitedAPI, host:
304
315
  # add kpiNames to order
305
316
  order += kpis['name'].to_list()
306
317
 
318
+ # check if coaches are blacklisted
319
+ if coaches_blacklisted:
320
+ order = [col for col in order if col not in ["coachId", "coachName"]]
321
+
307
322
  # select columns
308
323
  matchsums = matchsums[order]
309
324
 
@@ -395,16 +410,23 @@ def getSquadMatchsumsFromHost(matches: list, connection: RateLimitedAPI, host: s
395
410
  ignore_index=True)[["id", "name", "idMappings"]]
396
411
 
397
412
  # get coaches
398
- coaches = pd.concat(
399
- map(lambda iteration: connection.make_api_request_limited(
400
- url=f"{host}/v5/customerapi/iterations/{iteration}/coaches",
401
- method="GET"
402
- ).process_response(
403
- endpoint="Coaches",
404
- raise_exception=False
405
- ),
406
- iterations),
407
- ignore_index=True)[["id", "name"]].drop_duplicates()
413
+ coaches_blacklisted = False
414
+ try:
415
+ coaches = pd.concat(
416
+ map(lambda iteration: connection.make_api_request_limited(
417
+ url=f"{host}/v5/customerapi/iterations/{iteration}/coaches",
418
+ method="GET"
419
+ ).process_response(
420
+ endpoint="Coaches",
421
+ raise_exception=False
422
+ ),
423
+ iterations),
424
+ ignore_index=True)[["id", "name"]].drop_duplicates()
425
+ except KeyError:
426
+ # no coaches found, create empty df
427
+ coaches = pd.DataFrame(columns=["id", "name"])
428
+ except ForbiddenError:
429
+ coaches_blacklisted = True
408
430
 
409
431
  # unnest mappings
410
432
  squads = unnest_mappings_df(squads, "idMappings").drop(["idMappings"], axis=1).drop_duplicates()
@@ -502,16 +524,20 @@ def getSquadMatchsumsFromHost(matches: list, connection: RateLimitedAPI, host: s
502
524
  right_on="squadId",
503
525
  how="left",
504
526
  suffixes=("", "_home")
505
- ).merge(
506
- coaches[["id", "name"]].rename(
507
- columns={"id": "coachId", "name": "coachName"}
508
- ),
509
- left_on="coachId",
510
- right_on="coachId",
511
- how="left",
512
- suffixes=("", "_right")
513
527
  )
514
528
 
529
+ if not coaches_blacklisted:
530
+ matchsums["coachId"] = matchsums["coachId"].astype("Int64")
531
+ matchsums = matchsums.merge(
532
+ coaches[["id", "name"]].rename(
533
+ columns={"id": "coachId", "name": "coachName"}
534
+ ),
535
+ left_on="coachId",
536
+ right_on="coachId",
537
+ how="left",
538
+ suffixes=("", "_right")
539
+ )
540
+
515
541
  # rename some columns
516
542
  matchsums = matchsums.rename(columns={
517
543
  "scheduledDate": "dateTime"
@@ -549,6 +575,10 @@ def getSquadMatchsumsFromHost(matches: list, connection: RateLimitedAPI, host: s
549
575
  # reset index
550
576
  matchsums = matchsums.reset_index()
551
577
 
578
+ # check if coaches are blacklisted
579
+ if coaches_blacklisted:
580
+ order = [col for col in order if col not in ["coachId", "coachName"]]
581
+
552
582
  # select & order columns
553
583
  matchsums = matchsums[order]
554
584
 
@@ -1,7 +1,7 @@
1
1
  # load packages
2
2
  import pandas as pd
3
3
  import requests
4
- from impectPy.helpers import RateLimitedAPI, unnest_mappings_df
4
+ from impectPy.helpers import RateLimitedAPI, unnest_mappings_df, ForbiddenError
5
5
  from .matches import getMatchesFromHost
6
6
  from .iterations import getIterationsFromHost
7
7
 
@@ -151,16 +151,23 @@ def getPlayerMatchScoresFromHost(matches: list, connection: RateLimitedAPI, host
151
151
  ignore_index=True)[["id", "name"]].drop_duplicates()
152
152
 
153
153
  # get coaches
154
- coaches = pd.concat(
155
- map(lambda iteration: connection.make_api_request_limited(
156
- url=f"{host}/v5/customerapi/iterations/{iteration}/coaches",
157
- method="GET"
158
- ).process_response(
159
- endpoint="Coaches",
160
- raise_exception=False
161
- ),
162
- iterations),
163
- ignore_index=True)[["id", "name"]].drop_duplicates()
154
+ coaches_blacklisted = False
155
+ try:
156
+ coaches = pd.concat(
157
+ map(lambda iteration: connection.make_api_request_limited(
158
+ url=f"{host}/v5/customerapi/iterations/{iteration}/coaches",
159
+ method="GET"
160
+ ).process_response(
161
+ endpoint="Coaches",
162
+ raise_exception=False
163
+ ),
164
+ iterations),
165
+ ignore_index=True)[["id", "name"]].drop_duplicates()
166
+ except KeyError:
167
+ # no coaches found, create empty df
168
+ coaches = pd.DataFrame(columns=["id", "name"])
169
+ except ForbiddenError:
170
+ coaches_blacklisted = True
164
171
 
165
172
  # get player scores
166
173
  scores = connection.make_api_request_limited(
@@ -350,14 +357,6 @@ def getPlayerMatchScoresFromHost(matches: list, connection: RateLimitedAPI, host
350
357
  right_on="id",
351
358
  how="left",
352
359
  suffixes=("", "_right")
353
- ).merge(
354
- coaches[["id", "name"]].rename(
355
- columns={"id": "coachId", "name": "coachName"}
356
- ),
357
- left_on="coachId",
358
- right_on="coachId",
359
- how="left",
360
- suffixes=("", "_right")
361
360
  ).merge(
362
361
  countries.rename(columns={"fifaName": "playerCountry"}),
363
362
  left_on="countryId",
@@ -366,6 +365,18 @@ def getPlayerMatchScoresFromHost(matches: list, connection: RateLimitedAPI, host
366
365
  suffixes=("", "_right")
367
366
  )
368
367
 
368
+ if not coaches_blacklisted:
369
+ player_scores["coachId"] = player_scores["coachId"].astype("Int64")
370
+ player_scores = player_scores.merge(
371
+ coaches[["id", "name"]].rename(
372
+ columns={"id": "coachId", "name": "coachName"}
373
+ ),
374
+ left_on="coachId",
375
+ right_on="coachId",
376
+ how="left",
377
+ suffixes=("", "_right")
378
+ )
379
+
369
380
  # rename some columns
370
381
  player_scores = player_scores.rename(columns={
371
382
  "scheduledDate": "dateTime",
@@ -406,6 +417,10 @@ def getPlayerMatchScoresFromHost(matches: list, connection: RateLimitedAPI, host
406
417
  # add kpiNames to order
407
418
  order += scores["name"].to_list()
408
419
 
420
+ # check if coaches are blacklisted
421
+ if coaches_blacklisted:
422
+ order = [col for col in order if col not in ["coachId", "coachName"]]
423
+
409
424
  # select columns
410
425
  player_scores = player_scores[order]
411
426
 
@@ -1,7 +1,7 @@
1
1
  # load packages
2
2
  import pandas as pd
3
3
  import requests
4
- from impectPy.helpers import RateLimitedAPI, unnest_mappings_df
4
+ from impectPy.helpers import RateLimitedAPI, unnest_mappings_df, ForbiddenError
5
5
  from .matches import getMatchesFromHost
6
6
  from .iterations import getIterationsFromHost
7
7
 
@@ -81,16 +81,23 @@ def getSquadMatchScoresFromHost(matches: list, connection: RateLimitedAPI, host:
81
81
  ignore_index=True)[["id", "name", "idMappings"]]
82
82
 
83
83
  # get coaches
84
- coaches = pd.concat(
85
- map(lambda iteration: connection.make_api_request_limited(
86
- url=f"{host}/v5/customerapi/iterations/{iteration}/coaches",
87
- method="GET"
88
- ).process_response(
89
- endpoint="Coaches",
90
- raise_exception=False
91
- ),
92
- iterations),
93
- ignore_index=True)[["id", "name"]].drop_duplicates()
84
+ coaches_blacklisted = False
85
+ try:
86
+ coaches = pd.concat(
87
+ map(lambda iteration: connection.make_api_request_limited(
88
+ url=f"{host}/v5/customerapi/iterations/{iteration}/coaches",
89
+ method="GET"
90
+ ).process_response(
91
+ endpoint="Coaches",
92
+ raise_exception=False
93
+ ),
94
+ iterations),
95
+ ignore_index=True)[["id", "name"]].drop_duplicates()
96
+ except KeyError:
97
+ # no coaches found, create empty df
98
+ coaches = pd.DataFrame(columns=["id", "name"])
99
+ except ForbiddenError:
100
+ coaches_blacklisted = True
94
101
 
95
102
  # unnest mappings
96
103
  squads = unnest_mappings_df(squads, "idMappings").drop(["idMappings"], axis=1).drop_duplicates()
@@ -189,16 +196,20 @@ def getSquadMatchScoresFromHost(matches: list, connection: RateLimitedAPI, host:
189
196
  right_on="squadId",
190
197
  how="left",
191
198
  suffixes=("", "_right")
192
- ).merge(
193
- coaches[["id", "name"]].rename(
194
- columns={"id": "coachId", "name": "coachName"}
195
- ),
196
- left_on="coachId",
197
- right_on="coachId",
198
- how="left",
199
- suffixes=("", "_right")
200
199
  )
201
200
 
201
+ if not coaches_blacklisted:
202
+ squad_scores["coachId"] = squad_scores["coachId"].astype("Int64")
203
+ squad_scores = squad_scores.merge(
204
+ coaches[["id", "name"]].rename(
205
+ columns={"id": "coachId", "name": "coachName"}
206
+ ),
207
+ left_on="coachId",
208
+ right_on="coachId",
209
+ how="left",
210
+ suffixes=("", "_right")
211
+ )
212
+
202
213
  # rename some columns
203
214
  squad_scores = squad_scores.rename(columns={
204
215
  "scheduledDate": "dateTime"
@@ -224,6 +235,10 @@ def getSquadMatchScoresFromHost(matches: list, connection: RateLimitedAPI, host:
224
235
  "coachName"
225
236
  ]
226
237
 
238
+ # check if coaches are blacklisted
239
+ if coaches_blacklisted:
240
+ order = [col for col in order if col not in ["coachId", "coachName"]]
241
+
227
242
  # add scoreNames to order
228
243
  order += scores["name"].to_list()
229
244
 
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: impectPy
3
- Version: 2.5.0
3
+ Version: 2.5.2
4
4
  Summary: A Python package to facilitate interaction with the Impect customer API
5
5
  Home-page: https://github.com/ImpectAPI/impectPy
6
6
  Author: Impect
@@ -11,14 +11,23 @@ License-File: LICENSE.md
11
11
  Requires-Dist: requests>=2.24.0
12
12
  Requires-Dist: pandas>=2.0.0
13
13
  Requires-Dist: numpy<2.0,>=1.24.2
14
+ Dynamic: author
15
+ Dynamic: author-email
16
+ Dynamic: description
17
+ Dynamic: description-content-type
18
+ Dynamic: home-page
19
+ Dynamic: license
20
+ Dynamic: license-file
21
+ Dynamic: requires-dist
22
+ Dynamic: summary
14
23
 
15
24
  # impectPy <picture><source media="(prefers-color-scheme: dark)" srcset="https://github.com/ImpectAPI/logos/blob/main/impectPy_white.svg"><source media="(prefers-color-scheme: light)" srcset="https://github.com/ImpectAPI/logos/blob/main/impectPy_black.svg"><img alt="ImpectPy Logo" src="https://github.com/ImpectAPI/logos/blob/main/impectPy_black.svg" align="right" height="40"></picture>
16
25
 
17
26
  A package provided by: Impect GmbH
18
27
 
19
- Version: v2.5.0
28
+ Version: v2.5.2
20
29
 
21
- **Updated: October 15th 2025**
30
+ **Updated: October 20th 2025**
22
31
 
23
32
  ---
24
33
 
@@ -49,7 +58,7 @@ pip install impectPy
49
58
  You can also install it from [GitHub](https://github.com/) with:
50
59
 
51
60
  ```cmd
52
- pip install git+https://github.com/ImpectAPI/impectPy.git@v2.5.0
61
+ pip install git+https://github.com/ImpectAPI/impectPy.git@v2.5.2
53
62
  ```
54
63
 
55
64
  ## Usage
@@ -17,7 +17,7 @@ setup(
17
17
  "pandas>=2.0.0",
18
18
  "numpy>=1.24.2,<2.0"],
19
19
  # *strongly* suggested for sharing
20
- version="2.5.0",
20
+ version="2.5.2",
21
21
  # The license can be anything you like
22
22
  license="MIT",
23
23
  description="A Python package to facilitate interaction with the Impect customer API",
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes