oopsie-data-tools 0.2.0__py3-none-any.whl

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 (74) hide show
  1. oopsie_data_tools/__init__.py +7 -0
  2. oopsie_data_tools/annotation_tool/__init__.py +5 -0
  3. oopsie_data_tools/annotation_tool/annotation_schema.py +266 -0
  4. oopsie_data_tools/annotation_tool/annotator_server.py +850 -0
  5. oopsie_data_tools/annotation_tool/episode_recorder.py +648 -0
  6. oopsie_data_tools/annotation_tool/rollout_annotator.py +333 -0
  7. oopsie_data_tools/annotation_tool/ui/annotator.html +2240 -0
  8. oopsie_data_tools/cli.py +894 -0
  9. oopsie_data_tools/init_wizard.py +329 -0
  10. oopsie_data_tools/skill/SKILL.md +98 -0
  11. oopsie_data_tools/skill/reference/conversion.md +257 -0
  12. oopsie_data_tools/skill/reference/format.md +112 -0
  13. oopsie_data_tools/skill/reference/robot-profile.md +104 -0
  14. oopsie_data_tools/skill/reference/setup.md +216 -0
  15. oopsie_data_tools/skill/reference/troubleshooting.md +97 -0
  16. oopsie_data_tools/test/__init__.py +1 -0
  17. oopsie_data_tools/test/conftest.py +174 -0
  18. oopsie_data_tools/test/fixtures/__init__.py +0 -0
  19. oopsie_data_tools/test/fixtures/make_invalid.py +633 -0
  20. oopsie_data_tools/test/fixtures/make_valid.py +406 -0
  21. oopsie_data_tools/test/test_annotation_completeness.py +154 -0
  22. oopsie_data_tools/test/test_annotation_schema.py +190 -0
  23. oopsie_data_tools/test/test_annotator_server.py +240 -0
  24. oopsie_data_tools/test/test_annotator_server_guards.py +146 -0
  25. oopsie_data_tools/test/test_bulk_inference_end_to_end.py +112 -0
  26. oopsie_data_tools/test/test_cli_config.py +111 -0
  27. oopsie_data_tools/test/test_cli_tools.py +438 -0
  28. oopsie_data_tools/test/test_contributor_config.py +38 -0
  29. oopsie_data_tools/test/test_conversion_utils_annotations.py +75 -0
  30. oopsie_data_tools/test/test_credentials_location.py +106 -0
  31. oopsie_data_tools/test/test_diversity.py +33 -0
  32. oopsie_data_tools/test/test_episode_recorder.py +335 -0
  33. oopsie_data_tools/test/test_episode_video_paths.py +173 -0
  34. oopsie_data_tools/test/test_hf_upload.py +234 -0
  35. oopsie_data_tools/test/test_init_wizard.py +193 -0
  36. oopsie_data_tools/test/test_install_skill.py +120 -0
  37. oopsie_data_tools/test/test_migrate_taxonomy_v2.py +255 -0
  38. oopsie_data_tools/test/test_new_profile.py +84 -0
  39. oopsie_data_tools/test/test_paths.py +137 -0
  40. oopsie_data_tools/test/test_python38_compat.py +79 -0
  41. oopsie_data_tools/test/test_record_step_purity.py +127 -0
  42. oopsie_data_tools/test/test_robot_setup.py +244 -0
  43. oopsie_data_tools/test/test_rollout_annotator.py +134 -0
  44. oopsie_data_tools/test/test_rotation_utils.py +126 -0
  45. oopsie_data_tools/test/test_validate.py +494 -0
  46. oopsie_data_tools/utils/__init__.py +1 -0
  47. oopsie_data_tools/utils/claude_skill.py +96 -0
  48. oopsie_data_tools/utils/contributor_config.py +91 -0
  49. oopsie_data_tools/utils/conversion_utils.py +220 -0
  50. oopsie_data_tools/utils/h5.py +60 -0
  51. oopsie_data_tools/utils/h5_inspect.py +167 -0
  52. oopsie_data_tools/utils/hf_limits.py +22 -0
  53. oopsie_data_tools/utils/hf_upload.py +235 -0
  54. oopsie_data_tools/utils/log.py +35 -0
  55. oopsie_data_tools/utils/migrate_taxonomy_v2.py +215 -0
  56. oopsie_data_tools/utils/paths.py +162 -0
  57. oopsie_data_tools/utils/restructure.py +402 -0
  58. oopsie_data_tools/utils/robot_profile/__init__.py +1 -0
  59. oopsie_data_tools/utils/robot_profile/robot_profile.py +240 -0
  60. oopsie_data_tools/utils/robot_profile/rotation_utils.py +119 -0
  61. oopsie_data_tools/utils/robot_profile/template.py +108 -0
  62. oopsie_data_tools/utils/validation/__init__.py +5 -0
  63. oopsie_data_tools/utils/validation/annotation_completeness.py +67 -0
  64. oopsie_data_tools/utils/validation/diversity.py +93 -0
  65. oopsie_data_tools/utils/validation/episode_data.py +54 -0
  66. oopsie_data_tools/utils/validation/episode_loader.py +201 -0
  67. oopsie_data_tools/utils/validation/episode_validator.py +315 -0
  68. oopsie_data_tools/utils/validation/errors.py +17 -0
  69. oopsie_data_tools/utils/validation/validation_utils.py +88 -0
  70. oopsie_data_tools-0.2.0.dist-info/METADATA +131 -0
  71. oopsie_data_tools-0.2.0.dist-info/RECORD +74 -0
  72. oopsie_data_tools-0.2.0.dist-info/WHEEL +4 -0
  73. oopsie_data_tools-0.2.0.dist-info/entry_points.txt +2 -0
  74. oopsie_data_tools-0.2.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,174 @@
