atdd 0.4.5__py3-none-any.whl → 0.4.7__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.
@@ -0,0 +1,282 @@
1
+ """
2
+ Tester validators: Train frontend Python (Streamlit) convention validation.
3
+
4
+ Train First-Class Spec v0.6 Section 8: Frontend Python Conventions
5
+
6
+ Validates:
7
+ - SPEC-TRAIN-VAL-0029: Frontend Python code paths
8
+ - SPEC-TRAIN-VAL-0030: Frontend Python test paths
9
+
10
+ Frontend Python (Streamlit) should follow:
11
+ - Code paths: python/streamlit/ or python/apps/
12
+ - Test paths: python/tests/streamlit/test_<train_id>[_<slug>].py
13
+ """
14
+
15
+ import pytest
16
+ import re
17
+ from pathlib import Path
18
+ from typing import Dict, List, Tuple
19
+
20
+ import atdd
21
+ from atdd.coach.utils.repo import find_repo_root
22
+ from atdd.coach.utils.train_spec_phase import (
23
+ TrainSpecPhase,
24
+ should_enforce,
25
+ emit_phase_warning
26
+ )
27
+
28
+
29
+ # Path constants
30
+ REPO_ROOT = find_repo_root()
31
+ PYTHON_DIR = REPO_ROOT / "python"
32
+ STREAMLIT_DIR = PYTHON_DIR / "streamlit"
33
+ APPS_DIR = PYTHON_DIR / "apps"
34
+ STREAMLIT_TESTS_DIR = PYTHON_DIR / "tests" / "streamlit"
35
+
36
+ # Package resources
37
+ ATDD_PKG_DIR = Path(atdd.__file__).resolve().parent
38
+
39
+
40
+ def _get_trains_with_frontend_python() -> List[str]:
41
+ """
42
+ Get train IDs that expect frontend_python implementation.
43
+
44
+ Returns:
45
+ List of train_id strings
46
+ """
47
+ import yaml
48
+
49
+ train_ids = []
50
+ trains_registry_path = REPO_ROOT / "plan" / "_trains.yaml"
51
+
52
+ if not trains_registry_path.exists():
53
+ return train_ids
54
+
55
+ with open(trains_registry_path) as f:
56
+ data = yaml.safe_load(f)
57
+
58
+ trains_dir = REPO_ROOT / "plan" / "_trains"
59
+
60
+ for theme_key, categories in data.get("trains", {}).items():
61
+ if isinstance(categories, dict):
62
+ for category_key, trains_list in categories.items():
63
+ if isinstance(trains_list, list):
64
+ for train in trains_list:
65
+ train_id = train.get("train_id")
66
+ if not train_id:
67
+ continue
68
+
69
+ # Check expectations in registry
70
+ expectations = train.get("expectations", {})
71
+ if expectations.get("frontend_python"):
72
+ train_ids.append(train_id)
73
+ continue
74
+
75
+ # Check YAML file for expectations
76
+ train_file = trains_dir / f"{train_id}.yaml"
77
+ if train_file.exists():
78
+ try:
79
+ with open(train_file) as tf:
80
+ train_data = yaml.safe_load(tf)
81
+ yaml_expectations = train_data.get("expectations", {})
82
+ if yaml_expectations.get("frontend_python"):
83
+ train_ids.append(train_id)
84
+ except Exception:
85
+ pass
86
+
87
+ return train_ids
88
+
89
+
90
+ def _find_frontend_python_code_files() -> List[Path]:
91
+ """
92
+ Find all frontend Python code files.
93
+
94
+ Returns:
95
+ List of paths to .py files in streamlit/ or apps/ directories
96
+ """
97
+ files = []
98
+
99
+ for search_dir in [STREAMLIT_DIR, APPS_DIR]:
100
+ if search_dir.exists():
101
+ for py_file in search_dir.rglob("*.py"):
102
+ if not py_file.name.startswith("_"):
103
+ files.append(py_file)
104
+
105
+ return files
106
+
107
+
108
+ def _find_frontend_python_test_files() -> List[Tuple[Path, str]]:
109
+ """
110
+ Find all frontend Python test files.
111
+
112
+ Returns:
113
+ List of (path, train_id_from_filename) tuples
114
+ """
115
+ tests = []
116
+
117
+ if not STREAMLIT_TESTS_DIR.exists():
118
+ return tests
119
+
120
+ # Pattern: test_<train_id>*.py
121
+ for test_file in STREAMLIT_TESTS_DIR.glob("test_*.py"):
122
+ filename = test_file.stem
123
+ match = re.match(r"test_(\d{4}-[a-z0-9-]+)", filename)
124
+ if match:
125
+ train_id = match.group(1)
126
+ tests.append((test_file, train_id))
127
+
128
+ return tests
129
+
130
+
131
+ def _check_train_code_references(train_id: str) -> List[Path]:
132
+ """
133
+ Find code files that reference a specific train.
134
+
135
+ Returns:
136
+ List of paths that contain train_id reference
137
+ """
138
+ matching_files = []
139
+
140
+ for search_dir in [STREAMLIT_DIR, APPS_DIR]:
141
+ if not search_dir.exists():
142
+ continue
143
+
144
+ for py_file in search_dir.rglob("*.py"):
145
+ try:
146
+ with open(py_file, 'r', encoding='utf-8') as f:
147
+ content = f.read()
148
+
149
+ # Check for train_id in file
150
+ if train_id in content:
151
+ matching_files.append(py_file)
152
+
153
+ except Exception:
154
+ pass
155
+
156
+ return matching_files
157
+
158
+
159
+ # ============================================================================
160
+ # FRONTEND PYTHON VALIDATORS
161
+ # ============================================================================
162
+
163
+
164
+ @pytest.mark.platform
165
+ def test_frontend_python_code_paths():
166
+ """
167
+ SPEC-TRAIN-VAL-0029: Frontend Python code in allowed paths
168
+
169
+ Given: Trains expecting frontend_python implementation
170
+ When: Checking code locations
171
+ Then: Code is in python/streamlit/ or python/apps/
172
+
173
+ Section 8: Frontend Python Code Paths
174
+ """
175
+ trains_with_frontend_python = _get_trains_with_frontend_python()
176
+
177
+ if not trains_with_frontend_python:
178
+ pytest.skip("No trains expecting frontend_python implementation")
179
+
180
+ code_files = _find_frontend_python_code_files()
181
+
182
+ if not code_files:
183
+ if should_enforce(TrainSpecPhase.FULL_ENFORCEMENT):
184
+ pytest.fail(
185
+ f"Trains expect frontend_python but no code found in python/streamlit/ or python/apps/:\n"
186
+ f" Trains: {trains_with_frontend_python}"
187
+ )
188
+ else:
189
+ emit_phase_warning(
190
+ "SPEC-TRAIN-VAL-0029",
191
+ f"{len(trains_with_frontend_python)} trains expect frontend_python but no code found",
192
+ TrainSpecPhase.FULL_ENFORCEMENT
193
+ )
194
+ return
195
+
196
+ # Check that trains with expectations have corresponding code
197
+ missing_code = []
198
+ for train_id in trains_with_frontend_python:
199
+ refs = _check_train_code_references(train_id)
200
+ if not refs:
201
+ missing_code.append(f"{train_id}: no code references found")
202
+
203
+ if missing_code:
204
+ if should_enforce(TrainSpecPhase.FULL_ENFORCEMENT):
205
+ pytest.fail(
206
+ f"Trains missing frontend_python code:\n " + "\n ".join(missing_code) +
207
+ "\n\nExpected code in: python/streamlit/ or python/apps/"
208
+ )
209
+ else:
210
+ for missing in missing_code:
211
+ emit_phase_warning(
212
+ "SPEC-TRAIN-VAL-0029",
213
+ missing,
214
+ TrainSpecPhase.FULL_ENFORCEMENT
215
+ )
216
+
217
+
218
+ @pytest.mark.platform
219
+ def test_frontend_python_test_paths():
220
+ """
221
+ SPEC-TRAIN-VAL-0030: Frontend Python tests in correct location
222
+
223
+ Given: Frontend Python test files
224
+ When: Checking test paths
225
+ Then: Path follows python/tests/streamlit/test_<train_id>[_<slug>].py
226
+
227
+ Section 8: Frontend Python Test Paths
228
+ """
229
+ trains_with_frontend_python = _get_trains_with_frontend_python()
230
+
231
+ if not trains_with_frontend_python:
232
+ pytest.skip("No trains expecting frontend_python implementation")
233
+
234
+ test_files = _find_frontend_python_test_files()
235
+
236
+ # Check that tests exist for trains that expect frontend_python
237
+ train_ids_with_tests = {train_id for _, train_id in test_files}
238
+
239
+ missing_tests = []
240
+ for train_id in trains_with_frontend_python:
241
+ if train_id not in train_ids_with_tests:
242
+ missing_tests.append(
243
+ f"{train_id}: missing test at python/tests/streamlit/test_{train_id}.py"
244
+ )
245
+
246
+ if missing_tests:
247
+ if should_enforce(TrainSpecPhase.FULL_ENFORCEMENT):
248
+ pytest.fail(
249
+ f"Trains missing frontend_python tests:\n " + "\n ".join(missing_tests) +
250
+ "\n\nExpected: python/tests/streamlit/test_<train_id>[_<slug>].py"
251
+ )
252
+ else:
253
+ for missing in missing_tests:
254
+ emit_phase_warning(
255
+ "SPEC-TRAIN-VAL-0030",
256
+ missing,
257
+ TrainSpecPhase.FULL_ENFORCEMENT
258
+ )
259
+
260
+ # Validate existing test file naming
261
+ invalid_tests = []
262
+ all_train_ids = set(trains_with_frontend_python)
263
+
264
+ for test_path, train_id in test_files:
265
+ if train_id not in all_train_ids:
266
+ rel_path = test_path.relative_to(REPO_ROOT)
267
+ invalid_tests.append(
268
+ f"{rel_path}: train_id '{train_id}' not in trains expecting frontend_python"
269
+ )
270
+
271
+ if invalid_tests:
272
+ if should_enforce(TrainSpecPhase.FULL_ENFORCEMENT):
273
+ pytest.fail(
274
+ f"Frontend Python test path issues:\n " + "\n ".join(invalid_tests)
275
+ )
276
+ else:
277
+ for invalid in invalid_tests:
278
+ emit_phase_warning(
279
+ "SPEC-TRAIN-VAL-0030",
280
+ invalid,
281
+ TrainSpecPhase.FULL_ENFORCEMENT
282
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: atdd
3
- Version: 0.4.5
3
+ Version: 0.4.7
4
4
  Summary: ATDD Platform - Acceptance Test Driven Development toolkit
5
5
  License: MIT
6
6
  Requires-Python: >=3.10
@@ -1,6 +1,6 @@
1
1
  atdd/__init__.py,sha256=-S8i9OahH-t9FJkPn6nprxipnjVum3rLeVsCS74T6eY,156
2
2
  atdd/__main__.py,sha256=B0sXDQLjFN9GowTlXo4NMWwPZPjDsrT8Frq7DnbdOD8,77
3
- atdd/cli.py,sha256=NlhWL8sRLBzISgyn2KM-KT_aYnMBHt_xNP3TqfMHIhA,20364
3
+ atdd/cli.py,sha256=5O5IazSmlAPyIDmtOXE1Wi7RT_-FmtagkzETmPszE9E,22506
4
4
  atdd/conftest.py,sha256=Fj3kIhCETbj2QBCIjySBgdS3stKNRZcZzKTJr7A4LaQ,5300
5
5
  atdd/version_check.py,sha256=BlPcLwzNnm457vWUolB3wMtZEI-fXvpzfm6p8U_j7rc,6684
6
6
  atdd/coach/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -12,9 +12,9 @@ atdd/coach/commands/gate.py,sha256=_V2GypqoGixTs_kLWxFF3HgEt-Wi2r6Iv0YL75yWrWo,5
12
12
  atdd/coach/commands/infer_governance_status.py,sha256=MlLnx8SrJAOQq2rfuxLZMmyNylCQ-OYx4tSi_iFdhRA,4504
13
13
  atdd/coach/commands/initializer.py,sha256=wuvzj7QwA11ilNjRZU6Bx2bLQXITdBHJxR9_mZK7xjA,6503
14
14
  atdd/coach/commands/interface.py,sha256=FwBrJpWkfSL9n4n0HT_EC-alseXgU0bweKD4TImyHN0,40483
15
- atdd/coach/commands/inventory.py,sha256=qU42MnkXt1JSBh5GU7pPSKmCO27Zfga7XwMT19RquJE,20969
15
+ atdd/coach/commands/inventory.py,sha256=7Znpx2mFh3rQXEguUzIaBage3B5m1L_K2esYyd3pfLY,24764
16
16
  atdd/coach/commands/migration.py,sha256=wRxU7emvvHqWt1MvXKkNTkPBjp0sU9g8F5Uy5yV2YfI,8177
17
- atdd/coach/commands/registry.py,sha256=76-Pe3_cN483JR1pXUdDIE5WSZjWtVV0Jl8dRtRw_9Y,58349
17
+ atdd/coach/commands/registry.py,sha256=9iWW34CCJAr36v91863u8TDdlGQJdLpYYBGb1ojtS1Q,71546
18
18
  atdd/coach/commands/session.py,sha256=MhuWXd5TR6bB3w0t8vANeZx3L476qwLT6EUQMwg-wQA,14268
19
19
  atdd/coach/commands/sync.py,sha256=SLNzhcc6IuzMofMbkH9wM9rBSk5tPfcWPKXn9TaSZ-Y,13782
20
20
  atdd/coach/commands/test_interface.py,sha256=a7ut2Hhk0PnQ5LfJZkoQwfkfkVuB5OHA4QBwOS0-jcg,16870
@@ -30,16 +30,19 @@ atdd/coach/schemas/manifest.schema.json,sha256=WO13-YF_FgH1awh96khCtk-112b6XSC24
30
30
  atdd/coach/templates/ATDD.md,sha256=MLbrVbCETJre4c05d5FXGuf6W95Hz9E0jpE4RI9r4cg,13237
31
31
  atdd/coach/templates/SESSION-TEMPLATE.md,sha256=cGT_0x5KLbPHOCiuM8evLGpWKIlR-aggqxiBtbjSJoo,9478
32
32
  atdd/coach/utils/__init__.py,sha256=7Jbo-heJEKSAn6I0s35z_2S4R8qGZ48PL6a2IntcNYg,148
33
+ atdd/coach/utils/config.py,sha256=6XXaaeVfjTrJwdaR0IZ6Kf1-1ZHhaCVLO5pNx_A2el4,3320
33
34
  atdd/coach/utils/repo.py,sha256=0kiF5WpVTen0nO14u5T0RflznZhgGco2i9CwKobOh38,3757
35
+ atdd/coach/utils/train_spec_phase.py,sha256=Mk8CiMoO6jb-VGttHgI20KIG26r9cjSz4gDfk01q1M0,3025
34
36
  atdd/coach/utils/graph/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
35
37
  atdd/coach/utils/graph/urn.py,sha256=O2AHIB_CmmMUvXzyejc_oFReNW_rOcw7m4qaqSYcnNQ,33558
36
38
  atdd/coach/validators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
37
- atdd/coach/validators/shared_fixtures.py,sha256=tdqAb4675P-oOCL08mvSCG9XpmwMCjL9iSq1W5U7-wk,12558
39
+ atdd/coach/validators/shared_fixtures.py,sha256=AUb-387kEc584umEzG_TnzEzcHkYignrobkgrRcQOso,14518
38
40
  atdd/coach/validators/test_enrich_wagon_registry.py,sha256=WeTwYJqoNY6mEYc-QAvQo7YVagSOjaNKxB6Q6dpWqIM,6561
39
41
  atdd/coach/validators/test_registry.py,sha256=ffN70yA_1xxL3R8gdpGbY2M8dQXyuajIZhBZ-ylNiNs,17845
40
42
  atdd/coach/validators/test_release_versioning.py,sha256=B40DfbtrSGguPc537zXmjT75hhySfocWLzJWqOKZQcU,5678
41
43
  atdd/coach/validators/test_session_validation.py,sha256=0VszXtFwRTO04b5CxDPO3klk0VfiqlpdbNpshjMn-qU,39079
42
44
  atdd/coach/validators/test_traceability.py,sha256=qTyobt41VBiCr6xRN2C7BPtGYvk_2poVQIe814Blt8E,15977
45
+ atdd/coach/validators/test_train_registry.py,sha256=YDnmC1MP4TfAMZzyldh0hfHMo7LY27DZ2GXmhQx7vds,6021
43
46
  atdd/coach/validators/test_update_feature_paths.py,sha256=zOKVDgEIpncSJwDh_shyyou5Pu-Ai7Z_XgF8zAbQVTA,4528
44
47
  atdd/coach/validators/test_validate_contract_consumers.py,sha256=b01yam_GwAERF6YaFmUV6Bd7SNMWQkUKBfNVvplbEcU,12613
45
48
  atdd/coder/__init__.py,sha256=Rmi5S7Pzx7qsRe5MC66GduNGmkssWWnElkVvvNHFDgU,45
@@ -84,7 +87,7 @@ atdd/coder/validators/test_presentation_convention.py,sha256=ceAtg_sTEJiPkHVfnwB
84
87
  atdd/coder/validators/test_python_architecture.py,sha256=USnSujKVu7_BC2ij-pTSHyiFi4iBMBemIPR7oXYQ3B4,25243
85
88
  atdd/coder/validators/test_quality_metrics.py,sha256=vLWPfL0x9sfCvKXO4uECW61RnJTsjbmuEUjCsBcUmuA,12551
86
89
  atdd/coder/validators/test_station_master_pattern.py,sha256=biYwXAftpXdhIhDjn2RrVTdEdvTWPW5ddm2gQubJBXQ,9280
87
- atdd/coder/validators/test_train_infrastructure.py,sha256=e9oyWjGR7YoEQZPza8xHzLHN-wrqiJTbNc9Y0BLlGLw,16201
90
+ atdd/coder/validators/test_train_infrastructure.py,sha256=CXOSn_CPk3wJhEVNYztSdiV_ecIgnJkulD-xWivregE,24424
88
91
  atdd/coder/validators/test_train_urns.py,sha256=TvSNHbvG8SAtAPaS2K8mMgzE8GbJtrTaF4iEgkJEIIk,10099
89
92
  atdd/coder/validators/test_typescript_architecture.py,sha256=gi76IwlqX_MpWsr8CXWH7v16KAoud-1OY92iuN-0BpU,22176
90
93
  atdd/coder/validators/test_usecase_structure.py,sha256=nAeqmLWRCstXT8fDuxqk6iVcH4TLHjTvlaGDpanD9sM,14077
@@ -105,7 +108,7 @@ atdd/planner/schemas/acceptance.schema.json,sha256=3mQV067ipiYsTcXkDll4zWJBYdOkB
105
108
  atdd/planner/schemas/appendix.schema.json,sha256=aMqKIwHAgEoO49v8O8isyP1S3oTNCCEeIX3gNmge3TY,2885
106
109
  atdd/planner/schemas/component.schema.json,sha256=B-RgVUmG02T8j0jL1FjAPhVSIGiditJ0UsILNxYXElQ,3891
107
110
  atdd/planner/schemas/feature.schema.json,sha256=wZAIzroUv74iAS2tzIDPhWu2EIDMSRtzsMj5mAfLVdY,7228
108
- atdd/planner/schemas/train.schema.json,sha256=pk5-AjqH6kerfPVOGhCF5Fe5k797s3xxrRJBrN0nb2k,5750
111
+ atdd/planner/schemas/train.schema.json,sha256=YU58Pc_EuhwUR0tuwyXWOQBeKei0TsB4wkRLNcyE0Ig,9877
109
112
  atdd/planner/schemas/wagon.schema.json,sha256=Vy9QCd7aN9yUS5hTPv0XiZ_vw4MEWeDfvCW7jr9Dn6o,11699
110
113
  atdd/planner/schemas/wmbt.schema.json,sha256=KU_D6r0kQTJod-XHQT5QiiHcUUPJrLgg3aPeZdrRBUU,2298
111
114
  atdd/planner/validators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -115,7 +118,7 @@ atdd/planner/validators/test_plan_cross_refs.py,sha256=kxlq1uZ2u4mn3r8wHJjXVJsB8
115
118
  atdd/planner/validators/test_plan_uniqueness.py,sha256=rlC5khAoBkgpTZJdyHi1JbDUj14v1JiGBFv2iV_AP_Y,7735
116
119
  atdd/planner/validators/test_plan_urn_resolution.py,sha256=GoxFiRjOfp69FUmIyKGnsGgpYalOz3qfp6qjyCkga44,9440
117
120
  atdd/planner/validators/test_plan_wagons.py,sha256=l4jbHf9Kg-Fy8Gz5O8BO7PDQKbbeLN0uctoErPK_YKI,7357
118
- atdd/planner/validators/test_train_validation.py,sha256=KsAMxtuyipHse02x91k4rLWUxRiHW29sYBWZ6KNbfJ4,16870
121
+ atdd/planner/validators/test_train_validation.py,sha256=7vlu3P8PenWgZhZCf9kO0UTM-k1n37Ds_jUvrJa-Np0,39264
119
122
  atdd/planner/validators/test_wagon_urn_chain.py,sha256=KY_0vrj6CoiQJ80WbqfCGCYbup13cVssaxbNO0eVf74,26697
120
123
  atdd/planner/validators/test_wmbt_consistency.py,sha256=jdfu4xWEozzBGwplKDXxuDQNLBDxB_AC96NHLkyHqQ8,10875
121
124
  atdd/planner/validators/test_wmbt_vocabulary.py,sha256=PCivTzV7ntlZBa-PVzpBwEiKqLumsEZXfj1r2xl9usM,18803
@@ -180,11 +183,14 @@ atdd/tester/validators/test_red_layer_validation.py,sha256=otqohLMayIK4nPPF2fl-O
180
183
  atdd/tester/validators/test_red_python_layer_structure.py,sha256=5p6mTieijO7MpZGuVODYm9acKkMJ1XeMYDZ3gxPGW0k,3467
181
184
  atdd/tester/validators/test_red_supabase_layer_structure.py,sha256=zbUjsMWSJE1MPnLQx6Hk2lvMgNmMVUKq8a0rwKnp7Lo,3836
182
185
  atdd/tester/validators/test_telemetry_structure.py,sha256=uU5frZnxSlOn60iHyqhe7Pg9b0wrOV7N14D4S6Aw6TE,22626
186
+ atdd/tester/validators/test_train_backend_e2e.py,sha256=Yx75JMjUgf86XTqeuc0k8yT41XuIquo05h2ce3lNb2w,10950
187
+ atdd/tester/validators/test_train_frontend_e2e.py,sha256=fpfUwTbAWzuqxbVKoaFw-ab4e3puK-uLC-ahf1jYgk8,8469
188
+ atdd/tester/validators/test_train_frontend_python.py,sha256=KK2U3oNFWLyBK7YHC0fU7shR05k93gVcO762AI8Q3pw,9018
183
189
  atdd/tester/validators/test_typescript_test_naming.py,sha256=E-TyGv_GVlTfsbyuxrtv9sOWSZS_QcpH6rrJFbWoeeU,11280
184
190
  atdd/tester/validators/test_typescript_test_structure.py,sha256=eV89SD1RaKtchBZupqhnJmaruoROosf3LwB4Fwe4UJI,2612
185
- atdd-0.4.5.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
186
- atdd-0.4.5.dist-info/METADATA,sha256=tMR-3urPv4DOZPD6Mx-9e94DMpuxX8DMhmNymzr9XQ0,8716
187
- atdd-0.4.5.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
188
- atdd-0.4.5.dist-info/entry_points.txt,sha256=-C3yrA1WQQfN3iuGmSzPapA5cKVBEYU5Q1HUffSJTbY,38
189
- atdd-0.4.5.dist-info/top_level.txt,sha256=VKkf6Uiyrm4RS6ULCGM-v8AzYN8K2yg8SMqwJLoO-xs,5
190
- atdd-0.4.5.dist-info/RECORD,,
191
+ atdd-0.4.7.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
192
+ atdd-0.4.7.dist-info/METADATA,sha256=9kcgwnLFKtRapPjpY7J9n1UBjq8kOmS27bqdvr0_iek,8716
193
+ atdd-0.4.7.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
194
+ atdd-0.4.7.dist-info/entry_points.txt,sha256=-C3yrA1WQQfN3iuGmSzPapA5cKVBEYU5Q1HUffSJTbY,38
195
+ atdd-0.4.7.dist-info/top_level.txt,sha256=VKkf6Uiyrm4RS6ULCGM-v8AzYN8K2yg8SMqwJLoO-xs,5
196
+ atdd-0.4.7.dist-info/RECORD,,
File without changes