otf-api 0.6.0__tar.gz → 0.6.1__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. {otf_api-0.6.0 → otf_api-0.6.1}/PKG-INFO +2 -3
  2. {otf_api-0.6.0 → otf_api-0.6.1}/pyproject.toml +5 -5
  3. {otf_api-0.6.0 → otf_api-0.6.1}/src/otf_api/__init__.py +1 -1
  4. otf_api-0.6.1/src/otf_api/models/base.py +22 -0
  5. {otf_api-0.6.0 → otf_api-0.6.1}/src/otf_api/models/responses/member_detail.py +1 -1
  6. {otf_api-0.6.0 → otf_api-0.6.1}/src/otf_api/models/responses/performance_summary_list.py +1 -0
  7. {otf_api-0.6.0 → otf_api-0.6.1}/src/otf_api/models/responses/telemetry.py +9 -0
  8. otf_api-0.6.0/src/otf_api/models/base.py +0 -149
  9. {otf_api-0.6.0 → otf_api-0.6.1}/AUTHORS.md +0 -0
  10. {otf_api-0.6.0 → otf_api-0.6.1}/LICENSE +0 -0
  11. {otf_api-0.6.0 → otf_api-0.6.1}/README.md +0 -0
  12. {otf_api-0.6.0 → otf_api-0.6.1}/src/otf_api/api.py +0 -0
  13. {otf_api-0.6.0 → otf_api-0.6.1}/src/otf_api/auth.py +0 -0
  14. {otf_api-0.6.0 → otf_api-0.6.1}/src/otf_api/models/__init__.py +0 -0
  15. {otf_api-0.6.0 → otf_api-0.6.1}/src/otf_api/models/responses/__init__.py +0 -0
  16. {otf_api-0.6.0 → otf_api-0.6.1}/src/otf_api/models/responses/body_composition_list.py +0 -0
  17. {otf_api-0.6.0 → otf_api-0.6.1}/src/otf_api/models/responses/book_class.py +0 -0
  18. {otf_api-0.6.0 → otf_api-0.6.1}/src/otf_api/models/responses/bookings.py +0 -0
  19. {otf_api-0.6.0 → otf_api-0.6.1}/src/otf_api/models/responses/cancel_booking.py +0 -0
  20. {otf_api-0.6.0 → otf_api-0.6.1}/src/otf_api/models/responses/challenge_tracker_content.py +0 -0
  21. {otf_api-0.6.0 → otf_api-0.6.1}/src/otf_api/models/responses/challenge_tracker_detail.py +0 -0
  22. {otf_api-0.6.0 → otf_api-0.6.1}/src/otf_api/models/responses/classes.py +0 -0
  23. {otf_api-0.6.0 → otf_api-0.6.1}/src/otf_api/models/responses/enums.py +0 -0
  24. {otf_api-0.6.0 → otf_api-0.6.1}/src/otf_api/models/responses/favorite_studios.py +0 -0
  25. {otf_api-0.6.0 → otf_api-0.6.1}/src/otf_api/models/responses/latest_agreement.py +0 -0
  26. {otf_api-0.6.0 → otf_api-0.6.1}/src/otf_api/models/responses/lifetime_stats.py +0 -0
  27. {otf_api-0.6.0 → otf_api-0.6.1}/src/otf_api/models/responses/member_membership.py +0 -0
  28. {otf_api-0.6.0 → otf_api-0.6.1}/src/otf_api/models/responses/member_purchases.py +0 -0
  29. {otf_api-0.6.0 → otf_api-0.6.1}/src/otf_api/models/responses/out_of_studio_workout_history.py +0 -0
  30. {otf_api-0.6.0 → otf_api-0.6.1}/src/otf_api/models/responses/performance_summary_detail.py +0 -0
  31. {otf_api-0.6.0 → otf_api-0.6.1}/src/otf_api/models/responses/studio_detail.py +0 -0
  32. {otf_api-0.6.0 → otf_api-0.6.1}/src/otf_api/models/responses/studio_services.py +0 -0
  33. {otf_api-0.6.0 → otf_api-0.6.1}/src/otf_api/models/responses/telemetry_hr_history.py +0 -0
  34. {otf_api-0.6.0 → otf_api-0.6.1}/src/otf_api/models/responses/telemetry_max_hr.py +0 -0
  35. {otf_api-0.6.0 → otf_api-0.6.1}/src/otf_api/models/responses/total_classes.py +0 -0
  36. {otf_api-0.6.0 → otf_api-0.6.1}/src/otf_api/py.typed +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: otf-api
