weightslab 1.2.2__tar.gz → 1.2.3__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 (328) hide show
  1. {weightslab-1.2.2 → weightslab-1.2.3}/.github/workflows/ci.yml +73 -9
  2. {weightslab-1.2.2 → weightslab-1.2.3}/.github/workflows/release.yml +26 -9
  3. {weightslab-1.2.2 → weightslab-1.2.3}/.gitignore +1 -0
  4. weightslab-1.2.3/CHANGELOG.md +1 -0
  5. {weightslab-1.2.2/weightslab.egg-info → weightslab-1.2.3}/PKG-INFO +1 -1
  6. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/__init__.py +15 -9
  7. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/_version.py +3 -3
  8. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/backend/dataloader_interface.py +48 -9
  9. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/components/global_monitoring.py +8 -2
  10. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/data/dataframe_manager.py +2 -2
  11. weightslab-1.2.3/weightslab/examples/Docker_training/README.md +38 -0
  12. weightslab-1.2.3/weightslab/examples/Docker_training/docker_in_docker/Dockerfile +58 -0
  13. weightslab-1.2.3/weightslab/examples/Docker_training/docker_in_docker/README.md +161 -0
  14. weightslab-1.2.3/weightslab/examples/Docker_training/docker_in_docker/docker-compose.yml +54 -0
  15. weightslab-1.2.3/weightslab/examples/Docker_training/docker_in_docker/entrypoint.sh +67 -0
  16. weightslab-1.2.3/weightslab/examples/Docker_training/siblings_self_contained/Dockerfile +56 -0
  17. weightslab-1.2.3/weightslab/examples/Docker_training/siblings_self_contained/README.md +159 -0
  18. weightslab-1.2.3/weightslab/examples/Docker_training/siblings_self_contained/docker-compose.yml +44 -0
  19. weightslab-1.2.3/weightslab/examples/Docker_training/siblings_self_contained/entrypoint.sh +101 -0
  20. weightslab-1.2.3/weightslab/examples/Docker_training/siblings_self_contained/ui-compose.yml +61 -0
  21. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/Lightning/ws-classification/main.py +4 -0
  22. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-classification/main.py +4 -1
  23. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-clustering/main.py +4 -0
  24. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-detection/main.py +2 -2
  25. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-generation/main.py +4 -0
  26. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/main.py +2 -2
  27. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/Ultralytics/ws-detection/main.py +7 -0
  28. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/Usecases/ws-2d-lidar-detection/main.py +4 -1
  29. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/Usecases/ws-3d-lidar-detection/main.py +2 -2
  30. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/integrations/ultralytics/dataset.py +5 -3
  31. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/integrations/ultralytics/trainer.py +23 -5
  32. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/src.py +4 -0
  33. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/trainer/services/data_service.py +21 -3
  34. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/trainer/trainer_services.py +34 -25
  35. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/utils/logs.py +28 -0
  36. {weightslab-1.2.2 → weightslab-1.2.3/weightslab.egg-info}/PKG-INFO +1 -1
  37. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab.egg-info/SOURCES.txt +10 -8
  38. weightslab-1.2.2/CHANGELOG.md +0 -1
  39. weightslab-1.2.2/weightslab/examples/PyTorch/ws-classification/certs-debug/.grpc_auth_token +0 -1
  40. weightslab-1.2.2/weightslab/examples/PyTorch/ws-classification/certs-debug/backend-server.crt +0 -26
  41. weightslab-1.2.2/weightslab/examples/PyTorch/ws-classification/certs-debug/backend-server.key +0 -28
  42. weightslab-1.2.2/weightslab/examples/PyTorch/ws-classification/certs-debug/ca.crt +0 -30
  43. weightslab-1.2.2/weightslab/examples/PyTorch/ws-classification/certs-debug/envoy-client.crt +0 -24
  44. weightslab-1.2.2/weightslab/examples/PyTorch/ws-classification/certs-debug/envoy-client.key +0 -28
  45. weightslab-1.2.2/weightslab/examples/PyTorch/ws-classification/certs-debug/envoy-server.crt +0 -25
  46. weightslab-1.2.2/weightslab/examples/PyTorch/ws-classification/certs-debug/envoy-server.key +0 -28
  47. {weightslab-1.2.2 → weightslab-1.2.3}/.gitattributes +0 -0
  48. {weightslab-1.2.2 → weightslab-1.2.3}/.github/workflows/docs-pages.yml +0 -0
  49. {weightslab-1.2.2 → weightslab-1.2.3}/AGENTS.md +0 -0
  50. {weightslab-1.2.2 → weightslab-1.2.3}/LICENSE +0 -0
  51. {weightslab-1.2.2 → weightslab-1.2.3}/README.md +0 -0
  52. {weightslab-1.2.2 → weightslab-1.2.3}/agent_config.yaml +0 -0
  53. {weightslab-1.2.2 → weightslab-1.2.3}/docs/_static/.gitkeep +0 -0
  54. {weightslab-1.2.2 → weightslab-1.2.3}/docs/_static/custom.css +0 -0
  55. {weightslab-1.2.2 → weightslab-1.2.3}/docs/_static/favicon.png +0 -0
  56. {weightslab-1.2.2 → weightslab-1.2.3}/docs/_static/logo-dark.png +0 -0
  57. {weightslab-1.2.2 → weightslab-1.2.3}/docs/_static/logo-light.png +0 -0
  58. {weightslab-1.2.2 → weightslab-1.2.3}/docs/_static/version-switcher.js +0 -0
  59. {weightslab-1.2.2 → weightslab-1.2.3}/docs/_static/weights_studio_architecture.png +0 -0
  60. {weightslab-1.2.2 → weightslab-1.2.3}/docs/_templates/.gitkeep +0 -0
  61. {weightslab-1.2.2 → weightslab-1.2.3}/docs/conf.py +0 -0
  62. {weightslab-1.2.2 → weightslab-1.2.3}/docs/configuration.rst +0 -0
  63. {weightslab-1.2.2 → weightslab-1.2.3}/docs/data_exploration.rst +0 -0
  64. {weightslab-1.2.2 → weightslab-1.2.3}/docs/four_way_approach.rst +0 -0
  65. {weightslab-1.2.2 → weightslab-1.2.3}/docs/grpc/audit_logger.rst +0 -0
  66. {weightslab-1.2.2 → weightslab-1.2.3}/docs/grpc/grpc_functions.rst +0 -0
  67. {weightslab-1.2.2 → weightslab-1.2.3}/docs/grpc/index.rst +0 -0
  68. {weightslab-1.2.2 → weightslab-1.2.3}/docs/hyperparameters.rst +0 -0
  69. {weightslab-1.2.2 → weightslab-1.2.3}/docs/index.rst +0 -0
  70. {weightslab-1.2.2 → weightslab-1.2.3}/docs/logger.rst +0 -0
  71. {weightslab-1.2.2 → weightslab-1.2.3}/docs/model_interaction.rst +0 -0
  72. {weightslab-1.2.2 → weightslab-1.2.3}/docs/pytorch_lightning.rst +0 -0
  73. {weightslab-1.2.2 → weightslab-1.2.3}/docs/quickstart.rst +0 -0
  74. {weightslab-1.2.2 → weightslab-1.2.3}/docs/requirements.txt +0 -0
  75. {weightslab-1.2.2 → weightslab-1.2.3}/docs/segmentation_usecase.rst +0 -0
  76. {weightslab-1.2.2 → weightslab-1.2.3}/docs/usecases.rst +0 -0
  77. {weightslab-1.2.2 → weightslab-1.2.3}/docs/user_functions.rst +0 -0
  78. {weightslab-1.2.2 → weightslab-1.2.3}/docs/weights_studio.rst +0 -0
  79. {weightslab-1.2.2 → weightslab-1.2.3}/pyproject.toml +0 -0
  80. {weightslab-1.2.2 → weightslab-1.2.3}/setup.cfg +0 -0
  81. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/art.py +0 -0
  82. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/backend/__init__.py +0 -0
  83. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/backend/audit_logger.py +0 -0
  84. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/backend/cli.py +0 -0
  85. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/backend/ledgers.py +0 -0
  86. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/backend/logger.py +0 -0
  87. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/backend/model_interface.py +0 -0
  88. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/backend/optimizer_interface.py +0 -0
  89. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/baseline_models/__init__.py +0 -0
  90. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/baseline_models/pytorch/__init__.py +0 -0
  91. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/baseline_models/pytorch/models.py +0 -0
  92. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/components/__init__.py +0 -0
  93. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/components/checkpoint_manager.py +0 -0
  94. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/components/evaluation_controller.py +0 -0
  95. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/components/experiment_hash.py +0 -0
  96. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/components/parallel_primitives.py +0 -0
  97. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/components/tracking.py +0 -0
  98. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/data/__init__.py +0 -0
  99. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/data/array_proxy.py +0 -0
  100. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/data/data_samples_with_ops.py +0 -0
  101. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/data/data_utils.py +0 -0
  102. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/data/h5_array_store.py +0 -0
  103. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/data/h5_dataframe_store.py +0 -0
  104. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/data/point_cloud_utils.py +0 -0
  105. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/data/sample_stats.py +0 -0
  106. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/Lightning/ws-classification/config.yaml +0 -0
  107. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-classification/config.yaml +0 -0
  108. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-clustering/config.yaml +0 -0
  109. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-clustering/face/__init__.py +0 -0
  110. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-clustering/face/data.py +0 -0
  111. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-clustering/face/model.py +0 -0
  112. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-clustering/face/signals.py +0 -0
  113. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-clustering/face/utils.py +0 -0
  114. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-detection/README.md +0 -0
  115. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-detection/config.yaml +0 -0
  116. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-detection/utils/criterions.py +0 -0
  117. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-detection/utils/data.py +0 -0
  118. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-detection/utils/model.py +0 -0
  119. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-generation/config.yaml +0 -0
  120. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/images/train/0000f77c-6257be58.jpg +0 -0
  121. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/images/train/000f8d37-d4c09a0f.jpg +0 -0
  122. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/images/train/00a0f008-a315437f.jpg +0 -0
  123. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/images/train/00c12bd0-bb46e479.jpg +0 -0
  124. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/images/train/00c29c52-f9524f1e.jpg +0 -0
  125. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/images/train/00ce6f6d-50bbee62.jpg +0 -0
  126. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/images/train/00d1bafa-1b47b41c.jpg +0 -0
  127. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/images/train/00d7268f-fd4487be.jpg +0 -0
  128. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/images/train/00f0dd0f-5e9c9557.jpg +0 -0
  129. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/images/train/0a0d7f4c-ac5c3c8f.jpg +0 -0
  130. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/images/train/0a1f4fce-f9cac880.jpg +0 -0
  131. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/images/train/0a3bb2d8-c195d91e.jpg +0 -0
  132. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/images/val/b1cac6a7-04e33135.jpg +0 -0
  133. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/images/val/b1ceb32e-3f481b43.jpg +0 -0
  134. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/images/val/b1d10d08-5b108225.jpg +0 -0
  135. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/images/val/b1d22449-15fb948f.jpg +0 -0
  136. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/images/val/b1d7b3ac-5af8623b.jpg +0 -0
  137. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/images/val/b1dce572-c6a8cb5e.jpg +0 -0
  138. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/images/val/b1e1a7b8-0aec80e8.jpg +0 -0
  139. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/images/val/b1e8ad72-c3c79240.jpg +0 -0
  140. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/images/val/b1ee702d-0ae1fc10.jpg +0 -0
  141. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/images/val/b1f0efd9-37a14dda.jpg +0 -0
  142. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/images/val/b2a0648b-d8e126bc.jpg +0 -0
  143. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/images/val/b2b70230-bad4ff6e.jpg +0 -0
  144. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/labels/train/0000f77c-6257be58.png +0 -0
  145. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/labels/train/000f8d37-d4c09a0f.png +0 -0
  146. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/labels/train/00a0f008-a315437f.png +0 -0
  147. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/labels/train/00c12bd0-bb46e479.png +0 -0
  148. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/labels/train/00c29c52-f9524f1e.png +0 -0
  149. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/labels/train/00ce6f6d-50bbee62.png +0 -0
  150. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/labels/train/00d1bafa-1b47b41c.png +0 -0
  151. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/labels/train/00d7268f-fd4487be.png +0 -0
  152. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/labels/train/00f0dd0f-5e9c9557.png +0 -0
  153. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/labels/train/0a0d7f4c-ac5c3c8f.png +0 -0
  154. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/labels/train/0a1f4fce-f9cac880.png +0 -0
  155. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/labels/train/0a3bb2d8-c195d91e.png +0 -0
  156. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/labels/val/b1cac6a7-04e33135.png +0 -0
  157. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/labels/val/b1ceb32e-3f481b43.png +0 -0
  158. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/labels/val/b1d10d08-5b108225.png +0 -0
  159. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/labels/val/b1d22449-15fb948f.png +0 -0
  160. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/labels/val/b1d7b3ac-5af8623b.png +0 -0
  161. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/labels/val/b1dce572-c6a8cb5e.png +0 -0
  162. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/labels/val/b1e1a7b8-0aec80e8.png +0 -0
  163. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/labels/val/b1e8ad72-c3c79240.png +0 -0
  164. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/labels/val/b1ee702d-0ae1fc10.png +0 -0
  165. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/labels/val/b1f0efd9-37a14dda.png +0 -0
  166. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/labels/val/b2a0648b-d8e126bc.png +0 -0
  167. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/BDD_subset/labels/val/b2b70230-bad4ff6e.png +0 -0
  168. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/config.yaml +0 -0
  169. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/utils/criterions.py +0 -0
  170. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/utils/data.py +0 -0
  171. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/PyTorch/ws-segmentation/utils/model.py +0 -0
  172. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/Ultralytics/ws-detection/config.yaml +0 -0
  173. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/Ultralytics/ws-detection/requirements.txt +0 -0
  174. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/Usecases/ws-2d-lidar-detection/README.md +0 -0
  175. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/Usecases/ws-2d-lidar-detection/config.yaml +0 -0
  176. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/Usecases/ws-2d-lidar-detection/utils/criterions.py +0 -0
  177. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/Usecases/ws-2d-lidar-detection/utils/data.py +0 -0
  178. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/Usecases/ws-2d-lidar-detection/utils/model.py +0 -0
  179. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/Usecases/ws-3d-lidar-detection/README.md +0 -0
  180. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/Usecases/ws-3d-lidar-detection/config.yaml +0 -0
  181. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/Usecases/ws-3d-lidar-detection/utils/criterions.py +0 -0
  182. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/Usecases/ws-3d-lidar-detection/utils/data.py +0 -0
  183. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/Usecases/ws-3d-lidar-detection/utils/kitti_download.py +0 -0
  184. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/examples/Usecases/ws-3d-lidar-detection/utils/model.py +0 -0
  185. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/integrations/__init__.py +0 -0
  186. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/integrations/ultralytics/README.md +0 -0
  187. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/integrations/ultralytics/__init__.py +0 -0
  188. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/integrations/ultralytics/_utils.py +0 -0
  189. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/integrations/ultralytics/collate.py +0 -0
  190. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/integrations/ultralytics/signals.py +0 -0
  191. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/models/__init__.py +0 -0
  192. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/models/model_with_ops.py +0 -0
  193. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/models/monkey_patcher.py +0 -0
  194. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/modules/__init__.py +0 -0
  195. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/modules/modules_with_ops.py +0 -0
  196. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/modules/neuron_ops.py +0 -0
  197. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/proto/__init__.py +0 -0
  198. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/proto/experiment_service.proto +0 -0
  199. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/proto/experiment_service_pb2.py +0 -0
  200. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/proto/experiment_service_pb2_grpc.py +0 -0
  201. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/security/__init__.py +0 -0
  202. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/security/cert_auth_manager.py +0 -0
  203. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/__init__.py +0 -0
  204. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/backend/__init__.py +0 -0
  205. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/backend/test_audit_logger.py +0 -0
  206. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/backend/test_cli_additional_unit.py +0 -0
  207. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/backend/test_compare_dataloaders.py +0 -0
  208. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/backend/test_data_loader_interface.py +0 -0
  209. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/backend/test_instance_signal_logger.py +0 -0
  210. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/backend/test_ledgers.py +0 -0
  211. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/backend/test_logger_core.py +0 -0
  212. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/backend/test_model_interface_unit.py +0 -0
  213. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/backend/test_optimizer_interface.py +0 -0
  214. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/backend/test_optimizer_interface_additional_unit.py +0 -0
  215. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/backend/test_ui_docker_bridge.py +0 -0
  216. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/backend/test_write_dataframe.py +0 -0
  217. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/backend/test_write_history.py +0 -0
  218. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/chaos_monkeys_utests/__init__.py +0 -0
  219. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/chaos_monkeys_utests/test_grpc_chaos_monkey_robustness.py +0 -0
  220. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/components/__init__.py +0 -0
  221. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/components/test_checkpoint_workflow.py +0 -0
  222. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/components/test_experiment_hash_and_art.py +0 -0
  223. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/components/test_global_monitoring_unit.py +0 -0
  224. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/data/__init__.py +0 -0
  225. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/data/test_data_samples_with_ops.py +0 -0
  226. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/data/test_data_service_metadata_copy.py +0 -0
  227. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/data/test_data_utils_unit.py +0 -0
  228. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/data/test_dataframe_manager_unit.py +0 -0
  229. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/data/test_flush_pipeline.py +0 -0
  230. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/data/test_h5_array_store.py +0 -0
  231. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/data/test_h5_dataframe_store.py +0 -0
  232. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/data/test_point_cloud_utils.py +0 -0
  233. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/gRPC/__init__.py +0 -0
  234. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/gRPC/test_get_point_cloud.py +0 -0
  235. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/gRPC/test_grpc_tag_operations.py +0 -0
  236. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/gRPC/test_grpc_user_actions.py +0 -0
  237. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/general/__init__.py +0 -0
  238. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/general/test_auditor_mode.py +0 -0
  239. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/general/test_cli.py +0 -0
  240. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/general/test_hyperparams.py +0 -0
  241. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/general/test_logger_snapshot_rotation.py +0 -0
  242. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/general/test_signals.py +0 -0
  243. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/general/test_signals_wrapping.py +0 -0
  244. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/integrations/__init__.py +0 -0
  245. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/integrations/test_pytorch_lightning_integration.py +0 -0
  246. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/integrations/ultralytics/ddp/ddp_ablation.py +0 -0
  247. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/integrations/ultralytics/ddp/ddp_test_suite.py +0 -0
  248. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/model/__init__.py +0 -0
  249. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/model/test_constraint_generation.py +0 -0
  250. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/model/test_dependency_patterns.py +0 -0
  251. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/model/test_logger.py +0 -0
  252. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/model/test_model_with_ops.py +0 -0
  253. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/model/test_model_with_ops_unit.py +0 -0
  254. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/model/test_tracking.py +0 -0
  255. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/modules/__init__.py +0 -0
  256. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/modules/test_modules_with_ops.py +0 -0
  257. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/test_secure_docker.py +0 -0
  258. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/test_src_functions.py +0 -0
  259. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/trainer/__init__.py +0 -0
  260. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/trainer/services/__init__.py +0 -0
  261. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/trainer/services/test_agent_prompt_unit.py +0 -0
  262. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/trainer/services/test_agent_service_unit.py +0 -0
  263. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/trainer/services/test_trainer_services_server.py +0 -0
  264. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/trainer/services/test_trainer_services_unit.py +0 -0
  265. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/trainer/test_trainer_tools.py +0 -0
  266. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/utils/__init__.py +0 -0
  267. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/utils/test_computational_graph_utils_unit.py +0 -0
  268. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/utils/test_logs_unit.py +0 -0
  269. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/utils/test_modules_dependencies_unit.py +0 -0
  270. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/utils/test_plot_graph_render_unit.py +0 -0
  271. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/utils/test_plot_graph_unit.py +0 -0
  272. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/utils/test_shape_prop_unit.py +0 -0
  273. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/utils/test_utils_tools_unit.py +0 -0
  274. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/watchdog/__init__.py +0 -0
  275. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/watchdog/test_lock_monitor.py +0 -0
  276. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/tests/watchdog/test_watchdog.py +0 -0
  277. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/trainer/__init__.py +0 -0
  278. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/trainer/experiment_context.py +0 -0
  279. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/trainer/services/__init__.py +0 -0
  280. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/trainer/services/agent/__init__.py +0 -0
  281. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/trainer/services/agent/agent.py +0 -0
  282. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/trainer/services/agent/agent_overview/agent.png +0 -0
  283. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/trainer/services/agent/agent_overview/query_example.png +0 -0
  284. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/trainer/services/agent/agent_overview/schema.png +0 -0
  285. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/trainer/services/agent/intent_prompt.py +0 -0
  286. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/trainer/services/agent_service.py +0 -0
  287. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/trainer/services/data_image_utils.py +0 -0
  288. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/trainer/services/experiment_service.py +0 -0
  289. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/trainer/services/instance_merger.py +0 -0
  290. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/trainer/services/model_service.py +0 -0
  291. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/trainer/services/utils/__init__.py +0 -0
  292. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/trainer/services/utils/tools.py +0 -0
  293. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/trainer/trainer_tools.py +0 -0
  294. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/ui/Dockerfile +0 -0
  295. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/ui/docker/.dockerignore +0 -0
  296. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/ui/docker/.env.example +0 -0
  297. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/ui/docker/DEPLOYMENT.md +0 -0
  298. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/ui/docker/docker-compose.yml +0 -0
  299. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/ui/docker/nginx-entrypoint.sh +0 -0
  300. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/ui/docker/nginx.base-path.conf copy.template +0 -0
  301. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/ui/docker/nginx.base-path.conf.template +0 -0
  302. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/ui/docker/nginx.conf +0 -0
  303. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/ui/docker/test-deployment.sh +0 -0
  304. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/ui/docker/utils/build-and-deploy.sh +0 -0
  305. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/ui/docker/utils/generate-certs-auth-token.ps1 +0 -0
  306. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/ui/docker/utils/generate-certs-auth-token.sh +0 -0
  307. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/ui/docker/utils/test-deployment.sh +0 -0
  308. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/ui/envoy/envoy.downstream_plaintext.yaml +0 -0
  309. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/ui/envoy/envoy.downstream_upstream_plaintext.yaml +0 -0
  310. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/ui/envoy/envoy.upstream_plaintext.yaml +0 -0
  311. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/ui/envoy/envoy.yaml +0 -0
  312. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/ui/nginx.conf +0 -0
  313. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/ui_docker_bridge.py +0 -0
  314. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/utils/__init__.py +0 -0
  315. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/utils/computational_graph.py +0 -0
  316. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/utils/modules_dependencies.py +0 -0
  317. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/utils/plot_graph.py +0 -0
  318. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/utils/shape_prop.py +0 -0
  319. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/utils/tools.py +0 -0
  320. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/watchdog/__init__.py +0 -0
  321. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/watchdog/grpc_watchdog.py +0 -0
  322. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/watchdog/lock_monitor.py +0 -0
  323. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/watchdog/log_level.py +0 -0
  324. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab/watchdog/watchdog.py +0 -0
  325. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab.egg-info/dependency_links.txt +0 -0
  326. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab.egg-info/entry_points.txt +0 -0
  327. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab.egg-info/requires.txt +0 -0
  328. {weightslab-1.2.2 → weightslab-1.2.3}/weightslab.egg-info/top_level.txt +0 -0
