paces 0.0.17__tar.gz → 0.0.18__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 (58) hide show
  1. {paces-0.0.17 → paces-0.0.18}/PKG-INFO +1 -1
  2. {paces-0.0.17 → paces-0.0.18}/paces/model.py +10 -2
  3. {paces-0.0.17 → paces-0.0.18}/pyproject.toml +1 -1
  4. {paces-0.0.17 → paces-0.0.18}/tests/test_ask.py +2 -0
  5. {paces-0.0.17 → paces-0.0.18}/tests/test_segment.py +25 -0
  6. {paces-0.0.17 → paces-0.0.18}/.gitignore +0 -0
  7. {paces-0.0.17 → paces-0.0.18}/LICENSE +0 -0
  8. {paces-0.0.17 → paces-0.0.18}/README.md +0 -0
  9. {paces-0.0.17 → paces-0.0.18}/docs/README.md +0 -0
  10. {paces-0.0.17 → paces-0.0.18}/docs/alignment/README.md +0 -0
  11. {paces-0.0.17 → paces-0.0.18}/docs/poc-reference/README.md +0 -0
  12. {paces-0.0.17 → paces-0.0.18}/docs/poc-reference/artifacts/clips.json +0 -0
  13. {paces-0.0.17 → paces-0.0.18}/paces/__init__.py +0 -0
  14. {paces-0.0.17 → paces-0.0.18}/paces/__main__.py +0 -0
  15. {paces-0.0.17 → paces-0.0.18}/paces/ask.py +0 -0
  16. {paces-0.0.17 → paces-0.0.18}/paces/bodies/__init__.py +0 -0
  17. {paces-0.0.17 → paces-0.0.18}/paces/bodies/_base.py +0 -0
  18. {paces-0.0.17 → paces-0.0.18}/paces/bodies/derivation.py +0 -0
  19. {paces-0.0.17 → paces-0.0.18}/paces/bodies/document.py +0 -0
  20. {paces-0.0.17 → paces-0.0.18}/paces/bodies/signal.py +0 -0
  21. {paces-0.0.17 → paces-0.0.18}/paces/bodies/step.py +0 -0
  22. {paces-0.0.17 → paces-0.0.18}/paces/corrections.py +0 -0
  23. {paces-0.0.17 → paces-0.0.18}/paces/cues.py +0 -0
  24. {paces-0.0.17 → paces-0.0.18}/paces/data/ask/ask.css +0 -0
  25. {paces-0.0.17 → paces-0.0.18}/paces/data/ask/ask.html +0 -0
  26. {paces-0.0.17 → paces-0.0.18}/paces/data/ask/ask.js +0 -0
  27. {paces-0.0.17 → paces-0.0.18}/paces/derivation.py +0 -0
  28. {paces-0.0.17 → paces-0.0.18}/paces/edits.py +0 -0
  29. {paces-0.0.17 → paces-0.0.18}/paces/evidence.py +0 -0
  30. {paces-0.0.17 → paces-0.0.18}/paces/excerpts.py +0 -0
  31. {paces-0.0.17 → paces-0.0.18}/paces/measure.py +0 -0
  32. {paces-0.0.17 → paces-0.0.18}/paces/pose.py +0 -0
  33. {paces-0.0.17 → paces-0.0.18}/paces/projection.py +0 -0
  34. {paces-0.0.17 → paces-0.0.18}/paces/render.py +0 -0
  35. {paces-0.0.17 → paces-0.0.18}/paces/segmenters.py +0 -0
  36. {paces-0.0.17 → paces-0.0.18}/paces/timed_text.py +0 -0
  37. {paces-0.0.17 → paces-0.0.18}/paces/tools.py +0 -0
  38. {paces-0.0.17 → paces-0.0.18}/tests/audio_synth.py +0 -0
  39. {paces-0.0.17 → paces-0.0.18}/tests/data/body_schemas.json +0 -0
  40. {paces-0.0.17 → paces-0.0.18}/tests/data/routine.json +0 -0
  41. {paces-0.0.17 → paces-0.0.18}/tests/poc_fixture.py +0 -0
  42. {paces-0.0.17 → paces-0.0.18}/tests/test_chapters.py +0 -0
  43. {paces-0.0.17 → paces-0.0.18}/tests/test_cli_surface.py +0 -0
  44. {paces-0.0.17 → paces-0.0.18}/tests/test_corrections.py +0 -0
  45. {paces-0.0.17 → paces-0.0.18}/tests/test_cues.py +0 -0
  46. {paces-0.0.17 → paces-0.0.18}/tests/test_derivation.py +0 -0
  47. {paces-0.0.17 → paces-0.0.18}/tests/test_edit_protection_residuals.py +0 -0
  48. {paces-0.0.17 → paces-0.0.18}/tests/test_edits.py +0 -0
  49. {paces-0.0.17 → paces-0.0.18}/tests/test_evidence.py +0 -0
  50. {paces-0.0.17 → paces-0.0.18}/tests/test_evidence_schemas.py +0 -0
  51. {paces-0.0.17 → paces-0.0.18}/tests/test_excerpts.py +0 -0
  52. {paces-0.0.17 → paces-0.0.18}/tests/test_measure.py +0 -0
  53. {paces-0.0.17 → paces-0.0.18}/tests/test_pose.py +0 -0
  54. {paces-0.0.17 → paces-0.0.18}/tests/test_render_media.py +0 -0
  55. {paces-0.0.17 → paces-0.0.18}/tests/test_roundtrip_poc.py +0 -0
  56. {paces-0.0.17 → paces-0.0.18}/tests/test_smoke.py +0 -0
  57. {paces-0.0.17 → paces-0.0.18}/tests/test_vertical_slice.py +0 -0
  58. {paces-0.0.17 → paces-0.0.18}/tests/video_synth.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: paces
