Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .bumpversion.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[tool.bumpversion]
current_version = "0.13.3"
current_version = "0.14.0"

parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)(?:-(?P<rc_l>rc)(?P<rc>0|[1-9]\\d*))?"

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -167,3 +167,4 @@ cython_debug/
model_generator.py
scratch*.py
docs/reference/
.vscode
7 changes: 3 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "otf-api"
version = "0.13.3"
version = "0.14.0"
description = "Python OrangeTheory Fitness API Client"
authors = [{ name = "Jessica Smith", email = "j.smith.git1@gmail.com" }]
requires-python = ">=3.11"
Expand Down Expand Up @@ -39,7 +39,6 @@ Documentation = "https://otf-api.readthedocs.io/en/stable/"
dev = [
"build==1.2.1",
"bump-my-version>=0.23.0,<0.24",
"mypy==1.10.0",
"mypy-boto3-cognito-identity>=1.38.0",
"mypy-boto3-cognito-idp>=1.35.93,<2",
"pre-commit==3.7.1",
Expand All @@ -51,7 +50,7 @@ dev = [
docs = [
"autodoc-pydantic>=2.2.0",
"furo>=2024.8.6",
"sphinx==8.3.0",
"sphinx>=8.3.0",
"sphinx-autobuild==2024.10.3",
"sphinx-autodoc-typehints==3.2.0",
"sphinx-autodoc2==0.5.0",
Expand All @@ -72,5 +71,5 @@ default-groups = ["dev"]
pythonpath = ["src"]

[build-system]
requires = ["setuptools >= 61.0"]
requires = ["setuptools >= 80.0"]
build-backend = "setuptools.build_meta"
2 changes: 1 addition & 1 deletion source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
project = "OrangeTheory API"
copyright = "2025, Jessica Smith"
author = "Jessica Smith"
release = "0.13.3"
release = "0.14.0"

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
Expand Down
2 changes: 1 addition & 1 deletion src/otf_api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def _setup_logging() -> None:

_setup_logging()

__version__ = "0.13.3"
__version__ = "0.14.0"


__all__ = ["Otf", "OtfUser", "models"]
15 changes: 15 additions & 0 deletions src/otf_api/api/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,21 @@ def __init__(self, user: OtfUser | None = None):
)
atexit.register(self.session.close)

def __getstate__(self):
"""Get the state of the OtfClient instance for serialization."""
state = self.__dict__.copy()
# Remove circular references
state.pop("session", None)
return state

def __setstate__(self, state): # noqa
"""Set the state of the OtfClient instance from serialized data."""
self.__dict__.update(state)
self.session = httpx.Client(
headers=HEADERS, auth=self.user.httpx_auth, timeout=httpx.Timeout(20.0, connect=60.0)
)
atexit.register(self.session.close)

def _build_request(
self,
method: str,
Expand Down
2 changes: 1 addition & 1 deletion src/otf_api/api/members/member_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def __init__(self, client: OtfClient):
self.client = client
self.member_uuid = client.member_uuid

@CACHE.memoize(expire=600, tag="member_detail", ignore=(0,))
@CACHE.memoize(expire=600, tag="member_detail")
def get_member_detail(self) -> dict:
"""Retrieve raw member details."""
return self.client.default_request(
Expand Down
2 changes: 1 addition & 1 deletion src/otf_api/api/studios/studio_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def __init__(self, client: OtfClient):
self.client = client
self.member_uuid = client.member_uuid

@CACHE.memoize(expire=600, tag="studio_detail", ignore=(0,))
@CACHE.memoize(expire=600, tag="studio_detail")
def get_studio_detail(self, studio_uuid: str) -> dict:
"""Retrieve raw studio details."""
return self.client.default_request("GET", f"/mobile/v1/studios/{studio_uuid}")["data"]
Expand Down
4 changes: 2 additions & 2 deletions src/otf_api/api/workouts/workout_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def get_performance_summaries(self, limit: int | None = None) -> dict:
params = {"limit": limit} if limit else {}
return self.performance_summary_request("GET", "/v1/performance-summaries", params=params)

@CACHE.memoize(expire=600, tag="performance_summary", ignore=(0,))
@CACHE.memoize(expire=600, tag="performance_summary")
def get_performance_summary(self, performance_summary_id: str) -> dict:
"""Retrieve raw performance summary data."""
return self.performance_summary_request("GET", f"/v1/performance-summaries/{performance_summary_id}")
Expand All @@ -54,7 +54,7 @@ def get_hr_history_raw(self) -> dict:
"history"
]

@CACHE.memoize(expire=600, tag="telemetry", ignore=(0,))
@CACHE.memoize(expire=600, tag="telemetry")
def get_telemetry(self, performance_summary_id: str, max_data_points: int = 150) -> dict:
"""Retrieve raw telemetry data."""
return self.telemetry_request(
Expand Down
14 changes: 14 additions & 0 deletions src/otf_api/auth/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,20 @@ def _set_tokens(self, tokens: "InitiateAuthResponseTypeDef") -> None:
self.device_group_key = device_metadata.get("DeviceGroupKey", self.device_group_key)
CACHE.write_device_data_to_cache(self.device_metadata)

def __getstate__(self):
"""Get the state of the object for pickling."""
state = self.__dict__.copy()
del state["idp_client"]
del state["id_client"]
return state

def __setstate__(self, state): # noqa
"""Set the state of the object from a pickled state."""
self.__dict__.update(state)
self.idp_client = Session().client("cognito-idp", config=BOTO_CONFIG, region_name=REGION) # type: ignore

self.id_client = Session().client("cognito-identity", config=BOTO_CONFIG, region_name=REGION) # type: ignore


class HttpxCognitoAuth(httpx.Auth):
http_header: str = "Authorization"
Expand Down
Loading