otf-api 0.13.2__tar.gz → 0.14.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.
- {otf_api-0.13.2/src/otf_api.egg-info → otf_api-0.14.0}/PKG-INFO +1 -1
- {otf_api-0.13.2 → otf_api-0.14.0}/pyproject.toml +3 -4
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/__init__.py +1 -1
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/api/client.py +15 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/api/members/member_client.py +1 -1
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/api/studios/studio_client.py +1 -1
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/api/workouts/workout_api.py +3 -2
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/api/workouts/workout_client.py +2 -2
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/auth/auth.py +14 -0
- {otf_api-0.13.2 → otf_api-0.14.0/src/otf_api.egg-info}/PKG-INFO +1 -1
- {otf_api-0.13.2 → otf_api-0.14.0}/LICENSE +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/README.md +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/setup.cfg +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/api/__init__.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/api/_compat.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/api/api.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/api/bookings/__init__.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/api/bookings/booking_api.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/api/bookings/booking_client.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/api/members/__init__.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/api/members/member_api.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/api/studios/__init__.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/api/studios/studio_api.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/api/utils.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/api/workouts/__init__.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/auth/__init__.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/auth/user.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/auth/utils.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/cache.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/exceptions.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/models/__init__.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/models/base.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/models/bookings/__init__.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/models/bookings/bookings.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/models/bookings/bookings_v2.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/models/bookings/classes.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/models/bookings/enums.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/models/bookings/filters.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/models/bookings/ratings.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/models/members/__init__.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/models/members/member_detail.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/models/members/member_membership.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/models/members/member_purchases.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/models/members/notifications.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/models/mixins.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/models/studios/__init__.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/models/studios/enums.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/models/studios/studio_detail.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/models/studios/studio_services.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/models/workouts/__init__.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/models/workouts/body_composition_list.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/models/workouts/challenge_tracker_content.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/models/workouts/challenge_tracker_detail.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/models/workouts/enums.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/models/workouts/lifetime_stats.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/models/workouts/out_of_studio_workout_history.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/models/workouts/performance_summary.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/models/workouts/telemetry.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/models/workouts/workout.py +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/py.typed +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api.egg-info/SOURCES.txt +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api.egg-info/dependency_links.txt +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api.egg-info/requires.txt +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api.egg-info/top_level.txt +0 -0
- {otf_api-0.13.2 → otf_api-0.14.0}/tests/test_filters.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
[project]
|
2
2
|
name = "otf-api"
|
3
|
-
version = "0.
|
3
|
+
version = "0.14.0"
|
4
4
|
description = "Python OrangeTheory Fitness API Client"
|
5
5
|
authors = [{ name = "Jessica Smith", email = "j.smith.git1@gmail.com" }]
|
6
6
|
requires-python = ">=3.11"
|
@@ -39,7 +39,6 @@ Documentation = "https://otf-api.readthedocs.io/en/stable/"
|
|
39
39
|
dev = [
|
40
40
|
"build==1.2.1",
|
41
41
|
"bump-my-version>=0.23.0,<0.24",
|
42
|
-
"mypy==1.10.0",
|
43
42
|
"mypy-boto3-cognito-identity>=1.38.0",
|
44
43
|
"mypy-boto3-cognito-idp>=1.35.93,<2",
|
45
44
|
"pre-commit==3.7.1",
|
@@ -51,7 +50,7 @@ dev = [
|
|
51
50
|
docs = [
|
52
51
|
"autodoc-pydantic>=2.2.0",
|
53
52
|
"furo>=2024.8.6",
|
54
|
-
"sphinx
|
53
|
+
"sphinx>=8.3.0",
|
55
54
|
"sphinx-autobuild==2024.10.3",
|
56
55
|
"sphinx-autodoc-typehints==3.2.0",
|
57
56
|
"sphinx-autodoc2==0.5.0",
|
@@ -72,5 +71,5 @@ default-groups = ["dev"]
|
|
72
71
|
pythonpath = ["src"]
|
73
72
|
|
74
73
|
[build-system]
|
75
|
-
requires = ["setuptools >=
|
74
|
+
requires = ["setuptools >= 80.0"]
|
76
75
|
build-backend = "setuptools.build_meta"
|
@@ -49,6 +49,21 @@ class OtfClient:
|
|
49
49
|
)
|
50
50
|
atexit.register(self.session.close)
|
51
51
|
|
52
|
+
def __getstate__(self):
|
53
|
+
"""Get the state of the OtfClient instance for serialization."""
|
54
|
+
state = self.__dict__.copy()
|
55
|
+
# Remove circular references
|
56
|
+
state.pop("session", None)
|
57
|
+
return state
|
58
|
+
|
59
|
+
def __setstate__(self, state): # noqa
|
60
|
+
"""Set the state of the OtfClient instance from serialized data."""
|
61
|
+
self.__dict__.update(state)
|
62
|
+
self.session = httpx.Client(
|
63
|
+
headers=HEADERS, auth=self.user.httpx_auth, timeout=httpx.Timeout(20.0, connect=60.0)
|
64
|
+
)
|
65
|
+
atexit.register(self.session.close)
|
66
|
+
|
52
67
|
def _build_request(
|
53
68
|
self,
|
54
69
|
method: str,
|
@@ -14,7 +14,7 @@ class MemberClient:
|
|
14
14
|
self.client = client
|
15
15
|
self.member_uuid = client.member_uuid
|
16
16
|
|
17
|
-
@CACHE.memoize(expire=600, tag="member_detail"
|
17
|
+
@CACHE.memoize(expire=600, tag="member_detail")
|
18
18
|
def get_member_detail(self) -> dict:
|
19
19
|
"""Retrieve raw member details."""
|
20
20
|
return self.client.default_request(
|
@@ -15,7 +15,7 @@ class StudioClient:
|
|
15
15
|
self.client = client
|
16
16
|
self.member_uuid = client.member_uuid
|
17
17
|
|
18
|
-
@CACHE.memoize(expire=600, tag="studio_detail"
|
18
|
+
@CACHE.memoize(expire=600, tag="studio_detail")
|
19
19
|
def get_studio_detail(self, studio_uuid: str) -> dict:
|
20
20
|
"""Retrieve raw studio details."""
|
21
21
|
return self.client.default_request("GET", f"/mobile/v1/studios/{studio_uuid}")["data"]
|
@@ -242,13 +242,14 @@ class WorkoutApi:
|
|
242
242
|
return workout
|
243
243
|
|
244
244
|
def get_workouts(
|
245
|
-
self, start_date: date | str | None = None, end_date: date | str | None = None
|
245
|
+
self, start_date: date | str | None = None, end_date: date | str | None = None, max_data_points: int = 150
|
246
246
|
) -> list[models.Workout]:
|
247
247
|
"""Get the member's workouts, using the new bookings endpoint and the performance summary endpoint.
|
248
248
|
|
249
249
|
Args:
|
250
250
|
start_date (date | str | None): The start date for the workouts. If None, defaults to 30 days ago.
|
251
251
|
end_date (date | str | None): The end date for the workouts. If None, defaults to today.
|
252
|
+
max_data_points (int): The maximum number of data points to return for the telemetry. Default is 150.
|
252
253
|
|
253
254
|
Returns:
|
254
255
|
list[Workout]: The member's workouts.
|
@@ -265,7 +266,7 @@ class WorkoutApi:
|
|
265
266
|
bookings_dict = {b.workout.id: b for b in bookings if b.workout}
|
266
267
|
|
267
268
|
perf_summaries_dict = self.client.get_perf_summaries_threaded(list(bookings_dict.keys()))
|
268
|
-
telemetry_dict = self.client.get_telemetry_threaded(list(perf_summaries_dict.keys()))
|
269
|
+
telemetry_dict = self.client.get_telemetry_threaded(list(perf_summaries_dict.keys()), max_data_points)
|
269
270
|
perf_summary_to_class_uuid_map = self.client.get_perf_summary_to_class_uuid_mapping()
|
270
271
|
|
271
272
|
workouts: list[models.Workout] = []
|
@@ -43,7 +43,7 @@ class WorkoutClient:
|
|
43
43
|
params = {"limit": limit} if limit else {}
|
44
44
|
return self.performance_summary_request("GET", "/v1/performance-summaries", params=params)
|
45
45
|
|
46
|
-
@CACHE.memoize(expire=600, tag="performance_summary"
|
46
|
+
@CACHE.memoize(expire=600, tag="performance_summary")
|
47
47
|
def get_performance_summary(self, performance_summary_id: str) -> dict:
|
48
48
|
"""Retrieve raw performance summary data."""
|
49
49
|
return self.performance_summary_request("GET", f"/v1/performance-summaries/{performance_summary_id}")
|
@@ -54,7 +54,7 @@ class WorkoutClient:
|
|
54
54
|
"history"
|
55
55
|
]
|
56
56
|
|
57
|
-
@CACHE.memoize(expire=600, tag="telemetry"
|
57
|
+
@CACHE.memoize(expire=600, tag="telemetry")
|
58
58
|
def get_telemetry(self, performance_summary_id: str, max_data_points: int = 150) -> dict:
|
59
59
|
"""Retrieve raw telemetry data."""
|
60
60
|
return self.telemetry_request(
|
@@ -340,6 +340,20 @@ class OtfCognito(Cognito):
|
|
340
340
|
self.device_group_key = device_metadata.get("DeviceGroupKey", self.device_group_key)
|
341
341
|
CACHE.write_device_data_to_cache(self.device_metadata)
|
342
342
|
|
343
|
+
def __getstate__(self):
|
344
|
+
"""Get the state of the object for pickling."""
|
345
|
+
state = self.__dict__.copy()
|
346
|
+
del state["idp_client"]
|
347
|
+
del state["id_client"]
|
348
|
+
return state
|
349
|
+
|
350
|
+
def __setstate__(self, state): # noqa
|
351
|
+
"""Set the state of the object from a pickled state."""
|
352
|
+
self.__dict__.update(state)
|
353
|
+
self.idp_client = Session().client("cognito-idp", config=BOTO_CONFIG, region_name=REGION) # type: ignore
|
354
|
+
|
355
|
+
self.id_client = Session().client("cognito-identity", config=BOTO_CONFIG, region_name=REGION) # type: ignore
|
356
|
+
|
343
357
|
|
344
358
|
class HttpxCognitoAuth(httpx.Auth):
|
345
359
|
http_header: str = "Authorization"
|
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
|
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
|
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
|
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
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{otf_api-0.13.2 → otf_api-0.14.0}/src/otf_api/models/workouts/out_of_studio_workout_history.py
RENAMED
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
|