@@ -95,19 +95,22 @@ jobs:
95
95
  echo "$FILES" | xargs vulture --min-confidence 70 ./weightslab || true
96
96
  fi
97
97
 
98
+ # ── Fast install gate (always runs) ──────────────────────────────────────
99
+ # Single-version install on 3.11 — always runs so `test` has a gate to
100
+ # depend on regardless of branch.
98
101
  install:
99
102
  if: ${{ github.event_name != 'push' || !startsWith(github.ref, 'refs/tags/') }}
100
103
  runs-on: ubuntu-latest
104
+ name: install (Python 3.11)
101
105
  steps:
102
106
  - name: Checkout repository
103
107
  uses: actions/checkout@v4
104
108
 
105
- - name: Set up Python
109
+ - name: Set up Python 3.11
106
110
  uses: actions/setup-python@v5
107
111
  with:
108
112
  python-version: '3.11'
109
113
 
110
-
111
114
  - name: Install project dependencies
112
115
  run: |
113
116
  python -m pip install --upgrade pip
@@ -117,9 +120,49 @@ jobs:
117
120
  run: |
118
121
  python -c "import weightslab; print(f'weightslab imported successfully')"
119
122
 
123
+ # ── Full Python version matrix (PR and main only) ─────────────────────────
124
+ # Verifies that `pip install` + basic import work across all supported Python
125
+ # versions. Runs on every PR and every push to main; skipped on dev/other
126
+ # branch pushes to avoid unnecessary cost on work-in-progress commits.
127
+ install-matrix:
128
+ if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
129
+ runs-on: ubuntu-latest
130
+ strategy:
131
+ fail-fast: false # keep running other versions if one fails
132
+ matrix:
133
+ include:
134
+ - python-version: '3.10'
135
+ - python-version: '3.11'
136
+ - python-version: '3.12'
137
+ - python-version: '3.13'
138
+ - python-version: '3.14'
139
+ allow-prereleases: true # 3.14 is pre-release; visible failure but non-blocking
140
+ name: install (Python ${{ matrix.python-version }})
141
+ # 3.14 pre-release failures are informational — don't block the pipeline.
142
+ continue-on-error: ${{ matrix.allow-prereleases == true }}
143
+ steps:
144
+ - name: Checkout repository
145
+ uses: actions/checkout@v4
146
+
147
+ - name: Set up Python ${{ matrix.python-version }}
148
+ uses: actions/setup-python@v5
149
+ with:
150
+ python-version: ${{ matrix.python-version }}
151
+ allow-prereleases: ${{ matrix.allow-prereleases || false }}
152
+
153
+ - name: Install project dependencies
154
+ run: |
155
+ python -m pip install --upgrade pip
156
+ python -m pip install -e . --extra-index-url https://download.pytorch.org/whl/cpu
157
+
158
+ - name: Verify installation
159
+ run: |
160
+ python -c "import weightslab; print(f'weightslab imported successfully on Python ${{ matrix.python-version }}')"
161
+
120
162
  test:
121
163
  if: ${{ github.event_name != 'push' || !startsWith(github.ref, 'refs/tags/') }}
122
164
  runs-on: ubuntu-latest
165
+ # Depends on the fast 3.11 gate only — the matrix runs independently in parallel.
123
166
  needs: install
124
167
  steps:
125
168
  - name: Checkout repository
@@ -165,7 +208,8 @@ jobs:
165
208
  # echo "WeightsStudio workflow dispatch requested successfully."
166
209
 
167
210
  build-and-publish-dev:
168
- if: ${{ github.event_name != 'push' || !startsWith(github.ref, 'refs/tags/') }}
211
+ # Only publish to TestPyPI when pushing to main (not on PRs or dev branch pushes).
212
+ if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
169
213
  name: Build & Publish Dev (TestPyPI)
170
214
  needs: test
171
215
  runs-on: ubuntu-latest
@@ -248,18 +292,34 @@ jobs:
248
292
  fi
249
293
  python -m twine upload --repository-url https://test.pypi.org/legacy/ --verbose dist/*
250
294
 
295
+ # ── Cross-version install test from TestPyPI ──────────────────────────────
296
+ # Installs the just-published dev package from TestPyPI on every supported
297
+ # Python version and verifies the import works end-to-end.
298
+ # Runs only on main branch pushes (same gate as the publish step above).
251
299
  test-install-from-pip-dev:
252
- if: ${{ github.event_name != 'push' || !startsWith(github.ref, 'refs/tags/') }}
253
- name: Test Install From Pip Dev
300
+ if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
301
+ name: Test Install From Pip Dev (Python ${{ matrix.python-version }})
254
302
  needs: build-and-publish-dev
255
303
  runs-on: ubuntu-latest
304
+ strategy:
305
+ fail-fast: false
306
+ matrix:
307
+ include:
308
+ - python-version: '3.10'
309
+ - python-version: '3.11'
310
+ - python-version: '3.12'
311
+ - python-version: '3.13'
312
+ - python-version: '3.14'
313
+ allow-prereleases: true
314
+ continue-on-error: ${{ matrix.allow-prereleases == true }}
256
315
  permissions:
257
316
  contents: read
258
317
  steps:
259
- - name: Set up Python
318
+ - name: Set up Python ${{ matrix.python-version }}
260
319
  uses: actions/setup-python@v5
261
320
  with:
262
- python-version: '3.11'
321
+ python-version: ${{ matrix.python-version }}
322
+ allow-prereleases: ${{ matrix.allow-prereleases || false }}
263
323
 
264
324
  - name: Create isolated virtual environment
265
325
  run: |
@@ -296,9 +356,13 @@ jobs:
296
356
  done