3
- Version: 0.6.0
3
+ Version: 0.6.1
4
4
  Summary: Python OrangeTheory Fitness API Client
5
5
  License: MIT
6
6
  Author: Jessica Smith
@@ -18,7 +18,7 @@ Classifier: Topic :: Internet :: WWW/HTTP
18
18
  Classifier: Topic :: Software Development :: Libraries
19
19
  Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
20
20
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
- Requires-Dist: aiohttp (==3.8.*)
21
+ Requires-Dist: aiohttp (==3.10.*)
22
22
  Requires-Dist: humanize (>=4.9.0,<5.0.0)
23
23
  Requires-Dist: inflection (==0.5.*)
24
24
  Requires-Dist: loguru (==0.7.2)
@@ -26,7 +26,6 @@ Requires-Dist: pendulum (>=3.0.0,<4.0.0)
26
26
  Requires-Dist: pint (==0.24.*)
27
27
  Requires-Dist: pycognito (==2024.5.1)
28
28
  Requires-Dist: pydantic (==2.7.3)
29
- Requires-Dist: python-box (>=7.2.0,<8.0.0)
30
29
  Project-URL: Documentation, https://otf-api.readthedocs.io/en/stable/
31
30
  Description-Content-Type: text/markdown
32
31
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "otf-api"
3
- version = "0.6.0"
3
+ version = "0.6.1"
4
4
  description = "Python OrangeTheory Fitness API Client"
5
5
  authors = ["Jessica Smith <j.smith.git1@gmail.com>"]
6
6
  license = "MIT"
@@ -22,7 +22,7 @@ classifiers = [
22
22
 
23
23
  [tool.poetry.dependencies]
24
24
  python = "^3.10"
25
- aiohttp = "3.8.*"
25
+ aiohttp = "3.10.*"
26
26
  humanize = "^4.9.0"
27
27
  inflection = "0.5.*"
28
28
  loguru = "0.7.2"
@@ -30,7 +30,6 @@ pendulum = "^3.0.0"
30
30
  pint = "0.24.*"
31
31
  pycognito = "2024.5.1"
32
32
  pydantic = "2.7.3"
33
- python-box = "^7.2.0"
34
33
 
35
34
  [tool.poetry.group.dev.dependencies]
36
35
  aioresponses = "0.7.6"
@@ -46,7 +45,7 @@ pytest-cov = "5.0.0"
46
45
  pytest-loguru = "0.4.0"
47
46
  ruff = "0.4.9"
48
47
  tox = "4.15.1"
49
- twine = "5.1.0"
48
+ twine = "5.1.1"
50
49
 
51
50
 
52
51
  [tool.poetry.group.docs.dependencies]
@@ -63,9 +62,10 @@ mkdocs-material-extensions = "1.3.1"
63
62
  mkdocs-section-index = "0.3.9"
64
63
  mkdocstrings = "0.25.1"
65
64
  mkdocstrings-python = "1.10.3"
66
- pkginfo = "^1.11.1"
65
+ pkginfo = "<1.11"
67
66
  setuptools = "^70.0.0"
68
67
  virtualenv = "^20.26.2"
68
+ griffe = "<1.0.0"
69
69
 
70
70
 
71
71
  [build-system]
@@ -6,7 +6,7 @@ from loguru import logger
6
6
  from .api import Otf
7
7
  from .auth import OtfUser
8
8
 
9
- __version__ = "0.6.0"
9
+ __version__ = "0.6.1"
10
10
 
11
11
 
12
12
  __all__ = ["Otf", "OtfUser"]
@@ -0,0 +1,22 @@
1
+ from typing import ClassVar
2
+
3
+ from pydantic import BaseModel, ConfigDict
4
+
5
+
6
+ class OtfItemBase(BaseModel):
7
+ model_config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True, extra="allow")
8
+
9
+
10
+ class OtfListBase(BaseModel):
11
+ model_config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True, extra="allow")
12
+ collection_field: ClassVar[str] = "data"
13
+
14
+ @property
15
+ def collection(self) -> list[OtfItemBase]:
16
+ return getattr(self, self.collection_field)
17
+
18
+ def to_json(self, **kwargs) -> str:
19
+ kwargs.setdefault("indent", 4)
20
+ kwargs.setdefault("exclude_none", True)
21
+
22
+ return self.model_dump_json(**kwargs)
@@ -101,7 +101,7 @@ class MemberDetail(OtfItemBase):
101
101
  state: None
