impectPy 2.5.8__tar.gz → 2.5.10__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 (36) hide show
  1. {impectpy-2.5.8 → impectpy-2.5.10}/PKG-INFO +16 -4
  2. {impectpy-2.5.8 → impectpy-2.5.10}/README.md +15 -3
  3. {impectpy-2.5.8 → impectpy-2.5.10}/impectPy/__init__.py +2 -1
  4. impectpy-2.5.10/impectPy/data.py +54 -0
  5. {impectpy-2.5.8 → impectpy-2.5.10}/impectPy/formations.py +1 -1
  6. {impectpy-2.5.8 → impectpy-2.5.10}/impectPy/helpers.py +4 -2
  7. {impectpy-2.5.8 → impectpy-2.5.10}/impectPy/impect.py +27 -2
  8. {impectpy-2.5.8 → impectpy-2.5.10}/impectPy/iterations.py +8 -0
  9. {impectpy-2.5.8 → impectpy-2.5.10}/impectPy/matches.py +25 -1
  10. {impectpy-2.5.8 → impectpy-2.5.10}/impectPy/player_iteration_averages.py +9 -1
  11. {impectpy-2.5.8 → impectpy-2.5.10}/impectPy/player_iteration_scores.py +9 -1
  12. {impectpy-2.5.8 → impectpy-2.5.10}/impectPy/player_match_scores.py +9 -1
  13. {impectpy-2.5.8 → impectpy-2.5.10}/impectPy/player_matchsums.py +9 -1
  14. {impectpy-2.5.8 → impectpy-2.5.10}/impectPy/player_profile_scores.py +9 -1
  15. {impectpy-2.5.8 → impectpy-2.5.10}/impectPy/squad_coefficients.py +9 -1
  16. {impectpy-2.5.8 → impectpy-2.5.10}/impectPy/squad_iteration_averages.py +9 -1
  17. {impectpy-2.5.8 → impectpy-2.5.10}/impectPy/squad_iteration_scores.py +9 -1
  18. {impectpy-2.5.8 → impectpy-2.5.10}/impectPy/squad_match_scores.py +9 -1
  19. {impectpy-2.5.8 → impectpy-2.5.10}/impectPy/squad_matchsums.py +9 -1
  20. {impectpy-2.5.8 → impectpy-2.5.10}/impectPy/squad_ratings.py +9 -1
  21. {impectpy-2.5.8 → impectpy-2.5.10}/impectPy/starting_positions.py +1 -1
  22. {impectpy-2.5.8 → impectpy-2.5.10}/impectPy/substitutions.py +1 -1
  23. {impectpy-2.5.8 → impectpy-2.5.10}/impectPy.egg-info/PKG-INFO +16 -4
  24. {impectpy-2.5.8 → impectpy-2.5.10}/impectPy.egg-info/SOURCES.txt +1 -0
  25. {impectpy-2.5.8 → impectpy-2.5.10}/setup.py +1 -1
  26. {impectpy-2.5.8 → impectpy-2.5.10}/tests/test_package.py +7 -2
  27. {impectpy-2.5.8 → impectpy-2.5.10}/LICENSE.md +0 -0
  28. {impectpy-2.5.8 → impectpy-2.5.10}/impectPy/access_token.py +0 -0
  29. {impectpy-2.5.8 → impectpy-2.5.10}/impectPy/config.py +0 -0
  30. {impectpy-2.5.8 → impectpy-2.5.10}/impectPy/events.py +0 -0
  31. {impectpy-2.5.8 → impectpy-2.5.10}/impectPy/generate_xml.py +0 -0
  32. {impectpy-2.5.8 → impectpy-2.5.10}/impectPy/set_pieces.py +0 -0
  33. {impectpy-2.5.8 → impectpy-2.5.10}/impectPy.egg-info/dependency_links.txt +0 -0
  34. {impectpy-2.5.8 → impectpy-2.5.10}/impectPy.egg-info/requires.txt +0 -0
  35. {impectpy-2.5.8 → impectpy-2.5.10}/impectPy.egg-info/top_level.txt +0 -0
  36. {impectpy-2.5.8 → impectpy-2.5.10}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: impectPy
3
- Version: 2.5.8
3
+ Version: 2.5.10
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
@@ -25,9 +25,9 @@ Dynamic: summary
25
25
 
26
26
  A package provided by: Impect GmbH
27
27
 
28
- Version: v2.5.8
28
+ Version: v2.5.10
29
29
 
30
- **Updated: March 19th 2026**
30
+ **Updated: April 13th 2026**
31
31
 
32
32
  ---
33
33
 
