tamfis-code 0.2.3__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,318 @@
1
+ """
2
+ TAMFIS-CODE Test Enforcer - Properly handles sibling directories
3
+ CWD: /home/tamfisgpt
4
+ - tamgpt6/ (backend, this repo)
5
+ - tamfis-frontend/ (React frontend, sibling)
6
+ """
7
+
8
+ import os
9
+ import sys
10
+ import subprocess
11
+ import json
12
+ import time
13
+ from pathlib import Path
14
+ from datetime import datetime
15
+ from typing import Dict, List, Optional, Any
16
+
17
+ # Import click for CLI integration
18
+ try:
19
+ import click
20
+ except ImportError:
21
+ click = None
22
+
23
+
24
+ class TestEnforcer:
25
+ """Test enforcer that properly handles sibling directories"""
26
+
27
+ def __init__(self):
28
+ self.base = Path("/home/tamfisgpt")
29
+ self.backend = self.base / "tamgpt6"
30
+ self.frontend = self.base / "tamfis-frontend"
31
+ self.results = {
32
+ "timestamp": datetime.now().isoformat(),
33
+ "workspace": str(self.base),
34
+ "backend": str(self.backend),
35
+ "frontend": {
36
+ "exists": self.frontend.exists(),
37
+ "path": str(self.frontend),
38
+ },
39
+ "python": {"tests": [], "summary": {}},
40
+ "node": {"scripts": [], "summary": {}},
41
+ "frontend_tests": {"status": "checking", "results": []},
42
+ }
43
+ self._print = print
44
+
45
+ def _print_progress(self, message: str, status: str = "info", detail: str = ""):
46
+ """Print progress with formatting"""
47
+ emojis = {
48
+ "info": "ℹ️",
49
+ "success": "✅",
50
+ "error": "❌",
51
+ "warning": "⚠️",
52
+ "running": "🔄",
53
+ "python": "🐍",
54
+ "node": "📦",
55
+ "frontend": "🎨",
56
+ "done": "🎉"
57
+ }
58
+ prefix = emojis.get(status, "ℹ️")
59
+ if detail:
60
+ self._print(f"{prefix} {message}\n └─ {detail}")
61
+ else:
62
+ self._print(f"{prefix} {message}")
63
+ sys.stdout.flush()
64
+
65
+ def _run_cmd(self, cmd: List[str], cwd: Optional[Path] = None, timeout: int = 120) -> Dict[str, Any]:
66
+ cwd = cwd or self.backend
67
+ try:
68
+ start = time.time()
69
+ result = subprocess.run(
70
+ cmd,
71
+ cwd=cwd,
72
+ capture_output=True,
73
+ text=True,
74
+ timeout=timeout
75
+ )
76
+ elapsed = time.time() - start
77
+ return {
78
+ "success": result.returncode == 0,
79
+ "returncode": result.returncode,
80
+ "stdout": result.stdout,
81
+ "stderr": result.stderr,
82
+ "elapsed": elapsed,
83
+ "cmd": " ".join(cmd)
84
+ }
85
+ except subprocess.TimeoutExpired:
86
+ return {
87
+ "success": False,
88
+ "error": f"Timeout after {timeout}s",
89
+ "elapsed": timeout,
90
+ "cmd": " ".join(cmd)
91
+ }
92
+ except Exception as e:
93
+ return {
94
+ "success": False,
95
+ "error": str(e),
96
+ "elapsed": 0,
97
+ "cmd": " ".join(cmd)
98
+ }
99
+
100
+ def run(self) -> Dict[str, Any]:
101
+ """Run all enforcements"""
102
+ self._print_progress("=" * 70, "info")
103
+ self._print_progress("🔧 TAMFIS-CODE Test Enforcer", "info")
104
+ self._print_progress("=" * 70, "info")
105
+ self._print_progress(f"📂 Workspace: {self.base}", "info")
106
+ self._print_progress(f"📂 Backend: {self.backend}", "info")
107
+
108
+ # Check frontend
109
+ if self.frontend.exists():
110
+ self._print_progress(f"🎨 Frontend: {self.frontend}", "success")
111
+ self.results["frontend"]["exists"] = True
112
+ else:
113
+ self._print_progress(f"🎨 Frontend: NOT FOUND at {self.frontend}", "error")
114
+ self.results["frontend"]["exists"] = False
115
+
116
+ # Run backend tests
117
+ self._run_backend_tests()
118
+
119
+ # Run frontend tests if it exists
120
+ if self.frontend.exists():
121
+ self._run_frontend_tests()
122
+
123
+ self._generate_summary()
124
+ return self.results
125
+
126
+ def _run_backend_tests(self):
127
+ """Run backend (tamgpt6) tests"""
128
+ self._print_progress("", "info")
129
+ self._print_progress("🐍 Backend Tests (tamgpt6)", "python")
130
+ self._print_progress("-" * 50, "info")
131
+
132
+ test_dir = self.backend / "tests"
133
+ if not test_dir.exists():
134
+ self._print_progress("No tests directory found", "warning")
135
+ return
136
+
137
+ test_files = list(test_dir.glob("test_*.py"))
138
+ self._print_progress(f"📁 Found {len(test_files)} test files", "info")
139
+
140
+ passed = 0
141
+ for test_file in test_files:
142
+ self._print_progress(f"▶️ Running {test_file.name}...", "running")
143
+ result = self._run_cmd(
144
+ [sys.executable, "-m", "pytest", str(test_file), "-v", "--tb=short", "-q"],
145
+ cwd=self.backend,
146
+ timeout=60
147
+ )
148
+ if result["success"]:
149
+ passed += 1
150
+ self._print_progress(f"✅ {test_file.name} PASSED ({result['elapsed']:.2f}s)", "success")
151
+ else:
152
+ self._print_progress(f"❌ {test_file.name} FAILED ({result['elapsed']:.2f}s)", "error")
153
+ error_lines = [l for l in result["stdout"].split('\n') if 'FAILED' in l or 'ERROR' in l]
154
+ for line in error_lines[:3]:
155
+ self._print_progress(f" └─ {line.strip()}", "error")
156
+
157
+ self.results["python"]["summary"]["total"] = len(test_files)
158
+ self.results["python"]["summary"]["passed"] = passed
159
+ self._print_progress(f"📊 Summary: {passed}/{len(test_files)} test files passed",
160
+ "success" if passed == len(test_files) else "warning")
161
+
162
+ def _run_frontend_tests(self):
163
+ """Run frontend (tamfis-frontend) tests - ACTUALLY access the sibling directory"""
164
+ self._print_progress("", "info")
165
+ self._print_progress("🎨 Frontend Tests (tamfis-frontend)", "frontend")
166
+ self._print_progress("-" * 50, "info")
167
+
168
+ if not self.frontend.exists():
169
+ self._print_progress("❌ Frontend directory not found", "error")
170
+ return
171
+
172
+ # List what's in the frontend directory
173
+ self._print_progress(f"📁 Checking frontend at: {self.frontend}", "info")
174
+ try:
175
+ files = list(self.frontend.iterdir())
176
+ self._print_progress(f"📁 Found {len(files)} items in frontend", "info")
177
+ for f in files[:10]:
178
+ self._print_progress(f" └─ {f.name}", "info")
179
+ except Exception as e:
180
+ self._print_progress(f"❌ Cannot read frontend directory: {e}", "error")
181
+ return
182
+
183
+ # Check package.json
184
+ pkg_file = self.frontend / "package.json"
185
+ if not pkg_file.exists():
186
+ self._print_progress("❌ No package.json found in frontend!", "error")
187
+ self.results["frontend_tests"]["status"] = "no_package"
188
+ return
189
+
190
+ self._print_progress("✅ package.json found!", "success")
191
+
192
+ # Read package.json
193
+ import json
194
+ with open(pkg_file) as f:
195
+ pkg = json.load(f)
196
+ scripts = pkg.get("scripts", {})
197
+ self._print_progress(f"📁 Found {len(scripts)} scripts in package.json", "info")
198
+ for script in scripts:
199
+ self._print_progress(f" └─ {script}: {scripts[script][:50]}...", "info")
200
+
201
+ # Check npm
202
+ npm_check = self._run_cmd(["npm", "--version"], cwd=self.frontend)
203
+ if not npm_check["success"]:
204
+ self._print_progress("❌ npm not available", "error")
205
+ self.results["frontend_tests"]["status"] = "no_npm"
206
+ return
207
+ self._print_progress(f"✅ npm {npm_check['stdout'].strip()} available", "success")
208
+
209
+ # Install dependencies if needed
210
+ node_modules = self.frontend / "node_modules"
211
+ if not node_modules.exists():
212
+ self._print_progress("📦 Installing npm dependencies... (this may take a while)", "running")
213
+ result = self._run_cmd(["npm", "install"], cwd=self.frontend, timeout=300)
214
+ if result["success"]:
215
+ self._print_progress("✅ Dependencies installed", "success")
216
+ else:
217
+ self._print_progress("❌ Dependency installation failed", "error")
218
+ self.results["frontend_tests"]["status"] = "install_failed"
219
+ return
220
+
221
+ # Run test scripts
222
+ test_scripts = ["test", "test:unit", "test:integration", "build", "typecheck", "dev"]
223
+ available = [s for s in test_scripts if s in scripts]
224
+
225
+ if not available:
226
+ self._print_progress("No test scripts found in package.json", "warning")
227
+ self.results["frontend_tests"]["status"] = "no_scripts"
228
+ return
229
+
230
+ self._print_progress(f"📁 Found {len(available)} scripts to run", "info")
231
+
232
+ results = []
233
+ for script in available:
234
+ self._print_progress(f"▶️ Running npm {script}...", "running")
235
+ result = self._run_cmd(["npm", "run", script], cwd=self.frontend, timeout=120)
236
+ if result["success"]:
237
+ self._print_progress(f"✅ npm {script} PASSED ({result['elapsed']:.2f}s)", "success")
238
+ else:
239
+ self._print_progress(f"❌ npm {script} FAILED ({result['elapsed']:.2f}s)", "error")
240
+ if result.get("stderr"):
241
+ error_lines = [l for l in result["stderr"].split('\n') if l.strip()]
242
+ for line in error_lines[:2]:
243
+ self._print_progress(f" └─ {line.strip()[:100]}", "error")
244
+ results.append({
245
+ "script": script,
246
+ "passed": result["success"],
247
+ "elapsed": result.get("elapsed", 0)
248
+ })
249
+
250
+ self.results["frontend_tests"]["results"] = results
251
+ self.results["frontend_tests"]["status"] = "done"
252
+
253
+ passed = sum(1 for r in results if r["passed"])
254
+ total = len(results)
255
+ self._print_progress(f"📊 Frontend Summary: {passed}/{total} scripts passed",
256
+ "success" if passed == total else "warning")
257
+
258
+ def _generate_summary(self):
259
+ """Generate summary"""
260
+ self._print_progress("", "info")
261
+ self._print_progress("=" * 70, "info")
262
+ self._print_progress("📊 TEST ENFORCEMENT SUMMARY", "info")
263
+ self._print_progress("=" * 70, "info")
264
+
265
+ # Backend Python
266
+ py = self.results["python"]["summary"]
267
+ if py.get("total", 0) > 0:
268
+ passed = py.get("passed", 0)
269
+ total = py.get("total", 0)
270
+ self._print_progress(f"🐍 Backend: {passed}/{total} tests passed",
271
+ "success" if passed == total else "warning")
272
+
273
+ # Frontend
274
+ fe = self.results["frontend_tests"]
275
+ if fe.get("results"):
276
+ passed = sum(1 for r in fe["results"] if r["passed"])
277
+ total = len(fe["results"])
278
+ self._print_progress(f"🎨 Frontend: {passed}/{total} scripts passed",
279
+ "success" if passed == total else "warning")
280
+ else:
281
+ self._print_progress(f"🎨 Frontend: {fe.get('status', 'unknown')}", "warning")
282
+
283
+ self._print_progress("=" * 70, "info")
284
+ self._print_progress("✅ Test enforcement completed!", "success")
285
+
286
+
287
+ def run_enforcer():
288
+ """Run the test enforcer"""
289
+ enforcer = TestEnforcer()
290
+ return enforcer.run()
291
+
292
+
293
+ def add_enforcer_command(cli):
294
+ """Add enforcer command to CLI"""
295
+ if click is None:
296
+ return cli
297
+
298
+ @cli.command('enforce')
299
+ @click.option('--python', '-p', is_flag=True, help='Only run Python tests')
300
+ @click.option('--node', '-n', is_flag=True, help='Only run Node.js tests')
301
+ @click.option('--frontend', '-f', is_flag=True, help='Only run frontend tests')
302
+ def enforce_cmd(python: bool, node: bool, frontend: bool):
303
+ """Enforce and run all tests with real-time progress"""
304
+ enforcer = TestEnforcer()
305
+
306
+ if python:
307
+ enforcer._run_backend_tests()
308
+ elif node:
309
+ # Run node tests (which is actually frontend)
310
+ enforcer._run_frontend_tests()
311
+ elif frontend:
312
+ enforcer._run_frontend_tests()
313
+ else:
314
+ enforcer.run()
315
+
316
+ print("\n✅ Test enforcement completed!")
317
+
318
+ return cli