paces 0.0.20__tar.gz → 0.0.21__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 (59) hide show
  1. {paces-0.0.20 → paces-0.0.21}/PKG-INFO +1 -1
  2. {paces-0.0.20 → paces-0.0.21}/paces/measure.py +12 -4
  3. {paces-0.0.20 → paces-0.0.21}/paces/model.py +5 -1
  4. {paces-0.0.20 → paces-0.0.21}/pyproject.toml +1 -1
  5. {paces-0.0.20 → paces-0.0.21}/tests/test_segment.py +32 -0
  6. {paces-0.0.20 → paces-0.0.21}/.gitignore +0 -0
  7. {paces-0.0.20 → paces-0.0.21}/LICENSE +0 -0
  8. {paces-0.0.20 → paces-0.0.21}/README.md +0 -0
  9. {paces-0.0.20 → paces-0.0.21}/docs/README.md +0 -0
  10. {paces-0.0.20 → paces-0.0.21}/docs/alignment/README.md +0 -0
  11. {paces-0.0.20 → paces-0.0.21}/docs/poc-reference/README.md +0 -0
  12. {paces-0.0.20 → paces-0.0.21}/docs/poc-reference/artifacts/clips.json +0 -0
  13. {paces-0.0.20 → paces-0.0.21}/paces/__init__.py +0 -0
  14. {paces-0.0.20 → paces-0.0.21}/paces/__main__.py +0 -0
  15. {paces-0.0.20 → paces-0.0.21}/paces/ask.py +0 -0
  16. {paces-0.0.20 → paces-0.0.21}/paces/bodies/__init__.py +0 -0
  17. {paces-0.0.20 → paces-0.0.21}/paces/bodies/_base.py +0 -0
  18. {paces-0.0.20 → paces-0.0.21}/paces/bodies/derivation.py +0 -0
  19. {paces-0.0.20 → paces-0.0.21}/paces/bodies/document.py +0 -0
  20. {paces-0.0.20 → paces-0.0.21}/paces/bodies/signal.py +0 -0
  21. {paces-0.0.20 → paces-0.0.21}/paces/bodies/step.py +0 -0
  22. {paces-0.0.20 → paces-0.0.21}/paces/corrections.py +0 -0
  23. {paces-0.0.20 → paces-0.0.21}/paces/cues.py +0 -0
  24. {paces-0.0.20 → paces-0.0.21}/paces/data/ask/ask.css +0 -0
  25. {paces-0.0.20 → paces-0.0.21}/paces/data/ask/ask.html +0 -0
  26. {paces-0.0.20 → paces-0.0.21}/paces/data/ask/ask.js +0 -0
  27. {paces-0.0.20 → paces-0.0.21}/paces/derivation.py +0 -0
  28. {paces-0.0.20 → paces-0.0.21}/paces/edits.py +0 -0
  29. {paces-0.0.20 → paces-0.0.21}/paces/evidence.py +0 -0
  30. {paces-0.0.20 → paces-0.0.21}/paces/excerpts.py +0 -0
  31. {paces-0.0.20 → paces-0.0.21}/paces/pose.py +0 -0
  32. {paces-0.0.20 → paces-0.0.21}/paces/projection.py +0 -0
  33. {paces-0.0.20 → paces-0.0.21}/paces/render.py +0 -0
  34. {paces-0.0.20 → paces-0.0.21}/paces/segmentation.py +0 -0
  35. {paces-0.0.20 → paces-0.0.21}/paces/segmenters.py +0 -0
  36. {paces-0.0.20 → paces-0.0.21}/paces/timed_text.py +0 -0
  37. {paces-0.0.20 → paces-0.0.21}/paces/tools.py +0 -0
  38. {paces-0.0.20 → paces-0.0.21}/tests/audio_synth.py +0 -0
  39. {paces-0.0.20 → paces-0.0.21}/tests/data/body_schemas.json +0 -0
  40. {paces-0.0.20 → paces-0.0.21}/tests/data/routine.json +0 -0
  41. {paces-0.0.20 → paces-0.0.21}/tests/poc_fixture.py +0 -0
  42. {paces-0.0.20 → paces-0.0.21}/tests/test_ask.py +0 -0
  43. {paces-0.0.20 → paces-0.0.21}/tests/test_chapters.py +0 -0
  44. {paces-0.0.20 → paces-0.0.21}/tests/test_cli_surface.py +0 -0
  45. {paces-0.0.20 → paces-0.0.21}/tests/test_corrections.py +0 -0
  46. {paces-0.0.20 → paces-0.0.21}/tests/test_cues.py +0 -0
  47. {paces-0.0.20 → paces-0.0.21}/tests/test_derivation.py +0 -0
  48. {paces-0.0.20 → paces-0.0.21}/tests/test_edit_protection_residuals.py +0 -0
  49. {paces-0.0.20 → paces-0.0.21}/tests/test_edits.py +0 -0
  50. {paces-0.0.20 → paces-0.0.21}/tests/test_evidence.py +0 -0
  51. {paces-0.0.20 → paces-0.0.21}/tests/test_evidence_schemas.py +0 -0
  52. {paces-0.0.20 → paces-0.0.21}/tests/test_excerpts.py +0 -0
  53. {paces-0.0.20 → paces-0.0.21}/tests/test_measure.py +0 -0
  54. {paces-0.0.20 → paces-0.0.21}/tests/test_pose.py +0 -0
  55. {paces-0.0.20 → paces-0.0.21}/tests/test_render_media.py +0 -0
  56. {paces-0.0.20 → paces-0.0.21}/tests/test_roundtrip_poc.py +0 -0
  57. {paces-0.0.20 → paces-0.0.21}/tests/test_smoke.py +0 -0
  58. {paces-0.0.20 → paces-0.0.21}/tests/test_vertical_slice.py +0 -0
  59. {paces-0.0.20 → paces-0.0.21}/tests/video_synth.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: paces
3
- Version: 0.0.20
3
+ Version: 0.0.21
4
4
  Summary: Turn instructional media into structured, interactive learning material
5
5
  Project-URL: Homepage, https://github.com/thorwhalen/paces
6
6
  Project-URL: Repository, https://github.com/thorwhalen/paces
@@ -231,7 +231,7 @@ def measure_grid(
231
231
  flags += (f"tempo-unmeasured: {tempo_unmeasured_note}{suffix}",)
232
232
 
233
233
  # Explicit beats inferred — but a disagreement is a finding, not a secret.
234
- final_tempo = known_tempo or measured_tempo
234
+ final_tempo = known_tempo if known_tempo is not None else measured_tempo
235
235
  if (
236
236
  known_tempo is not None
237
237
  and measured_tempo is not None
@@ -243,7 +243,7 @@ def measure_grid(
243
243
  f"measures {measured_tempo} — using yours; drop tempoBpm from "
244
244
  "grid= to use the measured value",
245
245
  )
246
- final_origin = known_origin or measured_origin
246
+ final_origin = known_origin if known_origin is not None else measured_origin
247
247
  if known_origin is None and measured_origin is not None:
248
248
  flags += (
249
249
  f"origin-estimated: first beat of the music region "
@@ -267,11 +267,19 @@ def measure_grid(
267
267
  confidence = UNMEASURED_CONFIDENCE
268
268
  else:
269
269
  confidence = (
270
- KNOWN_ORIGIN_CONFIDENCE if known_origin else DFLT_MEASURED_CONFIDENCE
270
+ KNOWN_ORIGIN_CONFIDENCE
271
+ if known_origin is not None
272
+ else DFLT_MEASURED_CONFIDENCE
271
273
  )
272
274
 
273
275
  spu = seconds_per_unit(grid)
274
- if total_units and total_units > 0 and spu and final_origin and region:
276
+ if (
277
+ total_units
278
+ and total_units > 0
279
+ and spu
280
+ and final_origin is not None
281
+ and region is not None
282
+ ):
275
283
  routine_s = total_units * spu
276
284
  region_s = region.end - float(Fraction(final_origin))
277
285
  evidence.update(routine_s=round(routine_s, 2), region_s=round(region_s, 2))
@@ -345,7 +345,11 @@ def resolve(doc: StepDocument) -> dict:
345
345
  """
346
346
  grid = doc.metric
347
347
  spu = seconds_per_unit(grid) if grid is not None else None
348
- origin = float(Fraction(grid.origin)) if grid and grid.origin else None
348
+ origin = (
349
+ float(Fraction(grid.origin))
350
+ if grid is not None and grid.origin is not None
351
+ else None
352
+ )
349
353
 
350
354
  def _wall(offset_units: float) -> float | None:
351
355
  if spu is None or origin is None:
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
6
6
 
7
7
  [project]
8
8
  name = "paces"
9
- version = "0.0.20"
9
+ version = "0.0.21"
10
10
  description = "Turn instructional media into structured, interactive learning material"
11
11
  readme = "README.md"
12
12
  license = "MIT"
@@ -199,3 +199,35 @@ def test_place_on_grid_names_what_is_missing(steps, grid, match):
199
199
 
200
200
  with pytest.raises(ValueError, match=match):
201
201
  place_on_grid(steps, grid)
202
+
203
+
204
+ @pytest.mark.parametrize("origin, start", [("0", 0.0), ("0.0", 0.0), ("51.2", 51.2)])
205
+ def test_resolve_computes_wall_clock_from_any_origin_including_zero(origin, start):
206
+ """An origin of 0 is a real origin, not a missing one (#46)."""
207
+ from paces.model import resolve
208
+
209
+ doc = to_document(
210
+ segment(steps=[("a", 1)], grid={**GRID, "origin": origin}),
211
+ doc_id="d",
212
+ title="t",
213
+ )
214
+ assert resolve(doc)["steps"][0]["start_s"] == pytest.approx(start)
215
+
216
+
217
+ def test_resolve_without_an_origin_has_no_wall_clock():
218
+ from paces.model import resolve
219
+
220
+ doc = to_document(segment(steps=[("a", 1)], grid=GRID), doc_id="d", title="t")
221
+ doc = doc.model_copy(
222
+ update={"metric": doc.metric.model_copy(update={"origin": None})}
223
+ )
224
+ assert resolve(doc)["steps"][0]["start_s"] is None
225
+
226
+
227
+ def test_resolve_treats_a_numeric_zero_origin_as_an_origin():
228
+ """A grid updated in place skips wire validation; 0 must still be 0 (#46)."""
229
+ from paces.model import resolve
230
+
231
+ doc = to_document(segment(steps=[("a", 1)], grid=GRID), doc_id="d", title="t")
232
+ doc = doc.model_copy(update={"metric": doc.metric.model_copy(update={"origin": 0})})
233
+ assert resolve(doc)["steps"][0]["start_s"] == 0.0
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