@@ -58,7 +58,7 @@ pip install impectPy
58
58
  You can also install it from [GitHub](https://github.com/) with:
59
59
 
60
60
  ```cmd
61
- pip install git+https://github.com/ImpectAPI/impectPy.git@v2.5.8
61
+ pip install git+https://github.com/ImpectAPI/impectPy.git@v2.5.10
62
62
  ```
63
63
 
64
64
  ## Usage
@@ -302,6 +302,15 @@ calls made on the client side already. The rate limit is read from the first lim
302
302
  policy sent back by the API, so if this limit increases over time, this package will
303
303
  act accordingly.
304
304
 
305
+ ### Generic API Call
306
+ You can also use this package to make individual API calls querying a specific endpoint
307
+ such as the "squads" endpoint.
308
+
309
+ ```python
310
+ # query any IMPECT customer API endpoint
311
+ data = ip.getData(url=f"https://api.impect.com/v5/customerapi/iterations/{iteration}/squads", token=token)
312
+ ```
313
+
305
314
  ### SportsCodeXML
306
315
 
307
316
  It is also possible to convert a dataframe containing event data into an XML file,
@@ -449,6 +458,9 @@ squadIterationScores = api.getSquadIterationScores(iteration=iteration)
449
458
 
450
459
  # get player profile scores
451
460
  playerProfileScores = api.getPlayerProfileScores(iteration=iteration, positions=positions)
461
+
462
+ # query single API endpoint (e.g. squads for iteration 518)
463
+ data = api.getData(url=f"https://api.impect.com/v5/customerapi/iterations/{iteration}/squads")
452
464
  ```
453
465
 
454
466
  ## Final Notes
@@ -2,9 +2,9 @@
2
2
 
3
3
  A package provided by: Impect GmbH
4
4
 
5
- Version: v2.5.8
5
+ Version: v2.5.10
6
6
 
7
- **Updated: March 19th 2026**
7
+ **Updated: April 13th 2026**
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.8
38
+ pip install git+https://github.com/ImpectAPI/impectPy.git@v2.5.10
39
39
  ```
40
40
 
41
41
  ## Usage
@@ -279,6 +279,15 @@ calls made on the client side already. The rate limit is read from the first lim
279
279
  policy sent back by the API, so if this limit increases over time, this package will
280
280
  act accordingly.
281
281
 
282
+ ### Generic API Call
283
+ You can also use this package to make individual API calls querying a specific endpoint
284
+ such as the "squads" endpoint.
285
+
286
+ ```python
287
+ # query any IMPECT customer API endpoint
288
+ data = ip.getData(url=f"https://api.impect.com/v5/customerapi/iterations/{iteration}/squads", token=token)
289
+ ```
290
+
282
291
  ### SportsCodeXML
283
292
 
284
293
  It is also possible to convert a dataframe containing event data into an XML file,
@@ -426,6 +435,9 @@ squadIterationScores = api.getSquadIterationScores(iteration=iteration)
426
435
 
427
436
  # get player profile scores
428
437
  playerProfileScores = api.getPlayerProfileScores(iteration=iteration, positions=positions)
438
+
439
+ # query single API endpoint (e.g. squads for iteration 518)
440
+ data = api.getData(url=f"https://api.impect.com/v5/customerapi/iterations/{iteration}/squads")
429
441
  ```
430
442
 
431
443
  ## Final Notes
@@ -1,5 +1,5 @@
1
1
  # define version attribute
2
- __version__ = "2.5.8"
2
+ __version__ = "2.5.10"
3
3
 
4
4
  # import modules
5
5
  from .access_token import getAccessToken
@@ -22,5 +22,6 @@ from .squad_coefficients import getSquadCoefficients
22
22
  from .formations import getFormations
23
23
  from .substitutions import getSubstitutions
24
24
  from .starting_positions import getStartingPositions
25
+ from .data import getData
25
26
  from .config import Config as Config
26
27
  from .impect import Impect as Impect
@@ -0,0 +1,54 @@
1
+ # load packages
2
+ import pandas as pd
3
+ from typing import Optional, Dict, Any
4
+ from impectPy.helpers import RateLimitedAPI, ImpectSession
5
+
6
+
7
+ ######
8
+ #
9
+ # This function returns a dataframe from any Impect API endpoint
10
+ #
11
+ ######
12
+
13
+
14
+ def getData(
15
+ url: str, token: str, method: str = "GET", data: Optional[Dict[str, Any]] = None,
16
+ session: Optional[ImpectSession] = None
17
+ ) -> pd.DataFrame:
18
+ """Returns a processed DataFrame from any Impect API endpoint.
19
+
20
+ Args:
21
+ url (str): Full URL of the API endpoint.
22
+ token (str): Bearer token for authentication.
23
+ method (str): HTTP method. Defaults to "GET".
24
+ data (Optional[Dict[str, Any]]): Optional request body. Defaults to None.
25
+ session (Optional[ImpectSession]): The session object to use for the API calls. Defaults to a new ImpectSession.
26
+
27
+ Returns:
28
+ pd.DataFrame: Processed response data.
29
+ """
30
+ # create an instance of RateLimitedAPI
31
+ connection = RateLimitedAPI(session or ImpectSession())
32
+
33
+ # set auth header
34
+ connection.session.headers.update({"Authorization": f"Bearer {token}"})
35
+
36
+ return getDataFromHost(url=url, method=method, connection=connection, data=data)
37
+
38
+
39
+ def getDataFromHost(
40
+ url: str, method: str, connection: RateLimitedAPI, data: Optional[Dict[str, Any]] = None
41
+ ) -> pd.DataFrame:
42
+ """Core implementation: executes a rate-limited API call and returns a processed DataFrame.
43
+
44
+ Args:
45
+ url (str): Full URL of the API endpoint.
46
+ method (str): HTTP method.
47
+ connection (RateLimitedAPI): Authenticated connection object.
48
+ data (Optional[Dict[str, Any]]): Optional request body. Defaults to None.
49
+
50
+ Returns:
51
+ pd.DataFrame: Processed response data.
52
+ """
53
+ response = connection.make_api_request_limited(url=url, method=method, data=data)
54
+ return response.process_response(endpoint=url)
@@ -134,7 +134,7 @@ def getFormationsFromHost(matches: list, connection: RateLimitedAPI, host: str)
134
134
  # merge with matches info
135
135
  formations = formations.merge(
136
136
  matchplan[[
137
- "id", "skillCornerId", "heimSpielId", "wyscoutId", "matchDayIndex",
137
+ "id", "skillCornerId", "heimSpielId", "wyscoutId", "optaId", "statsPerformId", "transfermarktId", "soccerdonnaId", "matchDayIndex",
138
138
  "matchDayName", "scheduledDate", "lastCalculationDate", "iterationId"
139
139
  ]],
140
140
  left_on="id",
@@ -278,7 +278,7 @@ def unnest_mappings_dict(mapping_dict: dict) -> dict:
278
278
 
279
279
  def unnest_mappings_df(df: pd.DataFrame, mapping_col: str) -> pd.DataFrame:
280
280
  # create empty df to store mappings
281
- df_mappings = pd.DataFrame(columns=["wyscoutId", "heimSpielId", "skillCornerId"])
281
+ df_mappings = pd.DataFrame(columns=["wyscoutId", "heimSpielId", "skillCornerId", "optaId", "statsPerformId", "transfermarktId", "soccerdonnaId"])
282
282
 
283
283
  # iterate over entry and unnest idMappings
284
284
  for index, entry in df.iterrows():
@@ -291,7 +291,9 @@ def unnest_mappings_df(df: pd.DataFrame, mapping_col: str) -> pd.DataFrame:
291
291
  provider = "heimSpiel"
292
292
  elif provider == "skill_corner":
293
293
  provider = "skillCorner"
294
- elif provider == "wyscout":
294
+ elif provider == "stats_perform":
295
+ provider = "statsPerform"
296
+ elif provider in ("wyscout", "opta", "transfermarkt", "soccerdonna"):
295
297
  pass
296
298
  else:
297
299
  raise Exception(f"Unknown provider: {provider}")
@@ -1,4 +1,10 @@
1
+ from typing import Optional, Dict, Any
2
+ from xml.etree import ElementTree as ET
3
+
4
+ import pandas as pd
5
+
1
6
  from impectPy.config import Config
7
+
2
8
  from .helpers import RateLimitedAPI
3
9
  from .access_token import getAccessTokenFromUrl
4
10
  from .iterations import getIterationsFromHost
@@ -20,8 +26,7 @@ from .squad_coefficients import getSquadCoefficientsFromHost
20
26
  from .formations import getFormationsFromHost
21
27
  from .substitutions import getSubstitutionsFromHost
22
28
  from .starting_positions import getStartingPositionsFromHost
23
- import pandas as pd
24
- from xml.etree import ElementTree as ET
29
+ from .data import getDataFromHost
25
30
 
26
31
 
27
32
  class Impect:
@@ -130,6 +135,26 @@ class Impect:
130
135
  matches, self.connection, self.__config.HOST
131
136
  )
132
137
 
138
+ def getData(
139
+ self, url: str, method: str = "GET", data: Optional[Dict[str, Any]] = None
140
+ ) -> pd.DataFrame:
141
+ """Returns a processed DataFrame from any Impect API endpoint.
142
+
143
+ Accepts a full URL or a path. If a path is provided (does not start
144
+ with 'http'), the configured host is prepended automatically.
145
+
146
+ Args:
147
+ url (str): Full URL or path of the API endpoint.
148
+ method (str): HTTP method. Defaults to "GET".
149
+ data (Optional[Dict[str, Any]]): Optional request body. Defaults to None.
150
+
151
+ Returns:
152
+ pd.DataFrame: Processed response data.
153
+ """
154
+ if not url.startswith("http"):
155
+ url = f"{self.__config.HOST}{url}"
156
+ return getDataFromHost(url=url, method=method, connection=self.connection, data=data)
157
+
133
158
  @staticmethod
134
159
  def generateXML(
135
160
  events: pd.DataFrame,
@@ -49,6 +49,10 @@ def getIterationsFromHost(connection: RateLimitedAPI, host: str) -> pd.DataFrame
49
49
  df.skillCornerId = df.skillCornerId.apply(lambda x: x[0] if x else None)
50
50
  df.heimSpielId = df.heimSpielId.apply(lambda x: x[0] if x else None)
51
51
  df.wyscoutId = df.wyscoutId.apply(lambda x: x[0] if x else None)
52
+ df.optaId = df.optaId.apply(lambda x: x[0] if x else None)
53
+ df.statsPerformId = df.statsPerformId.apply(lambda x: x[0] if x else None)
54
+ df.transfermarktId = df.transfermarktId.apply(lambda x: x[0] if x else None)
55
+ df.soccerdonnaId = df.soccerdonnaId.apply(lambda x: x[0] if x else None)
52
56
 
53
57
  # get country data
54
58
  countries = connection.make_api_request_limited(
@@ -84,6 +88,10 @@ def getIterationsFromHost(connection: RateLimitedAPI, host: str) -> pd.DataFrame
84
88
  "wyscoutId",
85
89
  "heimSpielId",
86
90
  "skillCornerId",
91
+ "optaId",
92
+ "statsPerformId",
93
+ "transfermarktId",
94
+ "soccerdonnaId",
87
95
  ]
88
96
 
89
97
  # select columns
@@ -69,6 +69,10 @@ def getMatchesFromHost(iteration: int, connection: RateLimitedAPI, host: str) ->
69
69
  "skillCornerId_home": "homeSquadSkillCornerId",
70
70
  "heimSpielId_home": "homeSquadHeimSpielId",
71
71
  "wyscoutId_home": "homeSquadWyscoutId",
72
+ "optaId_home": "homeSquadOptaId",
73
+ "statsPerformId_home": "homeSquadStatsPerformId",
74
+ "transfermarktId_home": "homeSquadTransfermarktId",
75
+ "soccerdonnaId_home": "homeSquadSoccerdonnaId",
72
76
  "countryId": "homeSquadCountryId"
73
77
  })
74
78
  matches = matches.merge(squads,
@@ -81,6 +85,10 @@ def getMatchesFromHost(iteration: int, connection: RateLimitedAPI, host: str) ->
81
85
  "skillCornerId_away": "awaySquadSkillCornerId",
82
86
  "heimSpielId_away": "awaySquadHeimSpielId",
83
87
  "wyscoutId_away": "awaySquadWyscoutId",
88
+ "optaId_away": "awaySquadOptaId",
89
+ "statsPerformId_away": "awaySquadStatsPerformId",
90
+ "transfermarktId_away": "awaySquadTransfermarktId",
91
+ "soccerdonnaId_away": "awaySquadSoccerdonnaId",
84
92
  "countryId": "awaySquadCountryId"
85
93
  })
86
94
 
@@ -107,6 +115,10 @@ def getMatchesFromHost(iteration: int, connection: RateLimitedAPI, host: str) ->
107
115
  "skillCornerId",
108
116
  "heimSpielId",
109
117
  "wyscoutId",
118
+ "optaId",
119
+ "statsPerformId",
120
+ "transfermarktId",
121
+ "soccerdonnaId",
110
122
  "iterationId",
111
123
  "matchDayIndex",
112
124
  "matchDayName",
@@ -118,6 +130,10 @@ def getMatchesFromHost(iteration: int, connection: RateLimitedAPI, host: str) ->
118
130
  "homeSquadSkillCornerId",
119
131
  "homeSquadHeimSpielId",
120
132
  "homeSquadWyscoutId",
133
+ "homeSquadOptaId",
134
+ "homeSquadStatsPerformId",
135
+ "homeSquadTransfermarktId",
136
+ "homeSquadSoccerdonnaId",
121
137
  "awaySquadId",
122
138
  "awaySquadName",
123
139
  "awaySquadType",
@@ -126,6 +142,10 @@ def getMatchesFromHost(iteration: int, connection: RateLimitedAPI, host: str) ->
126
142
  "awaySquadSkillCornerId",
127
143
  "awaySquadHeimSpielId",
128
144
  "awaySquadWyscoutId",
145
+ "awaySquadOptaId",
146
+ "awaySquadStatsPerformId",
147
+ "awaySquadTransfermarktId",
148
+ "awaySquadSoccerdonnaId",
129
149
  "scheduledDate",
130
150
  "lastCalculationDate",
131
151
  "available"
@@ -156,9 +176,13 @@ def clean_df(data: dict) -> pd.DataFrame:
156
176
  # drop idMappings column
157
177
  df = df.drop("idMappings", axis=1)
158
178
 
159
- # keep first entry for skillcorner and heimspiel data
179
+ # keep first entry for skillcorner, heimspiel, wyscout, opta, statsperform, transfermarkt and soccerdonna data
160
180
  df.skillCornerId = df.skillCornerId.apply(lambda x: x[0] if x else None)
161
181
  df.heimSpielId = df.heimSpielId.apply(lambda x: x[0] if x else None)
162
182
  df.wyscoutId = df.wyscoutId.apply(lambda x: x[0] if x else None)
183
+ df.optaId = df.optaId.apply(lambda x: x[0] if x else None)
184
+ df.statsPerformId = df.statsPerformId.apply(lambda x: x[0] if x else None)
185
+ df.transfermarktId = df.transfermarktId.apply(lambda x: x[0] if x else None)
186
+ df.soccerdonnaId = df.soccerdonnaId.apply(lambda x: x[0] if x else None)
163
187
 
164
188
  return df
@@ -198,7 +198,7 @@ def getPlayerIterationAveragesFromHost(
198
198
  suffixes=("", "_squads")
199
199
  ).merge(
200
200
  players[[
201
- "id", "wyscoutId", "heimSpielId", "skillCornerId", "commonname",
201
+ "id", "wyscoutId", "heimSpielId", "skillCornerId", "optaId", "statsPerformId", "transfermarktId", "soccerdonnaId", "commonname",
202
202
  "firstname", "lastname", "birthdate", "birthplace", "countryId", "leg"
203
203
  ]].rename(
204
204
  columns={"commonname": "playerName"}
@@ -225,6 +225,10 @@ def getPlayerIterationAveragesFromHost(
225
225
  averages["wyscoutId"] = averages["wyscoutId"].astype("Int64")
226
226
  averages["heimSpielId"] = averages["heimSpielId"].astype("Int64")
227
227
  averages["skillCornerId"] = averages["skillCornerId"].astype("Int64")
228
+ averages["optaId"] = averages["optaId"].astype("string")
229
+ averages["statsPerformId"] = averages["statsPerformId"].astype("string")
230
+ averages["transfermarktId"] = averages["transfermarktId"].astype("string")
231
+ averages["soccerdonnaId"] = averages["soccerdonnaId"].astype("string")
228
232
 
229
233
  # define column order
230
234
  order = [
@@ -237,6 +241,10 @@ def getPlayerIterationAveragesFromHost(
237
241
  "wyscoutId",
238
242
  "heimSpielId",
239
243
  "skillCornerId",
244
+ "optaId",
245
+ "statsPerformId",
246
+ "transfermarktId",
247
+ "soccerdonnaId",
240
248
  "playerName",
241
249
  "firstname",
242
250
  "lastname",
@@ -271,7 +271,7 @@ def getPlayerIterationScoresFromHost(
271
271
  suffixes=("", "_iterations")
272
272
  ).merge(
273
273
  players[[
274
- "id", "wyscoutId", "heimSpielId", "skillCornerId", "commonname",
274
+ "id", "wyscoutId", "heimSpielId", "skillCornerId", "optaId", "statsPerformId", "transfermarktId", "soccerdonnaId", "commonname",
275
275
  "firstname", "lastname", "birthdate", "birthplace", "countryId", "leg"
276
276
  ]].rename(
277
277
  columns={"commonname": "playerName"}
@@ -302,6 +302,10 @@ def getPlayerIterationScoresFromHost(
302
302
  "wyscoutId",
303
303
  "heimSpielId",
304
304
  "skillCornerId",
305
+ "optaId",
306
+ "statsPerformId",
307
+ "transfermarktId",
308
+ "soccerdonnaId",
305
309
  "playerName",
306
310
  "firstname",
307
311
  "lastname",
@@ -326,6 +330,10 @@ def getPlayerIterationScoresFromHost(
326
330
  averages["wyscoutId"] = averages["wyscoutId"].astype("Int64")
327
331
  averages["heimSpielId"] = averages["heimSpielId"].astype("Int64")
328
332
  averages["skillCornerId"] = averages["skillCornerId"].astype("Int64")
333
+ averages["optaId"] = averages["optaId"].astype("string")
334
+ averages["statsPerformId"] = averages["statsPerformId"].astype("string")
335
+ averages["transfermarktId"] = averages["transfermarktId"].astype("string")
336
+ averages["soccerdonnaId"] = averages["soccerdonnaId"].astype("string")
329
337
 
330
338
  # return result
331
339
  return averages
@@ -378,7 +378,7 @@ def getPlayerMatchScoresFromHost(matches: list, connection: RateLimitedAPI, host
378
378
  suffixes=("", "_iterations")
379
379
  ).merge(
380
380
  players[[
381
- "id", "wyscoutId", "heimSpielId", "skillCornerId", "commonname",
381
+ "id", "wyscoutId", "heimSpielId", "skillCornerId", "optaId", "statsPerformId", "transfermarktId", "soccerdonnaId", "commonname",
382
382
  "firstname", "lastname", "birthdate", "birthplace", "countryId", "leg"
383
383
  ]].rename(
384
384
  columns={"commonname": "playerName"}
@@ -424,6 +424,10 @@ def getPlayerMatchScoresFromHost(matches: list, connection: RateLimitedAPI, host
424
424
  "wyscoutId",
425
425
  "heimSpielId",
426
426
  "skillCornerId",
427
+ "optaId",
428
+ "statsPerformId",
429
+ "transfermarktId",
430
+ "soccerdonnaId",
427
431
  "playerName",
428
432
  "firstname",
429
433
  "lastname",
@@ -453,6 +457,10 @@ def getPlayerMatchScoresFromHost(matches: list, connection: RateLimitedAPI, host
453
457
  player_scores["wyscoutId"] = player_scores["wyscoutId"].astype("Int64")
454
458
  player_scores["heimSpielId"] = player_scores["heimSpielId"].astype("Int64")
455
459
  player_scores["skillCornerId"] = player_scores["skillCornerId"].astype("Int64")
460
+ player_scores["optaId"] = player_scores["optaId"].astype("string")
461
+ player_scores["statsPerformId"] = player_scores["statsPerformId"].astype("string")
462
+ player_scores["transfermarktId"] = player_scores["transfermarktId"].astype("string")
463
+ player_scores["soccerdonnaId"] = player_scores["soccerdonnaId"].astype("string")
456
464
 
457
465
  # return data
458
466
  return player_scores
@@ -272,7 +272,7 @@ def getPlayerMatchsumsFromHost(matches: list, connection: RateLimitedAPI, host:
272
272
  suffixes=("", "_iterations")
273
273
  ).merge(
274
274
  players[[
275
- "id", "wyscoutId", "heimSpielId", "skillCornerId", "commonname",
275
+ "id", "wyscoutId", "heimSpielId", "skillCornerId", "optaId", "statsPerformId", "transfermarktId", "soccerdonnaId", "commonname",
276
276
  "firstname", "lastname", "birthdate", "birthplace", "countryId", "leg"
277
277
  ]].rename(
278
278
  columns={"commonname": "playerName"}
@@ -318,6 +318,10 @@ def getPlayerMatchsumsFromHost(matches: list, connection: RateLimitedAPI, host:
318
318
  "wyscoutId",
319
319
  "heimSpielId",
320
320
  "skillCornerId",
321
+ "optaId",
322
+ "statsPerformId",
323
+ "transfermarktId",
324
+ "soccerdonnaId",
321
325
  "playerName",
322
326
  "firstname",
323
327
  "lastname",
@@ -347,6 +351,10 @@ def getPlayerMatchsumsFromHost(matches: list, connection: RateLimitedAPI, host:
347
351
  matchsums["wyscoutId"] = matchsums["wyscoutId"].astype("Int64")
348
352
  matchsums["heimSpielId"] = matchsums["heimSpielId"].astype("Int64")
349
353
  matchsums["skillCornerId"] = matchsums["skillCornerId"].astype("Int64")
354
+ matchsums["optaId"] = matchsums["optaId"].astype("string")
355
+ matchsums["statsPerformId"] = matchsums["statsPerformId"].astype("string")
356
+ matchsums["transfermarktId"] = matchsums["transfermarktId"].astype("string")
357
+ matchsums["soccerdonnaId"] = matchsums["soccerdonnaId"].astype("string")
350
358
 
351
359
  # return data
352
360
  return matchsums
@@ -211,7 +211,7 @@ def getPlayerProfileScoresFromHost(
211
211
  suffixes=("", "_squads")
212
212
  ).merge(
213
213
  players[[
214
- "id", "wyscoutId", "heimSpielId", "skillCornerId", "commonname",
214
+ "id", "wyscoutId", "heimSpielId", "skillCornerId", "optaId", "statsPerformId", "transfermarktId", "soccerdonnaId", "commonname",
215
215
  "firstname", "lastname", "birthdate", "birthplace", "countryId", "leg"
216
216
  ]].rename(
217
217
  columns={"commonname": "playerName"}
@@ -233,6 +233,10 @@ def getPlayerProfileScoresFromHost(
233
233
  profile_scores["wyscoutId"] = profile_scores["wyscoutId"].astype("Int64")
234
234
  profile_scores["heimSpielId"] = profile_scores["heimSpielId"].astype("Int64")
235
235
  profile_scores["skillCornerId"] = profile_scores["skillCornerId"].astype("Int64")
236
+ profile_scores["optaId"] = profile_scores["optaId"].astype("string")
237
+ profile_scores["statsPerformId"] = profile_scores["statsPerformId"].astype("string")
238
+ profile_scores["transfermarktId"] = profile_scores["transfermarktId"].astype("string")
239
+ profile_scores["soccerdonnaId"] = profile_scores["soccerdonnaId"].astype("string")
236
240
 
237
241
  # define column order
238
242
  order = [
@@ -245,6 +249,10 @@ def getPlayerProfileScoresFromHost(
245
249
  "wyscoutId",
246
250
  "heimSpielId",
247
251
  "skillCornerId",
252
+ "optaId",
253
+ "statsPerformId",
254
+ "transfermarktId",
255
+ "soccerdonnaId",
248
256
  "playerName",
249
257
  "firstname",
250
258
  "lastname",
@@ -87,7 +87,7 @@ def getSquadCoefficientsFromHost(iteration: int, connection: RateLimitedAPI, hos
87
87
 
88
88
  # merge events with squads
89
89
  coefficients = coefficients.merge(
90
- squads[["id", "wyscoutId", "heimSpielId", "skillCornerId", "name"]].rename(
90
+ squads[["id", "wyscoutId", "heimSpielId", "skillCornerId", "optaId", "statsPerformId", "transfermarktId", "soccerdonnaId", "name"]].rename(
91
91
  columns={"id": "squadId", "name": "squadName"}
92
92
  ),
93
93
  left_on="squadId",
@@ -103,6 +103,10 @@ def getSquadCoefficientsFromHost(iteration: int, connection: RateLimitedAPI, hos
103
103
  coefficients["wyscoutId"] = coefficients["wyscoutId"].astype("Int64")
104
104
  coefficients["heimSpielId"] = coefficients["heimSpielId"].astype("Int64")
105
105
  coefficients["skillCornerId"] = coefficients["skillCornerId"].astype("Int64")
106
+ coefficients["optaId"] = coefficients["optaId"].astype("string")
107
+ coefficients["statsPerformId"] = coefficients["statsPerformId"].astype("string")
108
+ coefficients["transfermarktId"] = coefficients["transfermarktId"].astype("string")
109
+ coefficients["soccerdonnaId"] = coefficients["soccerdonnaId"].astype("string")
106
110
 
107
111
  # define desired column order
108
112
  order = [
@@ -120,6 +124,10 @@ def getSquadCoefficientsFromHost(iteration: int, connection: RateLimitedAPI, hos
120
124
  "wyscoutId",
121
125
  "heimSpielId",
122
126
  "skillCornerId",
127
+ "optaId",
128
+ "statsPerformId",
129
+ "transfermarktId",
130
+ "soccerdonnaId",
123
131
  "squadName",
124
132
  "attackCoefficient",
125
133
  "defenseCoefficient",
@@ -110,7 +110,7 @@ def getSquadIterationAveragesFromHost(iteration: int, connection: RateLimitedAPI
110
110
  how="left",
111
111
  suffixes=("", "_iterations")
112
112
  ).merge(
113
- squads[["id", "wyscoutId", "heimSpielId", "skillCornerId", "name"]].rename(
113
+ squads[["id", "wyscoutId", "heimSpielId", "skillCornerId", "optaId", "statsPerformId", "transfermarktId", "soccerdonnaId", "name"]].rename(
114
114
  columns={"id": "squadId", "name": "squadName"}
115
115
  ),
116
116
  left_on="squadId",
@@ -129,6 +129,10 @@ def getSquadIterationAveragesFromHost(iteration: int, connection: RateLimitedAPI
129
129
  averages["wyscoutId"] = averages["wyscoutId"].astype("Int64")
130
130
  averages["heimSpielId"] = averages["heimSpielId"].astype("Int64")
131
131
  averages["skillCornerId"] = averages["skillCornerId"].astype("Int64")
132
+ averages["optaId"] = averages["optaId"].astype("string")
133
+ averages["statsPerformId"] = averages["statsPerformId"].astype("string")
134
+ averages["transfermarktId"] = averages["transfermarktId"].astype("string")
135
+ averages["soccerdonnaId"] = averages["soccerdonnaId"].astype("string")
132
136
 
133
137
  # define column order
134
138
  order = [
@@ -139,6 +143,10 @@ def getSquadIterationAveragesFromHost(iteration: int, connection: RateLimitedAPI
139
143
  "wyscoutId",
140
144
  "heimSpielId",
141
145
  "skillCornerId",
146
+ "optaId",
147
+ "statsPerformId",
148
+ "transfermarktId",
149
+ "soccerdonnaId",
142
150
  "squadName",
143
151
  "matches"
144
152
  ]
@@ -110,7 +110,7 @@ def getSquadIterationScoresFromHost(iteration: int, connection: RateLimitedAPI,
110
110
  how="left",
111
111
  suffixes=("", "_iterations")
112
112
  ).merge(
113
- squads[["id", "wyscoutId", "heimSpielId", "skillCornerId", "name"]].rename(
113
+ squads[["id", "wyscoutId", "heimSpielId", "skillCornerId", "optaId", "statsPerformId", "transfermarktId", "soccerdonnaId", "name"]].rename(
114
114
  columns={"id": "squadId", "name": "squadName"}
115
115
  ),
116
116
  left_on="squadId",
@@ -129,6 +129,10 @@ def getSquadIterationScoresFromHost(iteration: int, connection: RateLimitedAPI,
129
129
  averages["wyscoutId"] = averages["wyscoutId"].astype("Int64")
130
130
  averages["heimSpielId"] = averages["heimSpielId"].astype("Int64")
131
131
  averages["skillCornerId"] = averages["skillCornerId"].astype("Int64")
132
+ averages["optaId"] = averages["optaId"].astype("string")
133
+ averages["statsPerformId"] = averages["statsPerformId"].astype("string")
134
+ averages["transfermarktId"] = averages["transfermarktId"].astype("string")
135
+ averages["soccerdonnaId"] = averages["soccerdonnaId"].astype("string")
132
136
 
133
137
  # define column order
134
138
  order = [
@@ -139,6 +143,10 @@ def getSquadIterationScoresFromHost(iteration: int, connection: RateLimitedAPI,
139
143
  "wyscoutId",
140
144
  "heimSpielId",
141
145
  "skillCornerId",
146
+ "optaId",
147
+ "statsPerformId",
148
+ "transfermarktId",
149
+ "soccerdonnaId",
142
150
  "squadName",
143
151
  "matches"
144
152
  ]
@@ -221,7 +221,7 @@ def getSquadMatchScoresFromHost(matches: list, connection: RateLimitedAPI, host:
221
221
  how="left",
222
222
  suffixes=("", "_iterations")
223
223
  ).merge(
224
- squads[["id", "wyscoutId", "heimSpielId", "skillCornerId", "name"]].rename(
224
+ squads[["id", "wyscoutId", "heimSpielId", "skillCornerId", "optaId", "statsPerformId", "transfermarktId", "soccerdonnaId", "name"]].rename(
225
225
  columns={"id": "squadId", "name": "squadName"}
226
226
  ),
227
227
  left_on="squadId",
@@ -259,6 +259,10 @@ def getSquadMatchScoresFromHost(matches: list, connection: RateLimitedAPI, host:
259
259
  "wyscoutId",
260
260
  "heimSpielId",
261
261
  "skillCornerId",
262
+ "optaId",
263
+ "statsPerformId",
264
+ "transfermarktId",
265
+ "soccerdonnaId",
262
266
  "squadName",
263
267
  "coachId",
264
268
  "coachName"
@@ -283,6 +287,10 @@ def getSquadMatchScoresFromHost(matches: list, connection: RateLimitedAPI, host:
283
287
  squad_scores["wyscoutId"] = squad_scores["wyscoutId"].astype("Int64")
284
288
  squad_scores["heimSpielId"] = squad_scores["heimSpielId"].astype("Int64")
285
289
  squad_scores["skillCornerId"] = squad_scores["skillCornerId"].astype("Int64")
290
+ squad_scores["optaId"] = squad_scores["optaId"].astype("string")
291
+ squad_scores["statsPerformId"] = squad_scores["statsPerformId"].astype("string")
292
+ squad_scores["transfermarktId"] = squad_scores["transfermarktId"].astype("string")
293
+ squad_scores["soccerdonnaId"] = squad_scores["soccerdonnaId"].astype("string")
286
294
 
287
295
  # return data
288
296
  return squad_scores
@@ -221,7 +221,7 @@ def getSquadMatchsumsFromHost(matches: list, connection: RateLimitedAPI, host: s
221
221
  how="left",
222
222
  suffixes=("", "_iterations")
223
223
  ).merge(
224
- squads[["id", "wyscoutId", "heimSpielId", "skillCornerId", "name"]].rename(
224
+ squads[["id", "wyscoutId", "heimSpielId", "skillCornerId", "optaId", "statsPerformId", "transfermarktId", "soccerdonnaId", "name"]].rename(
225
225
  columns={"id": "squadId", "name": "squadName"}
226
226
  ),
227
227
  left_on="squadId",
@@ -259,6 +259,10 @@ def getSquadMatchsumsFromHost(matches: list, connection: RateLimitedAPI, host: s
259
259
  "wyscoutId",
260
260
  "heimSpielId",
261
261
  "skillCornerId",
262
+ "optaId",
263
+ "statsPerformId",
264
+ "transfermarktId",
265
+ "soccerdonnaId",
262
266
  "squadName",
263
267
  "coachId",
264
268
  "coachName"
@@ -292,6 +296,10 @@ def getSquadMatchsumsFromHost(matches: list, connection: RateLimitedAPI, host: s
292
296
  matchsums["wyscoutId"] = matchsums["wyscoutId"].astype("Int64")
293
297
  matchsums["heimSpielId"] = matchsums["heimSpielId"].astype("Int64")
294
298
  matchsums["skillCornerId"] = matchsums["skillCornerId"].astype("Int64")
299
+ matchsums["optaId"] = matchsums["optaId"].astype("string")
300
+ matchsums["statsPerformId"] = matchsums["statsPerformId"].astype("string")
301
+ matchsums["transfermarktId"] = matchsums["transfermarktId"].astype("string")
302
+ matchsums["soccerdonnaId"] = matchsums["soccerdonnaId"].astype("string")
295
303
 
296
304
  # return data
297
305
  return matchsums
@@ -85,7 +85,7 @@ def getSquadRatingsFromHost(iteration: int, connection: RateLimitedAPI, host: st
85
85
 
86
86
  # merge events with squads
87
87
  ratings = ratings.merge(
88
- squads[["id", "wyscoutId", "heimSpielId", "skillCornerId", "name"]].rename(
88
+ squads[["id", "wyscoutId", "heimSpielId", "skillCornerId", "optaId", "statsPerformId", "transfermarktId", "soccerdonnaId", "name"]].rename(
89
89
  columns={"id": "squadId", "name": "squadName"}
90
90
  ),
91
91
  left_on="squadId",
@@ -101,6 +101,10 @@ def getSquadRatingsFromHost(iteration: int, connection: RateLimitedAPI, host: st
101
101
  ratings["wyscoutId"] = ratings["wyscoutId"].astype("Int64")
102
102
  ratings["heimSpielId"] = ratings["heimSpielId"].astype("Int64")
103
103
  ratings["skillCornerId"] = ratings["skillCornerId"].astype("Int64")
104
+ ratings["optaId"] = ratings["optaId"].astype("string")
105
+ ratings["statsPerformId"] = ratings["statsPerformId"].astype("string")
106
+ ratings["transfermarktId"] = ratings["transfermarktId"].astype("string")
107
+ ratings["soccerdonnaId"] = ratings["soccerdonnaId"].astype("string")
104
108
 
105
109
  # define desired column order
106
110
  order = [
@@ -115,6 +119,10 @@ def getSquadRatingsFromHost(iteration: int, connection: RateLimitedAPI, host: st
115
119
  "wyscoutId",
116
120
  "heimSpielId",
117
121
  "skillCornerId",
122
+ "optaId",
123
+ "statsPerformId",
124
+ "transfermarktId",
125
+ "soccerdonnaId",
118
126
  "squadName",
119
127
  "value"
120
128
  ]
@@ -179,7 +179,7 @@ def getStartingPositionsFromHost(matches: list, connection: RateLimitedAPI, host
179
179
  # merge with matches info
180
180
  starting_positions = starting_positions.merge(
181
181
  matchplan[[
182
- "id", "skillCornerId", "heimSpielId", "wyscoutId", "matchDayIndex",
182
+ "id", "skillCornerId", "heimSpielId", "wyscoutId", "optaId", "statsPerformId", "transfermarktId", "soccerdonnaId", "matchDayIndex",
183
183
  "matchDayName", "scheduledDate", "lastCalculationDate", "iterationId"
184
184
  ]],
185
185
  left_on="id",
@@ -194,7 +194,7 @@ def getSubstitutionsFromHost(matches: list, connection: RateLimitedAPI, host: st
194
194
  # merge with matches info
195
195
  substitutions = substitutions.merge(
196
196
  matchplan[[
197
- "id", "skillCornerId", "heimSpielId", "wyscoutId", "matchDayIndex",
197
+ "id", "skillCornerId", "heimSpielId", "wyscoutId", "optaId", "statsPerformId", "transfermarktId", "soccerdonnaId", "matchDayIndex",
198
198
  "matchDayName", "scheduledDate", "lastCalculationDate", "iterationId"
199
199
  ]],
200
200
  left_on="id",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: impectPy
3
- Version: 2.5.8
3
+ Version: 2.5.10
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
@@ -25,9 +25,9 @@ Dynamic: summary
25
25
 
26
26
  A package provided by: Impect GmbH
27
27
 
28
- Version: v2.5.8
28
+ Version: v2.5.10
29
29
 
30
- **Updated: March 19th 2026**
30
+ **Updated: April 13th 2026**
31
31
 
32
32
  ---
33
33
 
@@ -58,7 +58,7 @@ pip install impectPy
58
58
  You can also install it from [GitHub](https://github.com/) with:
59
59
 
60
60
  ```cmd
61
- pip install git+https://github.com/ImpectAPI/impectPy.git@v2.5.8
61
+ pip install git+https://github.com/ImpectAPI/impectPy.git@v2.5.10
62
62
  ```
63
63
 
64
64
  ## Usage
@@ -302,6 +302,15 @@ calls made on the client side already. The rate limit is read from the first lim
302
302
  policy sent back by the API, so if this limit increases over time, this package will
303
303
  act accordingly.
304
304
 
305
+ ### Generic API Call
306
+ You can also use this package to make individual API calls querying a specific endpoint
307
+ such as the "squads" endpoint.
308
+
309
+ ```python
310
+ # query any IMPECT customer API endpoint
311
+ data = ip.getData(url=f"https://api.impect.com/v5/customerapi/iterations/{iteration}/squads", token=token)
312
+ ```
313
+
305
314
  ### SportsCodeXML
306
315
 
307
316
  It is also possible to convert a dataframe containing event data into an XML file,
@@ -449,6 +458,9 @@ squadIterationScores = api.getSquadIterationScores(iteration=iteration)
449
458
 
450
459
  # get player profile scores
451
460
  playerProfileScores = api.getPlayerProfileScores(iteration=iteration, positions=positions)
461
+
462
+ # query single API endpoint (e.g. squads for iteration 518)
463
+ data = api.getData(url=f"https://api.impect.com/v5/customerapi/iterations/{iteration}/squads")
452
464
  ```
453
465
 
454
466
  ## Final Notes
@@ -4,6 +4,7 @@ setup.py
4
4
  impectPy/__init__.py
5
5
  impectPy/access_token.py
6
6
  impectPy/config.py
7
+ impectPy/data.py
7
8
  impectPy/events.py
8
9
  impectPy/formations.py
9
10
  impectPy/generate_xml.py
@@ -17,7 +17,7 @@ setup(
17
17
  "pandas>=2.2.0",
18
18
  "numpy>=1.24.2"],
19
19
  # *strongly* suggested for sharing
20
- version="2.5.8",
20
+ version="2.5.10",
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",
@@ -10,7 +10,7 @@ from tqdm import tqdm
10
10
  from dotenv import load_dotenv
11
11
  import pandas as pd
12
12
 
13
- execute_functions = False
13
+ execute_functions = True
14
14
 
15
15
  # branch comparison configuration
16
16
  BRANCH_A_NAME = "main"
@@ -110,7 +110,7 @@ if execute_functions:
110
110
  api = impectPy.Impect(config=config)
111
111
  api.login(username, password)
112
112
 
113
- with tqdm(total=20, desc=f"{branch}: Executing functions...", unit="chunk") as pbar:
113
+ with tqdm(total=21, desc=f"{branch}: Executing functions...", unit="chunk") as pbar:
114
114
 
115
115
  # get iterations
116
116
  iterations = api.getIterations()
@@ -204,6 +204,11 @@ if execute_functions:
204
204
  playerProfileScores.to_csv(f"files/{branch}/playerProfileScores.csv")
205
205
  pbar.update()
206
206
 
207
+ # # get data using generic getData() method
208
+ # pbar.set_description("Get data using generic getData() method...")
209
+ # data = api.getData(f"https://api.impect.com/v5/customerapi/iterations/{iteration}/players")
210
+ # pbar.update()
211
+
207
212
  print("\nRunning auto-diff between source and test outputs...\n")
208
213
 
209
214
  base_path = Path(__file__).parent / "files"
File without changes
File without changes
File without changes
File without changes