297
357
 
298
358
  python -m pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://download.pytorch.org/whl/cpu --extra-index-url https://pypi.org/simple "weightslab==${WL_VERSION}" --no-cache-dir --retries 10 --timeout 60
299
- echo "weightslab==${WL_VERSION} installed from TestPyPI"
359
+ echo "weightslab==${WL_VERSION} installed from TestPyPI on Python ${{ matrix.python-version }}"
300
360
 
301
361
  - name: Verify package import
302
362
  run: |
303
363
  . .venv-ci/bin/activate
304
- python -c "import weightslab; import importlib.metadata as m; print('weightslab import OK'); print('installed version:', m.version('weightslab'))"
364
+ python -c "
365
+ import weightslab, importlib.metadata as m
366
+ print('weightslab import OK on Python ${{ matrix.python-version }}')
367
+ print('installed version:', m.version('weightslab'))
368
+ "
@@ -114,16 +114,29 @@ jobs:
114
114
  path: dist/
115
115
  retention-days: 1
116
116
 
117
+ # ── Cross-version install test from TestPyPI (Dev Release) ───────────────
117
118
  test-install-from-pip-dev-release:
118
- name: Test Install From TestPyPI (Dev Release)
119
+ name: Test Install From TestPyPI — Python ${{ matrix.python-version }} (Dev Release)
119
120
  needs: build-and-publish-dev-release
120
121
  runs-on: ubuntu-latest
122
+ strategy:
123
+ fail-fast: false
124
+ matrix:
125
+ include:
126
+ - python-version: '3.10'
127
+ - python-version: '3.11'
128
+ - python-version: '3.12'
129
+ - python-version: '3.13'
130
+ - python-version: '3.14'
131
+ allow-prereleases: true
132
+ continue-on-error: ${{ matrix.allow-prereleases == true }}
121
133
  permissions:
122
134
  contents: read
123
135
  steps:
124
136
  - uses: actions/setup-python@v5
125
137
  with:
126
- python-version: '3.11'
138
+ python-version: ${{ matrix.python-version }}
139
+ allow-prereleases: ${{ matrix.allow-prereleases || false }}
127
140
 
128
141
  - name: Create isolated virtual environment
129
142
  run: python -m venv .venv-ci
@@ -159,14 +172,14 @@ jobs:
159
172
  --extra-index-url https://pypi.org/simple/ \
160
173
  --extra-index-url https://download.pytorch.org/whl/cpu \
161
174
  "weightslab==${WL_VERSION}" --no-cache-dir --retries 10 --timeout 60
162
- echo "weightslab==${WL_VERSION} installed from TestPyPI"
175
+ echo "weightslab==${WL_VERSION} installed on Python ${{ matrix.python-version }}"
163
176
 
164
177
  - name: Verify package import
165
178
  run: |
166
179
  . .venv-ci/bin/activate
167
180
  python -c "
168
181
  import weightslab, importlib.metadata as m
169
- print('weightslab import OK')
182
+ print('weightslab import OK on Python ${{ matrix.python-version }}')
170
183
  print('installed version:', m.version('weightslab'))
171
184
  "
172
185
 
@@ -290,7 +303,6 @@ jobs:
290
303
 
291
304
  build-and-publish-main:
292
305
  name: Build & Publish Main (PyPI)
293
- # needs: [detect-target, ]
294
306
  needs: [detect-target]
295
307
  runs-on: ubuntu-latest
296
308
  if: ${{ needs.detect-target.outputs.is_main == 'true' }}
@@ -343,16 +355,21 @@ jobs:
343
355
  path: dist/
344
356
  retention-days: 1
345
357
 
358
+ # ── Cross-version install test from PyPI (Main Release) ──────────────────
346
359
  test-install-from-pip-main:
347
- name: Test Install From PyPI (Main Release)
360
+ name: Test Install From PyPI — Python ${{ matrix.python-version }} (Main Release)
348
361
  needs: build-and-publish-main
349
362
  runs-on: ubuntu-latest
363
+ strategy:
364
+ fail-fast: false
365
+ matrix:
366
+ python-version: ['3.10', '3.11', '3.12', '3.13']
350
367
  permissions:
351
368
  contents: read
352
369
  steps:
353
370
  - uses: actions/setup-python@v5
354
371
  with:
355
- python-version: '3.11'
372
+ python-version: ${{ matrix.python-version }}
356
373
 
357
374
  - name: Create isolated virtual environment
358
375
  run: python -m venv .venv-ci
@@ -387,14 +404,14 @@ jobs:
387
404
  --index-url https://pypi.org/simple/ \
388
405
  --extra-index-url https://download.pytorch.org/whl/cpu \