1
+ """Shared pytest fixtures for oopsie_data_tools tests.
2
+
3
+ Session-scoped fixtures generate HDF5 + MP4 files once per test session into a
4
+ pytest-managed temporary directory and are cleaned up automatically at the end.
5
+
6
+ tmp_path_factory (session-scoped) – shared fixtures used across many tests
7
+ tmp_path (function-scoped, built-in) – per-test isolation
8
+
9
+ File generation delegates to the canonical fixture generators so that the
10
+ validator tests always exercise the exact same files as other test modules.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ from pathlib import Path
16
+
17
+ import pytest
18
+
19
+ from oopsie_data_tools.test.fixtures.make_invalid import (
20
+ _MAKERS_SIMPLE,
21
+ _MAKERS_WITH_VIDEO,
22
+ _write_video,
23
+ )
24
+ from oopsie_data_tools.test.fixtures.make_valid import (
25
+ make_failure,
26
+ make_legacy_v1,
27
+ make_multi_camera,
28
+ make_no_annotations,
29
+ make_success,
30
+ make_unannotated,
31
+ write_valid_episode, # re-exported for per-test use in test modules
32
+ )
33
+
34
+ __all__ = ["write_valid_episode"]
35
+
36
+
37
+ @pytest.fixture(autouse=True)
38
+ def _isolate_user_environment(tmp_path_factory, monkeypatch):
39
+ """Keep every test out of the developer's real home, config and working directory.
40
+
41
+ Three confirmed leaks this closes:
42
+
43
+ * ``cli.main`` exports ``$OOPSIE_CONFIG_DIR``. ``monkeypatch.delenv`` records nothing
44
+ when the variable is absent, so there was nothing to undo and the value outlived the
45
+ test that set it, pointing later tests at a deleted directory.
46
+ * ``test_robot_setup`` resolves profiles through the cwd and
47
+ ``$OOPSIE_ROBOT_PROFILES_DIR``, so it failed if either was set, or if pytest ran from
48
+ a directory that happened to contain ``robot_profiles/``.
49
+ * ``init_wizard.advise_persisting_config_dir`` appends an export line to ``~/.zshrc``.
50
+ Nothing stopped that from being the developer's real one.
51
+ """
52
+ home = tmp_path_factory.mktemp("home")
53
+ monkeypatch.setenv("HOME", str(home))
54
+ monkeypatch.setenv("XDG_CONFIG_HOME", str(home / ".config"))
55
+ for var in ("OOPSIE_CONFIG_DIR", "OOPSIE_ROBOT_PROFILES_DIR"):
56
+ # Set before deleting so monkeypatch always has a value to restore, whether or not
57
+ # the variable existed and whatever the test under it does.
58
+ monkeypatch.setenv(var, str(home / "unset"))
59
+ monkeypatch.delenv(var)
60
+ monkeypatch.chdir(tmp_path_factory.mktemp("cwd"))
61
+
62
+
63
+ @pytest.fixture(scope="session", autouse=True)
64
+ def _test_contributor_config():
65
+ """Supply a test lab_id everywhere the contributor config is read.
66
+
67
+ Lets the suite run on a fresh checkout without a filled-in
68
+ ``configs/contributor_config.yaml`` (whose blank lab_id would otherwise fail
69
+ ``EpisodeRecorder`` construction), without touching the committed file.
70
+
71
+ Every module that binds the name at import gets patched: ``hf_upload`` and
72
+ ``init_wizard`` also do ``from ... import read_contributor_config``, so rebinding two
73
+ hand-picked modules left them reading the developer's real config.
74
+ """
75
+ from _pytest.monkeypatch import MonkeyPatch
76
+
77
+ import oopsie_data_tools.annotation_tool.episode_recorder as _recorder
78
+ import oopsie_data_tools.init_wizard as _init_wizard
79
+ import oopsie_data_tools.utils.contributor_config as _cc
80
+ import oopsie_data_tools.utils.hf_upload as _hf_upload
81
+
82
+ def _fake(config_path=None) -> tuple[str, str]:
83
+ return ("test_lab", "test_token")
84
+
85
+ patch = MonkeyPatch()
86
+ for module in (_cc, _recorder, _hf_upload, _init_wizard):
87
+ patch.setattr(module, "read_contributor_config", _fake)
88
+ try:
89
+ yield
90
+ finally:
91
+ patch.undo()
92
+
93
+
94
+ # ---------------------------------------------------------------------------
95
+ # Session-scoped fixtures: valid episodes
96
+ # ---------------------------------------------------------------------------
97
+
98
+
99
+ @pytest.fixture(scope="session")
100
+ def valid_episode(tmp_path_factory) -> Path:
101
+ """Fully valid oopsiedata_format_v1 episode, minimally annotated as a success.
102
+
103
+ It carries an annotation despite ``make_unannotated``'s name: validation through the
104
+ CLI always checks annotations, so a general-purpose "valid episode" must have one.
105
+ """
106
+ d = tmp_path_factory.mktemp("valid")
107
+ make_unannotated(d)
108
+ return d / "episode_unannotated.h5"
109
+
110
+
111
+ @pytest.fixture(scope="session")
112
+ def episode_without_annotations(tmp_path_factory) -> Path:
113
+ """Structurally valid episode with no ``episode_annotations`` group at all."""
114
+ d = tmp_path_factory.mktemp("no_annotations")
115
+ make_no_annotations(d)
116
+ return d / "episode_no_annotations.h5"
117
+
118
+
119
+ @pytest.fixture(scope="session")
120
+ def valid_success_episode(tmp_path_factory) -> Path:
121
+ """Valid episode annotated as success."""
122
+ d = tmp_path_factory.mktemp("valid_success")
123
+ make_success(d)
124
+ return d / "episode_success.h5"
125
+
126
+
127
+ @pytest.fixture(scope="session")
128
+ def valid_failure_episode(tmp_path_factory) -> Path:
129
+ """Valid episode annotated as failure."""
130
+ d = tmp_path_factory.mktemp("valid_failure")
131
+ make_failure(d)
132
+ return d / "episode_failure.h5"
133
+
134
+
135
+ @pytest.fixture(scope="session")
136
+ def legacy_v1_episode(tmp_path_factory) -> Path:
137
+ """Valid episode still carrying the taxonomy v1 annotation schema."""
138
+ d = tmp_path_factory.mktemp("legacy_v1")
139
+ make_legacy_v1(d)
140
+ return d / "episode_legacy_v1.h5"
141
+
142
+
143
+ @pytest.fixture(scope="session")
144
+ def valid_session_dir(tmp_path_factory) -> Path:
145
+ """Session directory containing all four valid episode types."""
146
+ d = tmp_path_factory.mktemp("valid_session")
147
+ make_unannotated(d)
148
+ make_success(d)
149
+ make_failure(d)
150
+ make_multi_camera(d)
151
+ return d
152
+
153
+
154
+ # ---------------------------------------------------------------------------
155
+ # Session-scoped fixture: invalid episodes
156
+ # ---------------------------------------------------------------------------
157
+
158
+
159
+ @pytest.fixture(scope="session")
160
+ def invalid_fixtures(tmp_path_factory) -> dict[str, Path]:
161
+ """Dict mapping fixture stem → Path for every invalid HDF5 file.
162
+
163
+ Generated by the same make_invalid module used for manual inspection,
164
+ so tests and the generator stay in sync automatically.
165
+ """
166
+ d = tmp_path_factory.mktemp("invalid")
167
+
168
+ for maker in _MAKERS_SIMPLE:
169
+ maker(d)
170
+
171
+ for maker in _MAKERS_WITH_VIDEO:
172
+ maker(d, _write_video)
173
+
174
+ return {p.stem: p for p in d.glob("invalid_*.h5")}
File without changes