sweatstack 0.74.0__tar.gz → 0.75.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.
- {sweatstack-0.74.0 → sweatstack-0.75.0}/.claude/skills/sweatstack-python/client.md +16 -1
- {sweatstack-0.74.0 → sweatstack-0.75.0}/CHANGELOG.md +6 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/PKG-INFO +1 -1
- {sweatstack-0.74.0 → sweatstack-0.75.0}/pyproject.toml +1 -1
- {sweatstack-0.74.0 → sweatstack-0.75.0}/src/sweatstack/client.py +66 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/.claude/settings.local.json +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/.claude/skills/sweatstack-python/SKILL.md +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/.claude/skills/sweatstack-python/data-models.md +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/.claude/skills/sweatstack-python/fastapi.md +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/.claude/skills/sweatstack-python/streamlit.md +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/.gitignore +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/.python-version +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/CONTRIBUTING.md +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/DEVELOPMENT.md +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/LICENSE +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/Makefile +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/README.md +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/docs/conf.py +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/docs/everything.rst +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/docs/index.rst +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/examples/fastapi_webhooks_example.py +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/examples/send_webhook.py +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/plans/001a_tests.md +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/plans/001b_metadata.md +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/plans/001c_dailies.md +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/src/sweatstack/Sweat Stack examples/Getting started.ipynb +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/src/sweatstack/__init__.py +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/src/sweatstack/cli.py +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/src/sweatstack/constants.py +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/src/sweatstack/fastapi/__init__.py +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/src/sweatstack/fastapi/config.py +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/src/sweatstack/fastapi/dependencies.py +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/src/sweatstack/fastapi/models.py +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/src/sweatstack/fastapi/routes.py +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/src/sweatstack/fastapi/session.py +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/src/sweatstack/fastapi/token_stores.py +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/src/sweatstack/fastapi/webhooks.py +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/src/sweatstack/ipython_init.py +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/src/sweatstack/jupyterlab_oauth2_startup.py +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/src/sweatstack/openapi_schemas.py +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/src/sweatstack/py.typed +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/src/sweatstack/schemas.py +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/src/sweatstack/streamlit.py +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/src/sweatstack/sweatshell.py +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/src/sweatstack/utils.py +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/tests/__init__.py +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/tests/test_dailies.py +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/tests/test_dtype_conversion.py +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/tests/test_metadata.py +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/tests/test_teams.py +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/tests/test_tests.py +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/tests/test_webhooks.py +0 -0
- {sweatstack-0.74.0 → sweatstack-0.75.0}/uv.lock +0 -0
|
@@ -163,6 +163,21 @@ trace = client.create_trace(
|
|
|
163
163
|
tags=["test"],
|
|
164
164
|
notes="Lactate threshold test",
|
|
165
165
|
)
|
|
166
|
+
|
|
167
|
+
# Update a trace (full replace — fields not provided are set to null)
|
|
168
|
+
client.update_trace(
|
|
169
|
+
trace.id,
|
|
170
|
+
timestamp=trace.timestamp,
|
|
171
|
+
lactate=2.8, # corrected value
|
|
172
|
+
rpe=trace.rpe, # must re-pass to keep existing values
|
|
173
|
+
heart_rate=trace.heart_rate,
|
|
174
|
+
sport=trace.sport,
|
|
175
|
+
tags=trace.tags,
|
|
176
|
+
notes=trace.notes,
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
# Delete a trace
|
|
180
|
+
client.delete_trace("trace_id")
|
|
166
181
|
```
|
|
167
182
|
|
|
168
183
|
## Tests
|
|
@@ -373,6 +388,6 @@ df = sweatstack.get_latest_activity_data()
|
|
|
373
388
|
- **`sport` (singular) vs `sports` (list):** `get_latest_activity(sport=...)` and `create_trace(sport=...)` take a single sport. All other methods that filter by sport use `sports=[...]` (list). The singular `sport` parameter on longitudinal methods is deprecated.
|
|
374
389
|
- **DataFrames have standard dtypes.** The library converts API-optimized types (Int16, float16) to float64/datetime64[ns] automatically.
|
|
375
390
|
- **`as_dataframe=True`** is available on `get_activities()`, `get_traces()`, `get_tests()`, and `get_dailies()`. Time-series methods (`get_activity_data`, `get_longitudinal_data`, etc.) always return DataFrames.
|
|
376
|
-
- **`update_test()`
|
|
391
|
+
- **`update_test()` and `update_trace()` are full replaces.** Omitted optional fields are set to null. Always re-pass all fields you want to keep.
|
|
377
392
|
- **`summary` fields are optional.** Always null-check: `activity.summary.power.mean if activity.summary and activity.summary.power else None`.
|
|
378
393
|
- **`metrics` on ActivitySummary** lists available data streams, not the data itself. Use to check availability before calling `get_activity_data()`.
|
|
@@ -6,6 +6,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
8
|
|
|
9
|
+
## [0.75.0] - 2026-04-23
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- Update and delete traces: `update_trace()` and `delete_trace()` methods for full trace lifecycle management.
|
|
13
|
+
|
|
14
|
+
|
|
9
15
|
## [0.74.0] - 2026-04-22
|
|
10
16
|
|
|
11
17
|
### Added
|
|
@@ -1759,6 +1759,72 @@ class Client(_OAuth2Mixin, _DelegationMixin, _TokenStorageMixin, _LocalCacheMixi
|
|
|
1759
1759
|
self._raise_for_status(response)
|
|
1760
1760
|
return TraceDetails.model_validate(response.json())
|
|
1761
1761
|
|
|
1762
|
+
def update_trace(
|
|
1763
|
+
self,
|
|
1764
|
+
trace_id: str,
|
|
1765
|
+
*,
|
|
1766
|
+
timestamp: datetime,
|
|
1767
|
+
lactate: float | None = None,
|
|
1768
|
+
rpe: int | None = None,
|
|
1769
|
+
notes: str | None = None,
|
|
1770
|
+
power: int | None = None,
|
|
1771
|
+
speed: float | None = None,
|
|
1772
|
+
heart_rate: int | None = None,
|
|
1773
|
+
tags: list[str] | None = None,
|
|
1774
|
+
sport: Sport | str | None = None,
|
|
1775
|
+
) -> None:
|
|
1776
|
+
"""Updates a trace by replacing all fields.
|
|
1777
|
+
|
|
1778
|
+
This is a full replace operation. Fields not provided will be set to null
|
|
1779
|
+
server-side. To modify a single field, first fetch the trace with
|
|
1780
|
+
``get_traces()``, then pass all fields back.
|
|
1781
|
+
|
|
1782
|
+
Args:
|
|
1783
|
+
trace_id: The unique identifier of the trace to update.
|
|
1784
|
+
timestamp: The date and time when the trace was recorded.
|
|
1785
|
+
lactate: Optional blood lactate concentration in mmol/L.
|
|
1786
|
+
rpe: Optional rating of perceived exertion (typically on a scale of 1-10).
|
|
1787
|
+
notes: Optional text notes associated with this trace.
|
|
1788
|
+
power: Optional power measurement in watts.
|
|
1789
|
+
speed: Optional speed measurement in meters per second.
|
|
1790
|
+
heart_rate: Optional heart rate measurement in beats per minute.
|
|
1791
|
+
tags: Optional list of tags to associate with this trace.
|
|
1792
|
+
sport: Optional sport to associate with this trace.
|
|
1793
|
+
|
|
1794
|
+
Raises:
|
|
1795
|
+
HTTPStatusError: If the API request fails.
|
|
1796
|
+
"""
|
|
1797
|
+
sport = self._enums_to_strings([sport])[0] if sport else None
|
|
1798
|
+
with self._http_client() as client:
|
|
1799
|
+
response = client.put(
|
|
1800
|
+
url=f"/api/v1/traces/{trace_id}",
|
|
1801
|
+
json={
|
|
1802
|
+
"timestamp": timestamp.isoformat(),
|
|
1803
|
+
"lactate": lactate,
|
|
1804
|
+
"rpe": rpe,
|
|
1805
|
+
"notes": notes,
|
|
1806
|
+
"power": power,
|
|
1807
|
+
"speed": speed,
|
|
1808
|
+
"heart_rate": heart_rate,
|
|
1809
|
+
"tags": tags,
|
|
1810
|
+
"sport": sport,
|
|
1811
|
+
},
|
|
1812
|
+
)
|
|
1813
|
+
self._raise_for_status(response)
|
|
1814
|
+
|
|
1815
|
+
def delete_trace(self, trace_id: str) -> None:
|
|
1816
|
+
"""Deletes a trace.
|
|
1817
|
+
|
|
1818
|
+
Args:
|
|
1819
|
+
trace_id: The unique identifier of the trace to delete.
|
|
1820
|
+
|
|
1821
|
+
Raises:
|
|
1822
|
+
HTTPStatusError: If the API request fails.
|
|
1823
|
+
"""
|
|
1824
|
+
with self._http_client() as client:
|
|
1825
|
+
response = client.delete(url=f"/api/v1/traces/{trace_id}")
|
|
1826
|
+
self._raise_for_status(response)
|
|
1827
|
+
|
|
1762
1828
|
# -------------------------------------------------------------------------
|
|
1763
1829
|
# Tests
|
|
1764
1830
|
# -------------------------------------------------------------------------
|
|
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
|
{sweatstack-0.74.0 → sweatstack-0.75.0}/src/sweatstack/Sweat Stack examples/Getting started.ipynb
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
|
|
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
|