102
102
  postal_code: None = Field(..., alias="postalCode")
103
103
  phone_number: str = Field(..., alias="phoneNumber")
104
- home_phone: str = Field(..., alias="homePhone")
104
+ home_phone: str | None = Field(..., alias="homePhone")
105
105
  work_phone: None = Field(..., alias="workPhone")
106
106
  phone_type: None = Field(..., alias="phoneType")
107
107
  birth_day: date | str = Field(..., alias="birthDay")
@@ -34,6 +34,7 @@ class Class(OtfItemBase):
34
34
  ot_base_class_uuid: str | None = None
35
35
  starts_at_local: str
36
36
  name: str | None = None
37
+ type: str | None = None
37
38
  coach: Coach
38
39
  studio: Studio
39
40
 
@@ -25,6 +25,14 @@ class TreadData(OtfItemBase):
25
25
  agg_tread_distance: int = Field(..., alias="aggTreadDistance")
26
26
 
27
27
 
28
+ class RowData(OtfItemBase):
29
+ row_speed: float = Field(..., alias="rowSpeed")
30
+ row_pps: float = Field(..., alias="rowPps")
31
+ row_Spm: float = Field(..., alias="rowSpm")
32
+ agg_row_distance: int = Field(..., alias="aggRowDistance")
33
+ row_pace: int = Field(..., alias="rowPace")
34
+
35
+
28
36
  class TelemetryItem(OtfItemBase):
29
37
  relative_timestamp: int = Field(..., alias="relativeTimestamp")
30
38
  hr: int
@@ -36,6 +44,7 @@ class TelemetryItem(OtfItemBase):
36
44
  description="The timestamp of the telemetry item, calculated from the class start time and relative timestamp.",
37
45
  )
38
46
  tread_data: TreadData | None = Field(None, alias="treadData")
47
+ row_data: RowData | None = Field(None, alias="rowData")
39
48
 
40
49
 
41
50
  class Telemetry(OtfItemBase):