389
406
  "weightslab==${WL_VERSION}" --no-cache-dir --retries 10 --timeout 60
390
- echo "weightslab==${WL_VERSION} installed from PyPI"
407
+ echo "weightslab==${WL_VERSION} installed on Python ${{ matrix.python-version }}"
391
408
 
392
409
  - name: Verify package import
393
410
  run: |
394
411
  . .venv-ci/bin/activate
395
412
  python -c "
396
413
  import weightslab, importlib.metadata as m
397
- print('weightslab import OK')
414
+ print('weightslab import OK on Python ${{ matrix.python-version }}')
398
415
  print('installed version:', m.version('weightslab'))
399
416
  "
400
417
 
@@ -10,6 +10,7 @@ __pycache__
10
10
  venv
11
11
  runs
12
12
  data
13
+ MagicMock
13
14
 
14
15
  # Ignore hidden directories
15
16
  .history
@@ -0,0 +1 @@
1
+ # Changelog - 2026-06-12 v1.2.3 (1)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: weightslab
3
- Version: 1.2.2
3
+ Version: 1.2.3
4
4
  Summary: Paving the way between black-box and white-box modeling.
5
5
  Author-email: Alexandru-Andrei Rotaru <alexandru@graybx.com>, Guillaue Pelluet <guillaue@graybx.com>
6
6
  License: BSD 2-clause
@@ -14,7 +14,7 @@ import threading
14
14
  from .src import watch_or_edit, start_training, serve, keep_serving, save_signals, save_instance_signals, save_group_signals, tag_samples, register_categorical_tag, set_categorical_tag, discard_samples, get_samples_by_tag, get_discarded_samples, signal, eval_fn, compute_signals, SignalContext, clear_all, run_pending_evaluation, trigger_pending_evaluation_async, query_signal_history, query_sample_history, query_instance_history, write_history, write_dataframe, get_current_experiment_hash, pointcloud_thumbnail, pointcloud_boxes
15
15
  from .backend.ledgers import GLOBAL_LEDGER as ledger
16
16
  from .art import _BANNER
17
- from .utils.logs import setup_logging, set_log_directory
17
+ from .utils.logs import setup_logging, set_log_directory, is_main_process
18
18
  from .utils.tools import seed_everything
19
19
  from .components.global_monitoring import guard_training_context, guard_testing_context
20
20
 
@@ -25,21 +25,27 @@ from .components.global_monitoring import guard_training_context, guard_testing_
25
25
  # Change the name of the current (main) thread
26
26
  threading.current_thread().name = "WL-MainThread"
27
27
 
28
- # Auto-initialize logging on import. Python's module cache (sys.modules) guarantees
29
- # this block runs exactly once per process. Subprocesses get a fresh interpreter
30
- # and initialize independently no env var needed to coordinate across processes.
28
+ # Auto-initialize logging on import. Python's module cache (sys.modules) makes
29
+ # this block run once per process but spawned/forked workers (e.g. PyTorch
30
+ # DataLoader workers, which on Windows' 'spawn' start method re-import this
31
+ # package) are separate processes and would each re-emit the banner and create
32
+ # their own temp log file during training. The noisy parts below are therefore
33
+ # gated to the main process; workers keep a quiet console-only logger.
31
34
  log_level = os.getenv('WEIGHTSLAB_LOG_LEVEL', 'INFO')
32
35
  log_to_file = os.getenv('WEIGHTSLAB_LOG_TO_FILE', 'true').lower() == 'true'
33
36
 
34
- setup_logging(log_level, log_to_file=log_to_file)
37
+ _IS_MAIN_PROCESS = is_main_process()
38
+
39
+ setup_logging(log_level, log_to_file=(log_to_file and _IS_MAIN_PROCESS))
35
40
 
36
41
  logger = logging.getLogger(__name__)
37
- logger.info(f"WeightsLab package initialized - Log level: {log_level}, Log to file: {log_to_file}")
38
- if os.getenv('WEIGHTSLAB_SUPPRESS_BANNER', '0') != '1':
39
- logger.info(_BANNER)
42
+ if _IS_MAIN_PROCESS:
43
+ logger.info(f"WeightsLab package initialized - Log level: {log_level}, Log to file: {log_to_file}")
44
+ if os.getenv('WEIGHTSLAB_SUPPRESS_BANNER', '0') != '1':
45
+ logger.info(_BANNER)
40
46
 
41
47
  grpc_tls_enabled = os.environ.get('GRPC_TLS_ENABLED', 'true').lower() == 'true'
42
- if grpc_tls_enabled and os.environ.get('WEIGHTSLAB_SKIP_SECURE_INIT', 'false').lower() != 'true':
48
+ if _IS_MAIN_PROCESS and grpc_tls_enabled and os.environ.get('WEIGHTSLAB_SKIP_SECURE_INIT', 'false').lower() != 'true':
43
49
  try:
44
50
  from weightslab.security import CertAuthManager
45
51
 
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '1.2.2'
22
- __version_tuple__ = version_tuple = (1, 2, 2)
21
+ __version__ = version = '1.2.3'
22
+ __version_tuple__ = version_tuple = (1, 2, 3)
23
23
 
24
- __commit_id__ = commit_id = 'gffeacaaf3'
24
+ __commit_id__ = commit_id = 'g27ecce886'
@@ -443,6 +443,9 @@ class DataLoaderInterface:
443
443
  self.is_training = kwargs.pop("is_training", False)
444
444
  self._enable_h5_persistence = kwargs.pop("enable_h5_persistence", True)
445
445
  self.skip_previous_auto_load = kwargs.pop("skip_previous_auto_load", False)
446
+ # Captured so we can default it intelligently (see _should_persist_workers).
447
+ # Popped here so it never reaches DataLoader/wrapper twice via **kwargs.
448
+ self._user_persistent_workers = kwargs.pop("persistent_workers", None)
446
449
 
447
450
  # Init ledgered HP
448
451
  self.hp = get_hyperparams()
@@ -513,6 +516,7 @@ class DataLoaderInterface:
513
516
  num_workers=num_workers,
514
517
  pin_memory=pin_memory,
515
518
  collate_fn=collate_fn,
519
+ persistent_workers=self._should_persist_workers(num_workers),
516
520
  **filter_kwargs_for_callable(DataLoader, kwargs)
517
521
  )
518
522
  self._mutable_batch_sampler = batch_sampler
@@ -952,6 +956,29 @@ class DataLoaderInterface:
952
956
  # self._skipped = []
953
957
  # self._sample_offset = 0
954
958
 
959
+ def _should_persist_workers(self, num_workers: int) -> bool:
960
+ """Whether to keep DataLoader workers alive across iterator resets.
961
+
962
+ With num_workers > 0 and persistent_workers=False, every `_reset_iterator()`
963
+ (each epoch boundary, batch-size change, RNG restore) tears down and
964
+ re-spawns all worker processes. On Windows ('spawn') each respawn
965
+ re-imports torch + weightslab + the dataset module — hundreds of ms to
966
+ seconds per reset. Persisting workers makes the reset a cheap re-shuffle.
967
+
968
+ Safe because discards/eval filtering happen in the main-process sampler
969
+ (WeightsLabDataSampler, re-iterated every epoch) and the dataset's
970
+ idx->sample mapping is immutable. The one exception is tag-based
971
+ relabeling (use_tags=True): __getitem__ then reads live tags, which
972
+ today only reach workers via the per-epoch respawn — so keep respawning
973
+ in that case. An explicit persistent_workers= kwarg always wins.
974
+ """
975
+ if num_workers <= 0:
976
+ return False
977
+ if self._user_persistent_workers is not None:
978
+ return bool(self._user_persistent_workers)
979
+ use_tags_active = bool(getattr(self.tracked_dataset, "_use_tags", False))
980
+ return not use_tags_active
981
+
955
982
  def _reset_iterator(self) -> None:
956
983
  """Reset the internal iterator so `_next_batch()` starts from the beginning.
957
984
 
@@ -962,6 +989,14 @@ class DataLoaderInterface:
962
989
  import gc
963
990
  import time
964
991
 
992
+ # Workers are only torn down and re-spawned when they DON'T persist. When
993
+ # persistent_workers is on, iter(self.dataloader) reuses the live workers
994
+ # (a cheap re-shuffle), so the GC sweep and settle-delay below are pure
995
+ # overhead and are skipped.
996
+ num_workers = getattr(self.dataloader, 'num_workers', 0) or 0
997
+ persistent = bool(getattr(self.dataloader, 'persistent_workers', False))
998
+ respawning = num_workers > 0 and not persistent
999
+
965
1000
  # Explicitly delete old iterator to allow worker processes to be cleaned up
966
1001
  if hasattr(self, '_iterator') and self._iterator is not None:
967
1002
  try:
@@ -970,12 +1005,13 @@ class DataLoaderInterface:
970
1005
  except Exception as e:
971
1006
  logger.debug(f"Failed to delete old iterator: {e}")
972
1007
 
973
- # Force garbage collection to ensure worker processes are terminated
974
- # This is especially important when num_workers > 0
975
- try:
976
- gc.collect()
977
- except Exception:
978
- pass
1008
+ # Force garbage collection to ensure worker processes are terminated.
1009
+ # Only needed when workers are actually being torn down (non-persistent).
1010
+ if respawning:
1011
+ try:
1012
+ gc.collect()
1013
+ except Exception:
1014
+ pass
979
1015
 
980
1016
  # Reset sampler's offset for new epoch (important: prevents skipping samples on subsequent epochs)
981
1017
  if hasattr(self, '_mutable_batch_sampler') and self._mutable_batch_sampler is not None:
@@ -985,9 +1021,10 @@ class DataLoaderInterface:
985
1021
  if old_offset > 0:
986
1022
  logger.debug(f"Reset sampler offset from {old_offset} to 0")
987
1023
 
988
- # Give worker processes time to fully terminate (especially important with num_workers > 0)
989
- # Short delay to avoid race conditions when spawning new workers
990
- if hasattr(self.dataloader, 'num_workers') and self.dataloader.num_workers > 0:
1024
+ # Give worker processes time to fully terminate before spawning new ones.
1025
+ # Only relevant when workers are actually respawning; persistent workers
1026
+ # stay alive, so no settle-delay is needed.
1027
+ if respawning:
991
1028
  time.sleep(0.01) # 10ms delay for worker cleanup
992
1029
 
993
1030
  # Create new iterator
@@ -1168,6 +1205,7 @@ class DataLoaderInterface:
1168
1205
  num_workers=num_workers,
1169
1206
  pin_memory=pin_memory,
1170
1207
  collate_fn=collate_fn,
1208
+ persistent_workers=self._should_persist_workers(num_workers),
1171
1209
  **kwargs,
1172
1210
  )
1173
1211
  else:
@@ -1180,6 +1218,7 @@ class DataLoaderInterface:
1180
1218
  drop_last=drop_last,
1181
1219
  pin_memory=pin_memory,
1182
1220
  collate_fn=collate_fn,
1221
+ persistent_workers=self._should_persist_workers(num_workers),
1183
1222
  **kwargs,
1184
1223
  )
1185
1224
 
@@ -214,11 +214,13 @@ class GuardContext:
214
214
  except Exception:
215
215
  pass
216
216
 
217
- def __enter__(self):
217
+ def __enter__(self, f: bool = False):
218
218
  """
219
219
  Executed upon entering the 'with' block. Sets the model to training mode.
220
220
  """
221
221
  self._maybe_pause_at_step()
222
+ if f:
223
+ pause_controller.resume(force=f)
222
224
  pause_controller.wait_if_paused()
223
225
  self.architecture_guard.__enter__()
224
226
 
@@ -266,11 +268,15 @@ class GuardContext:
266
268
  self.model.set_tracking_mode(TrackingMode.EVAL)
267
269
  self.model.eval()
268
270
 
269
- def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> bool:
271
+ def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any, f: bool = False) -> bool:
270
272
  """
271
273
  Executed upon exiting the 'with' block (after user code runs).
272
274
  Reverts the model state.
273
275
  """
276
+
277
+ if f:
278
+ pause_controller.pause()
279
+
274
280
  # Revert the model state
275
281
  if self.model is not None and hasattr(self, '_prev_training_mode'):
276
282
  self.model.train(self._prev_training_mode)
@@ -1049,7 +1049,7 @@ class LedgeredDataFrameManager:
1049
1049
  if v is None:
1050
1050
  return False
1051
1051
  try:
1052
- return not np.isnan(v)
1052
+ return not np.isnan(v).any()
1053
1053
  except (TypeError, ValueError):
1054
1054
  return True
1055
1055
 
@@ -2378,7 +2378,7 @@ class LedgeredDataFrameManager:
2378
2378
  logger.debug(f"[LedgeredDataFrameManager] Waiting for buffer to drain. Buffer size: {len(self._buffer)}.")
2379
2379
  while time.time() < deadline:
2380
2380
  with self._buffer_lock:
2381
- logger.debug(f"[LedgeredDataFrameManager] Acquiring buffer lock for flush_async check. Buffer size: {len(self._buffer)}.")
2381
+ # logger.debug(f"[LedgeredDataFrameManager] Acquiring buffer lock for flush_async check. Buffer size: {len(self._buffer)}.")
2382
2382
  if len(self._buffer) < self._flush_max_rows:
2383
2383
  logger.debug(f"[LedgeredDataFrameManager] Buffer drained, proceeding. Buffer size: {len(self._buffer)}.")
2384
2384
  return
@@ -0,0 +1,38 @@
1
+ # Running WeightsLab from a "training docker" — three options
2
+
3
+ Each option runs the WeightsLab UI stack + the classification training inside a
4
+ container so the example ends up reachable at <http://localhost:5173>, talking to
5
+ the training process end-to-end. They differ in **how the container gets a docker
6
+ daemon** to launch Envoy + frontend, and the configuration that follows.
7
+
8
+ | | [docker_in_docker](docker_in_docker/) (A · DinD) | [siblings_docker](siblings_docker/) (B · DooD) | [siblings_self_contained](siblings_self_contained/) (C) |
9
+ |---|---|---|---|
10
+ | Docker daemon | own daemon, nested | host daemon (socket) | host daemon (socket) |
11
+ | Envoy/frontend run | nested in the trainer | siblings on the host | siblings on the host |
12
+ | Starts the UI via | `weightslab ui launch` | `weightslab ui launch` | own bind-mount-free `ui-compose.yml` |
13
+ | `--privileged` | **required** | no | no |
14
+ | gRPC `:50051` | not published | **published to host** | **published to host** |
15
+ | Browser ports 5173/8080 | re-published by trainer | published by siblings | published by siblings |
16
+ | Host bind mounts | resolve in-container — none | **path alignment** required | **none** (config via named volume + HTTP) |
17
+ | Host setup | none | `setup-host.sh` (clone to aligned path) | none |
18
+ | TLS (HTTPS) | ✅ `--certs` (+ backend TLS env) | ✅ `--certs` (aligned certs) | ✅ opt-in (certs via named volume) |
19
+ | Windows / Docker Desktop | ✅ works | ⚠️ awkward (use WSL2) | ✅ works natively |
20
+ | Best when | want isolation / Windows / TLS | Linux host, stock `ui launch` | "all from inside", no host prep, Windows |
21
+
22
+ See each directory's `README.md` for the detailed wiring diagram and run steps.
23
+
24
+ - **A (DinD)** — fully self-contained via a nested daemon; needs `--privileged`.
25
+ - **B (siblings)** — uses the stock `weightslab ui launch`; its bundled compose
26
+ bind-mounts the Envoy config + certs, so the host must see those files (path
27
+ alignment + `setup-host.sh`). Cleanest on a Linux host.
28
+ - **C (self-contained siblings)** — siblings *without* host bind mounts: it
29
+ delivers the Envoy config (and, for TLS, the certs) through named volumes over
30
+ the socket, so no host prep and it works natively on Windows. The trade-off:
31
+ it doesn't use `weightslab ui launch`. HTTP by default, TLS opt-in.
32
+
33
+ > All three can run secured TLS — see each README's "🔒" section. **A and C
34
+ > expose a one-flag toggle:** `WEIGHTSLAB_TLS=1 docker compose up --build`. Note
35
+ > that for **every** option cert generation only configures Envoy + the frontend;
36
+ > the **backend** example also needs `GRPC_TLS_ENABLED=1` + `GRPC_TLS_CERT_DIR`
37
+ > (the toggle handles this), or Envoy's upstream mTLS fails. And the dev CA must
38
+ > be trusted on the host browser to avoid a self-signed warning.
@@ -0,0 +1,58 @@
1
+ # =============================================================================
2
+ # WeightsLab "training docker" — Docker-in-Docker (DinD) variant
3
+ # =============================================================================
4
+ # This image runs BOTH:
5
+ # 1. the WeightsLab CLI ("weightslab ui launch") which spins up the
6
+ # Envoy + Weights Studio frontend containers, and
7
+ # 2. the training process ("weightslab start example") which serves the
8
+ # in-process gRPC backend on :50051.
9
+ #
10
+ # DinD = the container runs its OWN docker daemon inside itself (requires
11
+ # --privileged). The Envoy/frontend containers are nested *inside* this
12
+ # container's daemon, so they share this container's network namespace and
13
+ # filesystem. See README.md for why that matters.
14
+ # =============================================================================
15
+ FROM python:3.11-slim
16
+
17
+ # --- System deps -------------------------------------------------------------
18
+ # - docker engine (dockerd + CLI + compose plugin + containerd): installed via
19
+ # the official convenience script. We need the *daemon* here (DinD).
20
+ # - libgl1/libglib2.0-0: runtime libs for opencv-python (a weightslab dep).
21
+ # - curl/ca-certificates/git: fetch the docker installer + optional dev install.
22
+ RUN apt-get update && apt-get install -y --no-install-recommends \
23
+ curl sudo ca-certificates git libgl1 libglib2.0-0 \
24
+ && curl -fsSL https://get.docker.com | sh \
25
+ && rm -rf /var/lib/apt/lists/*
26
+
27
+ # --- WeightsLab --------------------------------------------------------------
28
+ # Default: install the published package from PyPI (matches "if you didn't
29
+ # modify weightslab, use pip install"). To run your local dev branch instead:
30
+ # docker compose build \
31
+ # --build-arg WEIGHTSLAB_SPEC="git+https://github.com/GrayboxTech/weightslab.git@dev"
32
+ ARG WEIGHTSLAB_SPEC=weightslab
33
+ RUN pip install --no-cache-dir "${WEIGHTSLAB_SPEC}"
34
+
35
+ # gRPC backend port — must match what Envoy is told to dial (GRPC_BACKEND_PORT).
36
+ ENV GRPC_BACKEND_PORT=50051
37
+
38
+ # --- GPU (NVIDIA) ------------------------------------------------------------
39
+ # Make the NVIDIA Container Toolkit inject the host driver (nvidia-smi + libs)
40
+ # into this container. `utility` => nvidia-smi works; `compute` => CUDA/torch.
41
+ # These are no-ops on a host without an NVIDIA GPU/toolkit (falls back to CPU).
42
+ # The actual GPU grant is requested in docker-compose.yml (deploy.resources).
43
+ # torch's default Linux wheel bundles the CUDA runtime, so no CUDA base image is
44
+ # needed — only the host driver (injected) is required for torch.cuda to work.
45
+ ENV NVIDIA_VISIBLE_DEVICES=all \
46
+ NVIDIA_DRIVER_CAPABILITIES=compute,utility
47
+
48
+ COPY entrypoint.sh /usr/local/bin/entrypoint.sh
49
+ # Strip any CR so the script runs under Linux bash even if checked out on Windows.
50
+ RUN sed -i 's/\r$//' /usr/local/bin/entrypoint.sh \
51
+ && chmod +x /usr/local/bin/entrypoint.sh
52
+
53
+ # OPTIONAL - Documentation only — EXPOSE does NOT publish ports. The host publishing is done
54
+ # by `ports:` in docker-compose.yml. Listed here purely to record intent:
55
+ # 5173 = Weights Studio frontend, 8080 = Envoy gRPC-web.
56
+ EXPOSE 5173 8080
57
+
58
+ ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]