3
- Version: 0.0.17
3
+ Version: 0.0.18
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
@@ -24,6 +24,7 @@ Design decisions, each argued in ``docs/07-annotation-model.md``:
24
24
 
25
25
  from __future__ import annotations
26
26
 
27
+ import math
27
28
  from collections.abc import Mapping
28
29
  from datetime import datetime
29
30
  from fractions import Fraction
@@ -286,9 +287,16 @@ def decimal_str(value: float, *, places: int = 3) -> str:
286
287
 
287
288
  >>> decimal_str(72.60000000000001, places=3)
288
289
  '72.6'
290
+ >>> decimal_str(-0.0004, places=3) # rounds to zero: no sign
291
+ '0'
289
292
  """
290
- text = f"{float(value):.{places}f}".rstrip("0").rstrip(".")
291
- return text or "0"
293
+ number = float(value)
294
+ if not math.isfinite(number):
295
+ raise ValueError(f"no decimal string for a non-finite value: {value!r}")
296
+ text = f"{number:.{places}f}"
297
+ if "." in text: # places=0 has no fraction to trim
298
+ text = text.rstrip("0").rstrip(".")
299
+ return "0" if text in ("", "-0") else text
292
300
 
293
301
 
294
302
  # ── serialisation (the git rules of docs/07 §6.5) ───────────────────────────
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
6
6
 
7
7
  [project]
8
8
  name = "paces"
9
- version = "0.0.17"
9
+ version = "0.0.18"
10
10
  description = "Turn instructional media into structured, interactive learning material"
11
11
  readme = "README.md"
12
12
  license = "MIT"
@@ -232,6 +232,8 @@ def test_js_time_format_matches_the_python_wire_format():
232
232
  values = [0, 15, 95.8, 0.8550444, 10.1235, 1e-7, 123.4567, 7.0005, 59.9996]
233
233
  # exact binary ties: Python's format rounds half-even, toFixed rounds up
234
234
  values += [10.0625, 0.0625, 0.1875, 0.3125, 2.5625, 1023.9375, 0.0005]
235
+ # values that round to zero carry no sign, in either language (#40)
236
+ values += [-0.0004, -0.0, -1e-9]
235
237
  got = _run_js(f"{json.dumps(values)}.map(core.timeStr)")
236
238
  assert got == [decimal_str(v, places=3) for v in values]
237
239
 
@@ -145,3 +145,28 @@ def test_tools_segment_accepts_json_strings():
145
145
  assert payload["method"] == "grid-placed"
146
146
  assert payload["steps"][0]["name"] == "intro"
147
147
  json.dumps(payload) # JSON-ready throughout
148
+
149
+
150
+ @pytest.mark.parametrize(
151
+ "value, places, expected",
152
+ [
153
+ (-0.0004, 3, "0"), # rounds to zero: no sign (#40)
154
+ (-0.0, 3, "0"),
155
+ (-0.0005, 3, "-0.001"),
156
+ (100, 0, "100"), # places=0: no fraction to trim, digits stay
157
+ (-0.4, 0, "0"),
158
+ (72.60000000000001, 3, "72.6"),
159
+ ],
160
+ )
161
+ def test_decimal_str_writes_clean_wire_decimals(value, places, expected):
162
+ from paces.model import decimal_str
163
+
164
+ assert decimal_str(value, places=places) == expected
165
+
166
+
167
+ @pytest.mark.parametrize("value", [float("nan"), float("inf"), float("-inf")])
168
+ def test_decimal_str_refuses_non_finite_values(value):
169
+ from paces.model import decimal_str
170
+
171
+ with pytest.raises(ValueError, match="non-finite"):
172
+ decimal_str(value)
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