@@ -1,149 +0,0 @@
1
- import inspect
2
- import typing
3
- from typing import ClassVar, TypeVar
4
-
5
- from box import Box
6
- from pydantic import BaseModel, ConfigDict
7
-
8
- if typing.TYPE_CHECKING:
9
- from pydantic.main import IncEx
10
-
11
- T = TypeVar("T", bound="OtfItemBase")
12
-
13
-
14
- class BetterDumperMixin:
15
- """A better dumper for Pydantic models that includes properties in the dumped data. Must be mixed
16
- into a Pydantic model, as it overrides the `model_dump` method.
17
-
18
- Includes support for nested models, and has an option to not include properties when dumping.
19
- """
20
-
21
- def get_properties(self) -> list[str]:
22
- """Get the properties of the model."""
23
- cls = type(self)
24
-
25
- properties: list[str] = []
26
- methods = inspect.getmembers(self, lambda f: not (inspect.isroutine(f)))
27
- for prop_name, _ in methods:
28
- if hasattr(cls, prop_name) and isinstance(getattr(cls, prop_name), property):
29
- properties.append(prop_name)
30
-
31
- return properties
32
-
33
- @typing.overload
34
- def model_dump(
35
- self,
36
- *,
37
- mode: typing.Literal["json", "python"] | str = "python",
38
- include: "IncEx" = None,
39
- exclude: "IncEx" = None,
40
- by_alias: bool = False,
41
- exclude_unset: bool = False,
42
- exclude_defaults: bool = False,
43
- exclude_none: bool = False,
44
- round_trip: bool = False,
45
- warnings: bool = True,
46
- include_properties: bool = True,
47
- ) -> Box[str, typing.Any]: ...
48
-
49
- @typing.overload
50
- def model_dump(
51
- self,
52
- *,
53
- mode: typing.Literal["json", "python"] | str = "python",
54
- include: "IncEx" = None,
55
- exclude: "IncEx" = None,
56
- by_alias: bool = False,
57
- exclude_unset: bool = False,
58
- exclude_defaults: bool = False,
59
- exclude_none: bool = False,
60
- round_trip: bool = False,
61
- warnings: bool = True,
62
- include_properties: bool = False,
63
- ) -> dict[str, typing.Any]: ...
64
-
65
- def model_dump(
66
- self,
67
- *,
68
- mode: typing.Literal["json", "python"] | str = "python",
69
- include: "IncEx" = None,
70
- exclude: "IncEx" = None,
71
- by_alias: bool = False,
72
- exclude_unset: bool = False,
73
- exclude_defaults: bool = False,
74
- exclude_none: bool = False,
75
- round_trip: bool = False,
76
- warnings: bool = True,
77
- include_properties: bool = True,
78
- ) -> dict[str, typing.Any] | Box[str, typing.Any]:
79
- """Usage docs: https://docs.pydantic.dev/2.4/concepts/serialization/#modelmodel_dump
80
-
81
- Generate a dictionary representation of the model, optionally specifying which fields to include or exclude.
82
-
83
- Args:
84
- mode: The mode in which `to_python` should run.
85
- If mode is 'json', the dictionary will only contain JSON serializable types.
86
- If mode is 'python', the dictionary may contain any Python objects.
87
- include: A list of fields to include in the output.
88
- exclude: A list of fields to exclude from the output.
89
- by_alias: Whether to use the field's alias in the dictionary key if defined.
90
- exclude_unset: Whether to exclude fields that are unset or None from the output.
91
- exclude_defaults: Whether to exclude fields that are set to their default value from the output.
92
- exclude_none: Whether to exclude fields that have a value of `None` from the output.
93
- round_trip: Whether to enable serialization and deserialization round-trip support.
94
- warnings: Whether to log warnings when invalid fields are encountered.
95
- include_properties: Whether to include properties in the dumped data.
96
-
97
- Returns:
98
- A dictionary representation of the model. Will be a `Box` if `include_properties` is `True`, otherwise a
99
- regular dictionary.
100
-
101
- """
102
- dumped_data = typing.cast(BaseModel, super()).model_dump(
103
- mode=mode,
104
- include=include,
105
- exclude=exclude,
106
- by_alias=by_alias,
107
- exclude_unset=exclude_unset,
108
- exclude_defaults=exclude_defaults,
109
- exclude_none=exclude_none,
110
- round_trip=round_trip,
111
- warnings=warnings,
112
- )
113
-
114
- if not include_properties:
115
- return dumped_data
116
-
117
- properties = self.get_properties()
118
-
119
- # set properties to their values
120
- for prop_name in properties:
121
- dumped_data[prop_name] = getattr(self, prop_name)
122
-
123
- # if the property is a Pydantic model, dump it as well
124
- for k, v in dumped_data.items():
125
- if issubclass(type(getattr(self, k)), BaseModel):
126
- dumped_data[k] = getattr(self, k).model_dump()
127
- elif hasattr(v, "model_dump"):
128
- dumped_data[k] = v.model_dump()
129
-
130
- return Box(dumped_data)
131
-
132
-
133
- class OtfItemBase(BetterDumperMixin, BaseModel):
134
- model_config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True, extra="forbid")
135
-
136
-
137
- class OtfListBase(BaseModel):
138
- model_config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True, extra="forbid")
139
- collection_field: ClassVar[str] = "data"
140
-
141
- @property
142
- def collection(self) -> list[OtfItemBase]:
143
- return getattr(self, self.collection_field)
144
-
145
- def to_json(self, **kwargs) -> str:
146
- kwargs.setdefault("indent", 4)
147
- kwargs.setdefault("exclude_none", True)
148
-
149
- return self.model_dump_json(**kwargs)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes