kinemotion 0.15.3__tar.gz → 0.16.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.

Potentially problematic release.


This version of kinemotion might be problematic. Click here for more details.

Files changed (85) hide show
  1. {kinemotion-0.15.3 → kinemotion-0.16.0}/.gitignore +2 -0
  2. {kinemotion-0.15.3 → kinemotion-0.16.0}/CHANGELOG.md +3 -0
  3. {kinemotion-0.15.3 → kinemotion-0.16.0}/CLAUDE.md +26 -2
  4. {kinemotion-0.15.3 → kinemotion-0.16.0}/PKG-INFO +1 -1
  5. {kinemotion-0.15.3 → kinemotion-0.16.0}/pyproject.toml +30 -1
  6. {kinemotion-0.15.3 → kinemotion-0.16.0}/uv.lock +69 -1
  7. {kinemotion-0.15.3 → kinemotion-0.16.0}/.dockerignore +0 -0
  8. {kinemotion-0.15.3 → kinemotion-0.16.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  9. {kinemotion-0.15.3 → kinemotion-0.16.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  10. {kinemotion-0.15.3 → kinemotion-0.16.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  11. {kinemotion-0.15.3 → kinemotion-0.16.0}/.github/pull_request_template.md +0 -0
  12. {kinemotion-0.15.3 → kinemotion-0.16.0}/.github/workflows/docs.yml +0 -0
  13. {kinemotion-0.15.3 → kinemotion-0.16.0}/.github/workflows/release.yml +0 -0
  14. {kinemotion-0.15.3 → kinemotion-0.16.0}/.pre-commit-config.yaml +0 -0
  15. {kinemotion-0.15.3 → kinemotion-0.16.0}/.readthedocs.yml +0 -0
  16. {kinemotion-0.15.3 → kinemotion-0.16.0}/.tool-versions +0 -0
  17. {kinemotion-0.15.3 → kinemotion-0.16.0}/CODE_OF_CONDUCT.md +0 -0
  18. {kinemotion-0.15.3 → kinemotion-0.16.0}/CONTRIBUTING.md +0 -0
  19. {kinemotion-0.15.3 → kinemotion-0.16.0}/Dockerfile +0 -0
  20. {kinemotion-0.15.3 → kinemotion-0.16.0}/GEMINI.md +0 -0
  21. {kinemotion-0.15.3 → kinemotion-0.16.0}/LICENSE +0 -0
  22. {kinemotion-0.15.3 → kinemotion-0.16.0}/README.md +0 -0
  23. {kinemotion-0.15.3 → kinemotion-0.16.0}/SECURITY.md +0 -0
  24. {kinemotion-0.15.3 → kinemotion-0.16.0}/docs/README.md +0 -0
  25. {kinemotion-0.15.3 → kinemotion-0.16.0}/docs/api/cmj.md +0 -0
  26. {kinemotion-0.15.3 → kinemotion-0.16.0}/docs/api/core.md +0 -0
  27. {kinemotion-0.15.3 → kinemotion-0.16.0}/docs/api/dropjump.md +0 -0
  28. {kinemotion-0.15.3 → kinemotion-0.16.0}/docs/api/overview.md +0 -0
  29. {kinemotion-0.15.3 → kinemotion-0.16.0}/docs/development/errors-findings.md +0 -0
  30. {kinemotion-0.15.3 → kinemotion-0.16.0}/docs/development/validation-plan.md +0 -0
  31. {kinemotion-0.15.3 → kinemotion-0.16.0}/docs/development/wallball-norep-detection.md +0 -0
  32. {kinemotion-0.15.3 → kinemotion-0.16.0}/docs/guides/bulk-processing.md +0 -0
  33. {kinemotion-0.15.3 → kinemotion-0.16.0}/docs/guides/camera-setup.md +0 -0
  34. {kinemotion-0.15.3 → kinemotion-0.16.0}/docs/guides/cmj-guide.md +0 -0
  35. {kinemotion-0.15.3 → kinemotion-0.16.0}/docs/index.md +0 -0
  36. {kinemotion-0.15.3 → kinemotion-0.16.0}/docs/reference/parameters.md +0 -0
  37. {kinemotion-0.15.3 → kinemotion-0.16.0}/docs/reference/pose-systems.md +0 -0
  38. {kinemotion-0.15.3 → kinemotion-0.16.0}/docs/research/sports-biomechanics-pose-estimation.md +0 -0
  39. {kinemotion-0.15.3 → kinemotion-0.16.0}/docs/technical/framerate.md +0 -0
  40. {kinemotion-0.15.3 → kinemotion-0.16.0}/docs/technical/imu-metadata.md +0 -0
  41. {kinemotion-0.15.3 → kinemotion-0.16.0}/docs/technical/real-time-analysis.md +0 -0
  42. {kinemotion-0.15.3 → kinemotion-0.16.0}/docs/technical/triple-extension.md +0 -0
  43. {kinemotion-0.15.3 → kinemotion-0.16.0}/docs/translations/es/camera-setup.md +0 -0
  44. {kinemotion-0.15.3 → kinemotion-0.16.0}/examples/bulk/README.md +0 -0
  45. {kinemotion-0.15.3 → kinemotion-0.16.0}/examples/bulk/bulk_processing.py +0 -0
  46. {kinemotion-0.15.3 → kinemotion-0.16.0}/examples/bulk/simple_example.py +0 -0
  47. {kinemotion-0.15.3 → kinemotion-0.16.0}/examples/programmatic_usage.py +0 -0
  48. {kinemotion-0.15.3 → kinemotion-0.16.0}/mkdocs.yml +0 -0
  49. {kinemotion-0.15.3 → kinemotion-0.16.0}/requirements-docs.txt +0 -0
  50. {kinemotion-0.15.3 → kinemotion-0.16.0}/samples/cmjs/README.md +0 -0
  51. {kinemotion-0.15.3 → kinemotion-0.16.0}/src/kinemotion/__init__.py +0 -0
  52. {kinemotion-0.15.3 → kinemotion-0.16.0}/src/kinemotion/api.py +0 -0
  53. {kinemotion-0.15.3 → kinemotion-0.16.0}/src/kinemotion/cli.py +0 -0
  54. {kinemotion-0.15.3 → kinemotion-0.16.0}/src/kinemotion/cmj/__init__.py +0 -0
  55. {kinemotion-0.15.3 → kinemotion-0.16.0}/src/kinemotion/cmj/analysis.py +0 -0
  56. {kinemotion-0.15.3 → kinemotion-0.16.0}/src/kinemotion/cmj/cli.py +0 -0
  57. {kinemotion-0.15.3 → kinemotion-0.16.0}/src/kinemotion/cmj/debug_overlay.py +0 -0
  58. {kinemotion-0.15.3 → kinemotion-0.16.0}/src/kinemotion/cmj/joint_angles.py +0 -0
  59. {kinemotion-0.15.3 → kinemotion-0.16.0}/src/kinemotion/cmj/kinematics.py +0 -0
  60. {kinemotion-0.15.3 → kinemotion-0.16.0}/src/kinemotion/core/__init__.py +0 -0
  61. {kinemotion-0.15.3 → kinemotion-0.16.0}/src/kinemotion/core/auto_tuning.py +0 -0
  62. {kinemotion-0.15.3 → kinemotion-0.16.0}/src/kinemotion/core/cli_utils.py +0 -0
  63. {kinemotion-0.15.3 → kinemotion-0.16.0}/src/kinemotion/core/debug_overlay_utils.py +0 -0
  64. {kinemotion-0.15.3 → kinemotion-0.16.0}/src/kinemotion/core/filtering.py +0 -0
  65. {kinemotion-0.15.3 → kinemotion-0.16.0}/src/kinemotion/core/pose.py +0 -0
  66. {kinemotion-0.15.3 → kinemotion-0.16.0}/src/kinemotion/core/smoothing.py +0 -0
  67. {kinemotion-0.15.3 → kinemotion-0.16.0}/src/kinemotion/core/video_io.py +0 -0
  68. {kinemotion-0.15.3 → kinemotion-0.16.0}/src/kinemotion/dropjump/__init__.py +0 -0
  69. {kinemotion-0.15.3 → kinemotion-0.16.0}/src/kinemotion/dropjump/analysis.py +0 -0
  70. {kinemotion-0.15.3 → kinemotion-0.16.0}/src/kinemotion/dropjump/cli.py +0 -0
  71. {kinemotion-0.15.3 → kinemotion-0.16.0}/src/kinemotion/dropjump/debug_overlay.py +0 -0
  72. {kinemotion-0.15.3 → kinemotion-0.16.0}/src/kinemotion/dropjump/kinematics.py +0 -0
  73. {kinemotion-0.15.3 → kinemotion-0.16.0}/src/kinemotion/py.typed +0 -0
  74. {kinemotion-0.15.3 → kinemotion-0.16.0}/tests/__init__.py +0 -0
  75. {kinemotion-0.15.3 → kinemotion-0.16.0}/tests/test_adaptive_threshold.py +0 -0
  76. {kinemotion-0.15.3 → kinemotion-0.16.0}/tests/test_api.py +0 -0
  77. {kinemotion-0.15.3 → kinemotion-0.16.0}/tests/test_aspect_ratio.py +0 -0
  78. {kinemotion-0.15.3 → kinemotion-0.16.0}/tests/test_cli_imports.py +0 -0
  79. {kinemotion-0.15.3 → kinemotion-0.16.0}/tests/test_cmj_analysis.py +0 -0
  80. {kinemotion-0.15.3 → kinemotion-0.16.0}/tests/test_cmj_kinematics.py +0 -0
  81. {kinemotion-0.15.3 → kinemotion-0.16.0}/tests/test_com_estimation.py +0 -0
  82. {kinemotion-0.15.3 → kinemotion-0.16.0}/tests/test_contact_detection.py +0 -0
  83. {kinemotion-0.15.3 → kinemotion-0.16.0}/tests/test_filtering.py +0 -0
  84. {kinemotion-0.15.3 → kinemotion-0.16.0}/tests/test_kinematics.py +0 -0
  85. {kinemotion-0.15.3 → kinemotion-0.16.0}/tests/test_polyorder.py +0 -0
@@ -39,7 +39,9 @@ env/
39
39
  # Testing
40
40
  .pytest_cache/
41
41
  .coverage
42
+ .coverage.*
42
43
  htmlcov/
44
+ coverage.xml
43
45
 
44
46
  # Output files
45
47
  *.mov
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  <!-- version list -->
9
9
 
10
+ ## v0.16.0 (2025-11-10)
11
+
12
+
10
13
  ## v0.15.3 (2025-11-10)
11
14
 
12
15
  ### Bug Fixes
@@ -19,10 +19,16 @@ uv run kinemotion cmj-analyze video.mp4
19
19
 
20
20
  **Development:**
21
21
  ```bash
22
- uv run pytest # Run all 75 tests
22
+ uv run pytest # Run all 75 tests with coverage (50.75%)
23
+ uv run pytest --cov-report=html # Generate HTML coverage report
23
24
  uv run ruff check --fix && uv run pyright # Lint + type check
24
25
  ```
25
26
 
27
+ **Coverage Reports:**
28
+ - Terminal: Automatic with `uv run pytest`
29
+ - HTML: `htmlcov/index.html` (open in browser)
30
+ - XML: `coverage.xml` (for CI integration)
31
+
26
32
  ## Architecture
27
33
 
28
34
  ### Module Structure
@@ -139,7 +145,7 @@ OpenCV vs NumPy ordering:
139
145
  ```bash
140
146
  uv run ruff check --fix # Auto-fix linting
141
147
  uv run pyright # Type check (strict)
142
- uv run pytest # All 70 tests
148
+ uv run pytest # All 75 tests with coverage
143
149
  ```
144
150
 
145
151
  ### Standards
@@ -148,6 +154,24 @@ uv run pytest # All 70 tests
148
154
  - Ruff (100 char lines)
149
155
  - Conventional Commits (see below)
150
156
  - **Code duplication target: < 3%**
157
+ - **Test coverage: ≥ 50% (current: 50.75% with branch coverage)**
158
+
159
+ ### Coverage Analysis
160
+
161
+ Current coverage: **50.75%** (2184 statements, 752 branches)
162
+
163
+ **Well-tested modules (>80%):**
164
+ - Core filtering: 87.80%
165
+ - Core pose tracking: 88.46%
166
+ - Drop jump kinematics: 83.94%
167
+ - CMJ kinematics: 94.67%
168
+
169
+ **Needs improvement (<30%):**
170
+ - CLI modules: 22-23% (expected - minimal integration tests)
171
+ - Debug overlays: 10-36% (visualization code)
172
+ - Joint angles: 6.20% (feature module)
173
+
174
+ View detailed report: `uv run pytest --cov-report=html && open htmlcov/index.html`
151
175
 
152
176
  ### Avoiding Code Duplication
153
177
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kinemotion
3
- Version: 0.15.3
3
+ Version: 0.16.0
4
4
  Summary: Video-based kinematic analysis for athletic performance
5
5
  Project-URL: Homepage, https://github.com/feniix/kinemotion
6
6
  Project-URL: Repository, https://github.com/feniix/kinemotion
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "kinemotion"
3
- version = "0.15.3"
3
+ version = "0.16.0"
4
4
  description = "Video-based kinematic analysis for athletic performance"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10,<3.13"
@@ -50,6 +50,7 @@ packages = ["src/kinemotion"]
50
50
  [dependency-groups]
51
51
  dev = [
52
52
  "pytest>=7.4.3",
53
+ "pytest-cov>=5.0.0",
53
54
  "black>=23.12.0",
54
55
  "ruff>=0.1.8",
55
56
  "pyright>=1.1.380",
@@ -61,6 +62,34 @@ dev = [
61
62
  ]
62
63
 
63
64
 
65
+ [tool.pytest.ini_options]
66
+ testpaths = ["tests"]
67
+ addopts = [
68
+ "--cov=src/kinemotion",
69
+ "--cov-report=term-missing",
70
+ "--cov-report=html",
71
+ "--cov-report=xml",
72
+ "--cov-branch",
73
+ ]
74
+
75
+ [tool.coverage.run]
76
+ source = ["src/kinemotion"]
77
+ branch = true
78
+ parallel = true
79
+
80
+ [tool.coverage.report]
81
+ exclude_lines = [
82
+ "pragma: no cover",
83
+ "def __repr__",
84
+ "raise AssertionError",
85
+ "raise NotImplementedError",
86
+ "if __name__ == .__main__.:",
87
+ "if TYPE_CHECKING:",
88
+ ]
89
+ precision = 2
90
+ show_missing = true
91
+ fail_under = 50.0 # Current baseline: 50.75% - prevent regression
92
+
64
93
  [tool.ruff]
65
94
  line-length = 100
66
95
  target-version = "py310"
@@ -346,6 +346,58 @@ wheels = [
346
346
  { url = "https://files.pythonhosted.org/packages/0c/58/bd257695f39d05594ca4ad60df5bcb7e32247f9951fd09a9b8edb82d1daa/contourpy-1.3.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:3d1a3799d62d45c18bafd41c5fa05120b96a28079f2393af559b843d1a966a77", size = 225315, upload-time = "2025-07-26T12:02:58.801Z" },
347
347
  ]
348
348
 
349
+ [[package]]
350
+ name = "coverage"
351
+ version = "7.11.3"
352
+ source = { registry = "https://pypi.org/simple" }
353
+ sdist = { url = "https://files.pythonhosted.org/packages/d2/59/9698d57a3b11704c7b89b21d69e9d23ecf80d538cabb536c8b63f4a12322/coverage-7.11.3.tar.gz", hash = "sha256:0f59387f5e6edbbffec2281affb71cdc85e0776c1745150a3ab9b6c1d016106b", size = 815210, upload-time = "2025-11-10T00:13:17.18Z" }
354
+ wheels = [
355
+ { url = "https://files.pythonhosted.org/packages/fd/68/b53157115ef76d50d1d916d6240e5cd5b3c14dba8ba1b984632b8221fc2e/coverage-7.11.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0c986537abca9b064510f3fd104ba33e98d3036608c7f2f5537f869bc10e1ee5", size = 216377, upload-time = "2025-11-10T00:10:27.317Z" },
356
+ { url = "https://files.pythonhosted.org/packages/14/c1/d2f9d8e37123fe6e7ab8afcaab8195f13bc84a8b2f449a533fd4812ac724/coverage-7.11.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:28c5251b3ab1d23e66f1130ca0c419747edfbcb4690de19467cd616861507af7", size = 216892, upload-time = "2025-11-10T00:10:30.624Z" },
357
+ { url = "https://files.pythonhosted.org/packages/83/73/18f05d8010149b650ed97ee5c9f7e4ae68c05c7d913391523281e41c2495/coverage-7.11.3-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:4f2bb4ee8dd40f9b2a80bb4adb2aecece9480ba1fa60d9382e8c8e0bd558e2eb", size = 243650, upload-time = "2025-11-10T00:10:32.392Z" },
358
+ { url = "https://files.pythonhosted.org/packages/63/3c/c0cbb296c0ecc6dcbd70f4b473fcd7fe4517bbef8b09f4326d78f38adb87/coverage-7.11.3-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e5f4bfac975a2138215a38bda599ef00162e4143541cf7dd186da10a7f8e69f1", size = 245478, upload-time = "2025-11-10T00:10:34.157Z" },
359
+ { url = "https://files.pythonhosted.org/packages/b9/9a/dad288cf9faa142a14e75e39dc646d968b93d74e15c83e9b13fd628f2cb3/coverage-7.11.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8f4cbfff5cf01fa07464439a8510affc9df281535f41a1f5312fbd2b59b4ab5c", size = 247337, upload-time = "2025-11-10T00:10:35.655Z" },
360
+ { url = "https://files.pythonhosted.org/packages/e3/ba/f6148ebf5547b3502013175e41bf3107a4e34b7dd19f9793a6ce0e1cd61f/coverage-7.11.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:31663572f20bf3406d7ac00d6981c7bbbcec302539d26b5ac596ca499664de31", size = 244328, upload-time = "2025-11-10T00:10:37.459Z" },
361
+ { url = "https://files.pythonhosted.org/packages/e6/4d/b93784d0b593c5df89a0d48cbbd2d0963e0ca089eaf877405849792e46d3/coverage-7.11.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9799bd6a910961cb666196b8583ed0ee125fa225c6fdee2cbf00232b861f29d2", size = 245381, upload-time = "2025-11-10T00:10:39.229Z" },
362
+ { url = "https://files.pythonhosted.org/packages/3a/8d/6735bfd4f0f736d457642ee056a570d704c9d57fdcd5c91ea5d6b15c944e/coverage-7.11.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:097acc18bedf2c6e3144eaf09b5f6034926c3c9bb9e10574ffd0942717232507", size = 243390, upload-time = "2025-11-10T00:10:40.984Z" },
363
+ { url = "https://files.pythonhosted.org/packages/db/3d/7ba68ed52d1873d450aefd8d2f5a353e67b421915cb6c174e4222c7b918c/coverage-7.11.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:6f033dec603eea88204589175782290a038b436105a8f3637a81c4359df27832", size = 243654, upload-time = "2025-11-10T00:10:42.496Z" },
364
+ { url = "https://files.pythonhosted.org/packages/14/26/be2720c4c7bf73c6591ae4ab503a7b5a31c7a60ced6dba855cfcb4a5af7e/coverage-7.11.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:dd9ca2d44ed8018c90efb72f237a2a140325a4c3339971364d758e78b175f58e", size = 244272, upload-time = "2025-11-10T00:10:44.39Z" },
365
+ { url = "https://files.pythonhosted.org/packages/90/20/086f5697780df146dbc0df4ae9b6db2b23ddf5aa550f977b2825137728e9/coverage-7.11.3-cp310-cp310-win32.whl", hash = "sha256:900580bc99c145e2561ea91a2d207e639171870d8a18756eb57db944a017d4bb", size = 218969, upload-time = "2025-11-10T00:10:45.863Z" },
366
+ { url = "https://files.pythonhosted.org/packages/98/5c/cc6faba945ede5088156da7770e30d06c38b8591785ac99bcfb2074f9ef6/coverage-7.11.3-cp310-cp310-win_amd64.whl", hash = "sha256:c8be5bfcdc7832011b2652db29ed7672ce9d353dd19bce5272ca33dbcf60aaa8", size = 219903, upload-time = "2025-11-10T00:10:47.676Z" },
367
+ { url = "https://files.pythonhosted.org/packages/92/92/43a961c0f57b666d01c92bcd960c7f93677de5e4ee7ca722564ad6dee0fa/coverage-7.11.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:200bb89fd2a8a07780eafcdff6463104dec459f3c838d980455cfa84f5e5e6e1", size = 216504, upload-time = "2025-11-10T00:10:49.524Z" },
368
+ { url = "https://files.pythonhosted.org/packages/5d/5c/dbfc73329726aef26dbf7fefef81b8a2afd1789343a579ea6d99bf15d26e/coverage-7.11.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8d264402fc179776d43e557e1ca4a7d953020d3ee95f7ec19cc2c9d769277f06", size = 217006, upload-time = "2025-11-10T00:10:51.32Z" },
369
+ { url = "https://files.pythonhosted.org/packages/a5/e0/878c84fb6661964bc435beb1e28c050650aa30e4c1cdc12341e298700bda/coverage-7.11.3-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:385977d94fc155f8731c895accdfcc3dd0d9dd9ef90d102969df95d3c637ab80", size = 247415, upload-time = "2025-11-10T00:10:52.805Z" },
370
+ { url = "https://files.pythonhosted.org/packages/56/9e/0677e78b1e6a13527f39c4b39c767b351e256b333050539861c63f98bd61/coverage-7.11.3-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0542ddf6107adbd2592f29da9f59f5d9cff7947b5bb4f734805085c327dcffaa", size = 249332, upload-time = "2025-11-10T00:10:54.35Z" },
371
+ { url = "https://files.pythonhosted.org/packages/54/90/25fc343e4ce35514262451456de0953bcae5b37dda248aed50ee51234cee/coverage-7.11.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d60bf4d7f886989ddf80e121a7f4d140d9eac91f1d2385ce8eb6bda93d563297", size = 251443, upload-time = "2025-11-10T00:10:55.832Z" },
372
+ { url = "https://files.pythonhosted.org/packages/13/56/bc02bbc890fd8b155a64285c93e2ab38647486701ac9c980d457cdae857a/coverage-7.11.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0a3b6e32457535df0d41d2d895da46434706dd85dbaf53fbc0d3bd7d914b362", size = 247554, upload-time = "2025-11-10T00:10:57.829Z" },
373
+ { url = "https://files.pythonhosted.org/packages/0f/ab/0318888d091d799a82d788c1e8d8bd280f1d5c41662bbb6e11187efe33e8/coverage-7.11.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:876a3ee7fd2613eb79602e4cdb39deb6b28c186e76124c3f29e580099ec21a87", size = 249139, upload-time = "2025-11-10T00:10:59.465Z" },
374
+ { url = "https://files.pythonhosted.org/packages/79/d8/3ee50929c4cd36fcfcc0f45d753337001001116c8a5b8dd18d27ea645737/coverage-7.11.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:a730cd0824e8083989f304e97b3f884189efb48e2151e07f57e9e138ab104200", size = 247209, upload-time = "2025-11-10T00:11:01.432Z" },
375
+ { url = "https://files.pythonhosted.org/packages/94/7c/3cf06e327401c293e60c962b4b8a2ceb7167c1a428a02be3adbd1d7c7e4c/coverage-7.11.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:b5cd111d3ab7390be0c07ad839235d5ad54d2ca497b5f5db86896098a77180a4", size = 246936, upload-time = "2025-11-10T00:11:02.964Z" },
376
+ { url = "https://files.pythonhosted.org/packages/99/0b/ffc03dc8f4083817900fd367110015ef4dd227b37284104a5eb5edc9c106/coverage-7.11.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:074e6a5cd38e06671580b4d872c1a67955d4e69639e4b04e87fc03b494c1f060", size = 247835, upload-time = "2025-11-10T00:11:04.405Z" },
377
+ { url = "https://files.pythonhosted.org/packages/17/4d/dbe54609ee066553d0bcdcdf108b177c78dab836292bee43f96d6a5674d1/coverage-7.11.3-cp311-cp311-win32.whl", hash = "sha256:86d27d2dd7c7c5a44710565933c7dc9cd70e65ef97142e260d16d555667deef7", size = 218994, upload-time = "2025-11-10T00:11:05.966Z" },
378
+ { url = "https://files.pythonhosted.org/packages/94/11/8e7155df53f99553ad8114054806c01a2c0b08f303ea7e38b9831652d83d/coverage-7.11.3-cp311-cp311-win_amd64.whl", hash = "sha256:ca90ef33a152205fb6f2f0c1f3e55c50df4ef049bb0940ebba666edd4cdebc55", size = 219926, upload-time = "2025-11-10T00:11:07.936Z" },
379
+ { url = "https://files.pythonhosted.org/packages/1f/93/bea91b6a9e35d89c89a1cd5824bc72e45151a9c2a9ca0b50d9e9a85e3ae3/coverage-7.11.3-cp311-cp311-win_arm64.whl", hash = "sha256:56f909a40d68947ef726ce6a34eb38f0ed241ffbe55c5007c64e616663bcbafc", size = 218599, upload-time = "2025-11-10T00:11:09.578Z" },
380
+ { url = "https://files.pythonhosted.org/packages/c2/39/af056ec7a27c487e25c7f6b6e51d2ee9821dba1863173ddf4dc2eebef4f7/coverage-7.11.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5b771b59ac0dfb7f139f70c85b42717ef400a6790abb6475ebac1ecee8de782f", size = 216676, upload-time = "2025-11-10T00:11:11.566Z" },
381
+ { url = "https://files.pythonhosted.org/packages/3c/f8/21126d34b174d037b5d01bea39077725cbb9a0da94a95c5f96929c695433/coverage-7.11.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:603c4414125fc9ae9000f17912dcfd3d3eb677d4e360b85206539240c96ea76e", size = 217034, upload-time = "2025-11-10T00:11:13.12Z" },
382
+ { url = "https://files.pythonhosted.org/packages/d5/3f/0fd35f35658cdd11f7686303214bd5908225838f374db47f9e457c8d6df8/coverage-7.11.3-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:77ffb3b7704eb7b9b3298a01fe4509cef70117a52d50bcba29cffc5f53dd326a", size = 248531, upload-time = "2025-11-10T00:11:15.023Z" },
383
+ { url = "https://files.pythonhosted.org/packages/8f/59/0bfc5900fc15ce4fd186e092451de776bef244565c840c9c026fd50857e1/coverage-7.11.3-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4d4ca49f5ba432b0755ebb0fc3a56be944a19a16bb33802264bbc7311622c0d1", size = 251290, upload-time = "2025-11-10T00:11:16.628Z" },
384
+ { url = "https://files.pythonhosted.org/packages/71/88/d5c184001fa2ac82edf1b8f2cd91894d2230d7c309e937c54c796176e35b/coverage-7.11.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:05fd3fb6edff0c98874d752013588836f458261e5eba587afe4c547bba544afd", size = 252375, upload-time = "2025-11-10T00:11:18.249Z" },
385
+ { url = "https://files.pythonhosted.org/packages/5c/29/f60af9f823bf62c7a00ce1ac88441b9a9a467e499493e5cc65028c8b8dd2/coverage-7.11.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0e920567f8c3a3ce68ae5a42cf7c2dc4bb6cc389f18bff2235dd8c03fa405de5", size = 248946, upload-time = "2025-11-10T00:11:20.202Z" },
386
+ { url = "https://files.pythonhosted.org/packages/67/16/4662790f3b1e03fce5280cad93fd18711c35980beb3c6f28dca41b5230c6/coverage-7.11.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4bec8c7160688bd5a34e65c82984b25409563134d63285d8943d0599efbc448e", size = 250310, upload-time = "2025-11-10T00:11:21.689Z" },
387
+ { url = "https://files.pythonhosted.org/packages/8f/75/dd6c2e28308a83e5fc1ee602f8204bd3aa5af685c104cb54499230cf56db/coverage-7.11.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:adb9b7b42c802bd8cb3927de8c1c26368ce50c8fdaa83a9d8551384d77537044", size = 248461, upload-time = "2025-11-10T00:11:23.384Z" },
388
+ { url = "https://files.pythonhosted.org/packages/16/fe/b71af12be9f59dc9eb060688fa19a95bf3223f56c5af1e9861dfa2275d2c/coverage-7.11.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:c8f563b245b4ddb591e99f28e3cd140b85f114b38b7f95b2e42542f0603eb7d7", size = 248039, upload-time = "2025-11-10T00:11:25.07Z" },
389
+ { url = "https://files.pythonhosted.org/packages/11/b8/023b2003a2cd96bdf607afe03d9b96c763cab6d76e024abe4473707c4eb8/coverage-7.11.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e2a96fdc7643c9517a317553aca13b5cae9bad9a5f32f4654ce247ae4d321405", size = 249903, upload-time = "2025-11-10T00:11:26.992Z" },
390
+ { url = "https://files.pythonhosted.org/packages/d6/ee/5f1076311aa67b1fa4687a724cc044346380e90ce7d94fec09fd384aa5fd/coverage-7.11.3-cp312-cp312-win32.whl", hash = "sha256:e8feeb5e8705835f0622af0fe7ff8d5cb388948454647086494d6c41ec142c2e", size = 219201, upload-time = "2025-11-10T00:11:28.619Z" },
391
+ { url = "https://files.pythonhosted.org/packages/4f/24/d21688f48fe9fcc778956680fd5aaf69f4e23b245b7c7a4755cbd421d25b/coverage-7.11.3-cp312-cp312-win_amd64.whl", hash = "sha256:abb903ffe46bd319d99979cdba350ae7016759bb69f47882242f7b93f3356055", size = 220012, upload-time = "2025-11-10T00:11:30.234Z" },
392
+ { url = "https://files.pythonhosted.org/packages/4f/9e/d5eb508065f291456378aa9b16698b8417d87cb084c2b597f3beb00a8084/coverage-7.11.3-cp312-cp312-win_arm64.whl", hash = "sha256:1451464fd855d9bd000c19b71bb7dafea9ab815741fb0bd9e813d9b671462d6f", size = 218652, upload-time = "2025-11-10T00:11:32.165Z" },
393
+ { url = "https://files.pythonhosted.org/packages/19/8f/92bdd27b067204b99f396a1414d6342122f3e2663459baf787108a6b8b84/coverage-7.11.3-py3-none-any.whl", hash = "sha256:351511ae28e2509c8d8cae5311577ea7dd511ab8e746ffc8814a0896c3d33fbe", size = 208478, upload-time = "2025-11-10T00:13:14.908Z" },
394
+ ]
395
+
396
+ [package.optional-dependencies]
397
+ toml = [
398
+ { name = "tomli", marker = "python_full_version <= '3.11'" },
399
+ ]
400
+
349
401
  [[package]]
350
402
  name = "cycler"
351
403
  version = "0.12.1"
@@ -648,7 +700,7 @@ wheels = [
648
700
 
649
701
  [[package]]
650
702
  name = "kinemotion"
651
- version = "0.15.3"
703
+ version = "0.16.0"
652
704
  source = { editable = "." }
653
705
  dependencies = [
654
706
  { name = "click" },
@@ -668,6 +720,7 @@ dev = [
668
720
  { name = "pre-commit" },
669
721
  { name = "pyright" },
670
722
  { name = "pytest" },
723
+ { name = "pytest-cov" },
671
724
  { name = "python-semantic-release" },
672
725
  { name = "ruff" },
673
726
  ]
@@ -690,6 +743,7 @@ dev = [
690
743
  { name = "pre-commit", specifier = ">=3.6.0" },
691
744
  { name = "pyright", specifier = ">=1.1.380" },
692
745
  { name = "pytest", specifier = ">=7.4.3" },
746
+ { name = "pytest-cov", specifier = ">=5.0.0" },
693
747
  { name = "python-semantic-release", specifier = ">=9.8.2" },
694
748
  { name = "ruff", specifier = ">=0.1.8" },
695
749
  ]
@@ -1434,6 +1488,20 @@ wheels = [
1434
1488
  { url = "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79", size = 365750, upload-time = "2025-09-04T14:34:20.226Z" },
1435
1489
  ]
1436
1490
 
1491
+ [[package]]
1492
+ name = "pytest-cov"
1493
+ version = "7.0.0"
1494
+ source = { registry = "https://pypi.org/simple" }
1495
+ dependencies = [
1496
+ { name = "coverage", extra = ["toml"] },
1497
+ { name = "pluggy" },
1498
+ { name = "pytest" },
1499
+ ]
1500
+ sdist = { url = "https://files.pythonhosted.org/packages/5e/f7/c933acc76f5208b3b00089573cf6a2bc26dc80a8aece8f52bb7d6b1855ca/pytest_cov-7.0.0.tar.gz", hash = "sha256:33c97eda2e049a0c5298e91f519302a1334c26ac65c1a483d6206fd458361af1", size = 54328, upload-time = "2025-09-09T10:57:02.113Z" }
1501
+ wheels = [
1502
+ { url = "https://files.pythonhosted.org/packages/ee/49/1377b49de7d0c1ce41292161ea0f721913fa8722c19fb9c1e3aa0367eecb/pytest_cov-7.0.0-py3-none-any.whl", hash = "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861", size = 22424, upload-time = "2025-09-09T10:57:00.695Z" },
1503
+ ]
1504
+
1437
1505
  [[package]]
1438
1506
  name = "python-dateutil"
1439
1507
  version = "2.9.0.post0"
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