python2mobile 1.0.1__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 (50) hide show
  1. examples/example_ecommerce_app.py +189 -0
  2. examples/example_todo_app.py +159 -0
  3. p2m/__init__.py +31 -0
  4. p2m/cli.py +470 -0
  5. p2m/config.py +205 -0
  6. p2m/core/__init__.py +18 -0
  7. p2m/core/api.py +191 -0
  8. p2m/core/ast_walker.py +171 -0
  9. p2m/core/database.py +192 -0
  10. p2m/core/events.py +56 -0
  11. p2m/core/render_engine.py +597 -0
  12. p2m/core/runtime.py +128 -0
  13. p2m/core/state.py +51 -0
  14. p2m/core/validator.py +284 -0
  15. p2m/devserver/__init__.py +9 -0
  16. p2m/devserver/server.py +84 -0
  17. p2m/i18n/__init__.py +7 -0
  18. p2m/i18n/translator.py +74 -0
  19. p2m/imagine/__init__.py +35 -0
  20. p2m/imagine/agent.py +463 -0
  21. p2m/imagine/legacy.py +217 -0
  22. p2m/llm/__init__.py +20 -0
  23. p2m/llm/anthropic_provider.py +78 -0
  24. p2m/llm/base.py +42 -0
  25. p2m/llm/compatible_provider.py +120 -0
  26. p2m/llm/factory.py +72 -0
  27. p2m/llm/ollama_provider.py +89 -0
  28. p2m/llm/openai_provider.py +79 -0
  29. p2m/testing/__init__.py +41 -0
  30. p2m/ui/__init__.py +43 -0
  31. p2m/ui/components.py +301 -0
  32. python2mobile-1.0.1.dist-info/METADATA +238 -0
  33. python2mobile-1.0.1.dist-info/RECORD +50 -0
  34. python2mobile-1.0.1.dist-info/WHEEL +5 -0
  35. python2mobile-1.0.1.dist-info/entry_points.txt +2 -0
  36. python2mobile-1.0.1.dist-info/top_level.txt +3 -0
  37. tests/test_basic_engine.py +281 -0
  38. tests/test_build_generation.py +603 -0
  39. tests/test_build_test_gate.py +150 -0
  40. tests/test_carousel_modal.py +84 -0
  41. tests/test_config_system.py +272 -0
  42. tests/test_i18n.py +101 -0
  43. tests/test_ifood_app_integration.py +172 -0
  44. tests/test_imagine_cli.py +133 -0
  45. tests/test_imagine_command.py +341 -0
  46. tests/test_llm_providers.py +321 -0
  47. tests/test_new_apps_integration.py +588 -0
  48. tests/test_ollama_functional.py +329 -0
  49. tests/test_real_world_apps.py +228 -0
  50. tests/test_run_integration.py +776 -0
@@ -0,0 +1,329 @@
1
+ """
2
+ Functional tests for P2M Imagine with Ollama (qwen3-coder:latest)
3
+ Tests against https://ollama.dataseed.com.br/
4
+ """
5
+
6
+ import sys
7
+ from pathlib import Path
8
+
9
+ # Add project to path
10
+ sys.path.insert(0, str(Path(__file__).parent.parent))
11
+
12
+ from p2m.imagine.legacy import CodeImaginer
13
+
14
+
15
+ # Ollama configuration
16
+ OLLAMA_BASE_URL = "https://ollama.dataseed.com.br"
17
+ OLLAMA_MODEL = "qwen3-coder:latest"
18
+
19
+
20
+ def test_ollama_connection():
21
+ """Test connection to Ollama server"""
22
+ print("\n🧪 Test 1: Ollama Server Connection")
23
+
24
+ imaginer = CodeImaginer(
25
+ provider="ollama",
26
+ model=OLLAMA_MODEL,
27
+ base_url=OLLAMA_BASE_URL
28
+ )
29
+
30
+ valid, msg = imaginer.validate_config()
31
+ assert valid, f"Configuration should be valid: {msg}"
32
+
33
+ success, msg = imaginer.create_provider()
34
+ if not success:
35
+ print(f"⚠️ Cannot connect to Ollama: {msg}")
36
+ print(f" Server: {OLLAMA_BASE_URL}")
37
+ print(f" Model: {OLLAMA_MODEL}")
38
+ return False
39
+
40
+ print(f"✅ Connected to Ollama server")
41
+ print(f" Server: {OLLAMA_BASE_URL}")
42
+ print(f" Model: {OLLAMA_MODEL}")
43
+ return True
44
+
45
+
46
+ def test_hello_world_app():
47
+ """Test generating a simple Hello World app"""
48
+ print("\n🧪 Test 2: Generate Hello World App")
49
+
50
+ imaginer = CodeImaginer(
51
+ provider="ollama",
52
+ model=OLLAMA_MODEL,
53
+ base_url=OLLAMA_BASE_URL
54
+ )
55
+
56
+ valid, msg = imaginer.validate_config()
57
+ if not valid:
58
+ print(f"⚠️ Configuration invalid: {msg}")
59
+ return False
60
+
61
+ success, msg = imaginer.create_provider()
62
+ if not success:
63
+ print(f"⚠️ Cannot create provider: {msg}")
64
+ return False
65
+
66
+ description = "Create a simple Hello World app with a centered text that says 'Hello World' and a button that says 'Click Me'"
67
+ success, code = imaginer.generate_code(description)
68
+
69
+ if not success:
70
+ print(f"❌ Code generation failed: {code}")
71
+ return False
72
+
73
+ print(f"✅ Code generated successfully")
74
+ print(f" Lines of code: {len(code.split(chr(10)))}")
75
+
76
+ # Validate code
77
+ valid, msg = imaginer.validate_code(code)
78
+ if not valid:
79
+ print(f"⚠️ Code validation failed: {msg}")
80
+ print(f"\nGenerated code:\n{code[:500]}...")
81
+ return False
82
+
83
+ print(f"✅ Code validation passed")
84
+ return True
85
+
86
+
87
+ def test_todo_app():
88
+ """Test generating a Todo app"""
89
+ print("\n🧪 Test 3: Generate Todo App")
90
+
91
+ imaginer = CodeImaginer(
92
+ provider="ollama",
93
+ model=OLLAMA_MODEL,
94
+ base_url=OLLAMA_BASE_URL
95
+ )
96
+
97
+ valid, msg = imaginer.validate_config()
98
+ if not valid:
99
+ print(f"⚠️ Configuration invalid: {msg}")
100
+ return False
101
+
102
+ success, msg = imaginer.create_provider()
103
+ if not success:
104
+ print(f"⚠️ Cannot create provider: {msg}")
105
+ return False
106
+
107
+ description = """Create a Todo app with:
108
+ - A title 'My Todo List'
109
+ - An input field to add new todos
110
+ - A button to add todos
111
+ - A list of todos with delete buttons
112
+ - Show count of completed todos"""
113
+
114
+ success, code = imaginer.generate_code(description)
115
+
116
+ if not success:
117
+ print(f"❌ Code generation failed: {code}")
118
+ return False
119
+
120
+ print(f"✅ Code generated successfully")
121
+ print(f" Lines of code: {len(code.split(chr(10)))}")
122
+
123
+ # Validate code
124
+ valid, msg = imaginer.validate_code(code)
125
+ if not valid:
126
+ print(f"⚠️ Code validation failed: {msg}")
127
+ return False
128
+
129
+ print(f"✅ Code validation passed")
130
+ return True
131
+
132
+
133
+ def test_counter_app():
134
+ """Test generating a Counter app"""
135
+ print("\n🧪 Test 4: Generate Counter App")
136
+
137
+ imaginer = CodeImaginer(
138
+ provider="ollama",
139
+ model=OLLAMA_MODEL,
140
+ base_url=OLLAMA_BASE_URL
141
+ )
142
+
143
+ valid, msg = imaginer.validate_config()
144
+ if not valid:
145
+ print(f"⚠️ Configuration invalid: {msg}")
146
+ return False
147
+
148
+ success, msg = imaginer.create_provider()
149
+ if not success:
150
+ print(f"⚠️ Cannot create provider: {msg}")
151
+ return False
152
+
153
+ description = """Create a Counter app with:
154
+ - A large display showing the current count
155
+ - An Increment button (green)
156
+ - A Decrement button (red)
157
+ - A Reset button (gray)
158
+ - Start count at 0"""
159
+
160
+ success, code = imaginer.generate_code(description)
161
+
162
+ if not success:
163
+ print(f"❌ Code generation failed: {code}")
164
+ return False
165
+
166
+ print(f"✅ Code generated successfully")
167
+ print(f" Lines of code: {len(code.split(chr(10)))}")
168
+
169
+ # Validate code
170
+ valid, msg = imaginer.validate_code(code)
171
+ if not valid:
172
+ print(f"⚠️ Code validation failed: {msg}")
173
+ return False
174
+
175
+ print(f"✅ Code validation passed")
176
+ return True
177
+
178
+
179
+ def test_form_app():
180
+ """Test generating a Form app"""
181
+ print("\n🧪 Test 5: Generate Form App")
182
+
183
+ imaginer = CodeImaginer(
184
+ provider="ollama",
185
+ model=OLLAMA_MODEL,
186
+ base_url=OLLAMA_BASE_URL
187
+ )
188
+
189
+ valid, msg = imaginer.validate_config()
190
+ if not valid:
191
+ print(f"⚠️ Configuration invalid: {msg}")
192
+ return False
193
+
194
+ success, msg = imaginer.create_provider()
195
+ if not success:
196
+ print(f"⚠️ Cannot create provider: {msg}")
197
+ return False
198
+
199
+ description = """Create a Contact Form app with:
200
+ - A title 'Contact Us'
201
+ - Input field for name
202
+ - Input field for email
203
+ - Input field for message
204
+ - A submit button
205
+ - Display a success message when submitted"""
206
+
207
+ success, code = imaginer.generate_code(description)
208
+
209
+ if not success:
210
+ print(f"❌ Code generation failed: {code}")
211
+ return False
212
+
213
+ print(f"✅ Code generated successfully")
214
+ print(f" Lines of code: {len(code.split(chr(10)))}")
215
+
216
+ # Validate code
217
+ valid, msg = imaginer.validate_code(code)
218
+ if not valid:
219
+ print(f"⚠️ Code validation failed: {msg}")
220
+ return False
221
+
222
+ print(f"✅ Code validation passed")
223
+ return True
224
+
225
+
226
+ def test_dashboard_app():
227
+ """Test generating a Dashboard app"""
228
+ print("\n🧪 Test 6: Generate Dashboard App")
229
+
230
+ imaginer = CodeImaginer(
231
+ provider="ollama",
232
+ model=OLLAMA_MODEL,
233
+ base_url=OLLAMA_BASE_URL
234
+ )
235
+
236
+ valid, msg = imaginer.validate_config()
237
+ if not valid:
238
+ print(f"⚠️ Configuration invalid: {msg}")
239
+ return False
240
+
241
+ success, msg = imaginer.create_provider()
242
+ if not success:
243
+ print(f"⚠️ Cannot create provider: {msg}")
244
+ return False
245
+
246
+ description = """Create a Dashboard app with:
247
+ - A header with title 'Dashboard'
248
+ - Three cards showing:
249
+ - Users: 1,234
250
+ - Orders: 567
251
+ - Revenue: $89,012
252
+ - A refresh button
253
+ - Use different colors for each card"""
254
+
255
+ success, code = imaginer.generate_code(description)
256
+
257
+ if not success:
258
+ print(f"❌ Code generation failed: {code}")
259
+ return False
260
+
261
+ print(f"✅ Code generated successfully")
262
+ print(f" Lines of code: {len(code.split(chr(10)))}")
263
+
264
+ # Validate code
265
+ valid, msg = imaginer.validate_code(code)
266
+ if not valid:
267
+ print(f"⚠️ Code validation failed: {msg}")
268
+ return False
269
+
270
+ print(f"✅ Code validation passed")
271
+ return True
272
+
273
+
274
+ def run_all_tests():
275
+ """Run all functional tests"""
276
+ print("\n" + "="*60)
277
+ print("🧪 P2M Imagine - Ollama Functional Tests")
278
+ print("="*60)
279
+ print(f"Server: {OLLAMA_BASE_URL}")
280
+ print(f"Model: {OLLAMA_MODEL}")
281
+
282
+ tests = [
283
+ test_ollama_connection,
284
+ test_hello_world_app,
285
+ test_todo_app,
286
+ test_counter_app,
287
+ test_form_app,
288
+ test_dashboard_app,
289
+ ]
290
+
291
+ results = []
292
+
293
+ for test_func in tests:
294
+ try:
295
+ result = test_func()
296
+ results.append((test_func.__name__, result))
297
+ except Exception as e:
298
+ results.append((test_func.__name__, False))
299
+ print(f"❌ {test_func.__name__} failed: {e}")
300
+ import traceback
301
+ traceback.print_exc()
302
+
303
+ # Summary
304
+ print("\n" + "="*60)
305
+ print("📊 Test Summary")
306
+ print("="*60)
307
+
308
+ passed = sum(1 for _, success in results if success)
309
+ total = len(results)
310
+
311
+ for name, success in results:
312
+ status = "✅ PASS" if success else "❌ FAIL"
313
+ print(f"{status} - {name}")
314
+
315
+ print(f"\n📈 Results: {passed}/{total} tests passed")
316
+
317
+ if passed == total:
318
+ print("\n🎉 All tests passed!")
319
+ elif passed > 0:
320
+ print(f"\n⚠️ {total - passed} test(s) failed (connection issues?)")
321
+ else:
322
+ print(f"\n❌ All tests failed (cannot connect to Ollama server)")
323
+
324
+ return passed > 0 # Return True if at least one test passed
325
+
326
+
327
+ if __name__ == "__main__":
328
+ success = run_all_tests()
329
+ sys.exit(0 if success else 1)
@@ -0,0 +1,228 @@
1
+ """
2
+ Test suite for real-world P2M applications
3
+ """
4
+
5
+ import sys
6
+ from pathlib import Path
7
+
8
+ # Add project to path
9
+ sys.path.insert(0, str(Path(__file__).parent.parent))
10
+
11
+ from p2m.core import Render, RenderEngine
12
+
13
+
14
+ def test_todo_app():
15
+ """Test todo app example"""
16
+ print("\n🧪 Test 1: Todo App Example")
17
+
18
+ try:
19
+ # Import the example
20
+ sys.path.insert(0, str(Path(__file__).parent.parent / "examples"))
21
+ import example_todo_app
22
+
23
+ # Execute the view
24
+ component_tree = Render.execute(example_todo_app.create_view)
25
+
26
+ assert component_tree is not None
27
+ assert component_tree["type"] == "Container"
28
+
29
+ # Render to HTML
30
+ engine = RenderEngine()
31
+ html = engine.render(component_tree, mobile_frame=False)
32
+
33
+ assert html is not None
34
+ assert "My Todo App" in html
35
+ assert "Todo List" in html
36
+
37
+ print("✅ Todo app test passed")
38
+ print(f" Generated HTML: {len(html)} bytes")
39
+ return True
40
+ except Exception as e:
41
+ print(f"❌ Todo app test failed: {e}")
42
+ import traceback
43
+ traceback.print_exc()
44
+ return False
45
+
46
+
47
+ def test_ecommerce_app():
48
+ """Test e-commerce app example"""
49
+ print("\n🧪 Test 2: E-commerce App Example")
50
+
51
+ try:
52
+ # Import the example
53
+ sys.path.insert(0, str(Path(__file__).parent.parent / "examples"))
54
+ import example_ecommerce_app
55
+
56
+ # Execute the view
57
+ component_tree = Render.execute(example_ecommerce_app.create_view)
58
+
59
+ assert component_tree is not None
60
+ assert component_tree["type"] == "Container"
61
+
62
+ # Render to HTML
63
+ engine = RenderEngine()
64
+ html = engine.render(component_tree, mobile_frame=False)
65
+
66
+ assert html is not None
67
+ assert "TechStore" in html
68
+ assert "Featured Products" in html
69
+
70
+ print("✅ E-commerce app test passed")
71
+ print(f" Generated HTML: {len(html)} bytes")
72
+ return True
73
+ except Exception as e:
74
+ print(f"❌ E-commerce app test failed: {e}")
75
+ import traceback
76
+ traceback.print_exc()
77
+ return False
78
+
79
+
80
+ def test_todo_app_with_mobile_frame():
81
+ """Test todo app with mobile frame"""
82
+ print("\n🧪 Test 3: Todo App with Mobile Frame")
83
+
84
+ try:
85
+ sys.path.insert(0, str(Path(__file__).parent.parent / "examples"))
86
+ import example_todo_app
87
+
88
+ component_tree = Render.execute(example_todo_app.create_view)
89
+
90
+ # Render with mobile frame
91
+ engine = RenderEngine()
92
+ html = engine.render(component_tree, mobile_frame=True)
93
+
94
+ assert html is not None
95
+ assert "mobile-frame" in html
96
+ assert "375px" in html
97
+ assert "My Todo App" in html
98
+
99
+ print("✅ Todo app with mobile frame test passed")
100
+ print(f" Generated HTML: {len(html)} bytes")
101
+ return True
102
+ except Exception as e:
103
+ print(f"❌ Todo app with mobile frame test failed: {e}")
104
+ import traceback
105
+ traceback.print_exc()
106
+ return False
107
+
108
+
109
+ def test_ecommerce_app_with_mobile_frame():
110
+ """Test e-commerce app with mobile frame"""
111
+ print("\n🧪 Test 4: E-commerce App with Mobile Frame")
112
+
113
+ try:
114
+ sys.path.insert(0, str(Path(__file__).parent.parent / "examples"))
115
+ import example_ecommerce_app
116
+
117
+ component_tree = Render.execute(example_ecommerce_app.create_view)
118
+
119
+ # Render with mobile frame
120
+ engine = RenderEngine()
121
+ html = engine.render(component_tree, mobile_frame=True)
122
+
123
+ assert html is not None
124
+ assert "mobile-frame" in html
125
+ assert "TechStore" in html
126
+
127
+ print("✅ E-commerce app with mobile frame test passed")
128
+ print(f" Generated HTML: {len(html)} bytes")
129
+ return True
130
+ except Exception as e:
131
+ print(f"❌ E-commerce app with mobile frame test failed: {e}")
132
+ import traceback
133
+ traceback.print_exc()
134
+ return False
135
+
136
+
137
+ def test_app_structure():
138
+ """Test app component structure"""
139
+ print("\n🧪 Test 5: App Component Structure")
140
+
141
+ try:
142
+ sys.path.insert(0, str(Path(__file__).parent.parent / "examples"))
143
+ import example_todo_app
144
+
145
+ component_tree = Render.execute(example_todo_app.create_view)
146
+
147
+ # Verify structure
148
+ assert component_tree["type"] == "Container"
149
+ assert len(component_tree["children"]) > 0
150
+
151
+ # Count different component types
152
+ def count_components(comp, comp_type):
153
+ count = 0
154
+ if comp.get("type") == comp_type:
155
+ count += 1
156
+ for child in comp.get("children", []):
157
+ if isinstance(child, dict):
158
+ count += count_components(child, comp_type)
159
+ return count
160
+
161
+ text_count = count_components(component_tree, "Text")
162
+ button_count = count_components(component_tree, "Button")
163
+ card_count = count_components(component_tree, "Card")
164
+
165
+ assert text_count > 0, "Should have Text components"
166
+ assert button_count > 0, "Should have Button components"
167
+
168
+ print(f"✅ App structure test passed")
169
+ print(f" Text components: {text_count}")
170
+ print(f" Button components: {button_count}")
171
+ print(f" Card components: {card_count}")
172
+ return True
173
+ except Exception as e:
174
+ print(f"❌ App structure test failed: {e}")
175
+ import traceback
176
+ traceback.print_exc()
177
+ return False
178
+
179
+
180
+ def run_all_tests():
181
+ """Run all tests"""
182
+ print("\n" + "="*60)
183
+ print("🧪 P2M Real-World Apps Test Suite")
184
+ print("="*60)
185
+
186
+ tests = [
187
+ test_todo_app,
188
+ test_ecommerce_app,
189
+ test_todo_app_with_mobile_frame,
190
+ test_ecommerce_app_with_mobile_frame,
191
+ test_app_structure,
192
+ ]
193
+
194
+ results = []
195
+
196
+ for test_func in tests:
197
+ try:
198
+ result = test_func()
199
+ results.append((test_func.__name__, result))
200
+ except Exception as e:
201
+ results.append((test_func.__name__, False))
202
+ print(f"❌ {test_func.__name__} failed: {e}")
203
+
204
+ # Summary
205
+ print("\n" + "="*60)
206
+ print("📊 Test Summary")
207
+ print("="*60)
208
+
209
+ passed = sum(1 for _, success in results if success)
210
+ total = len(results)
211
+
212
+ for name, success in results:
213
+ status = "✅ PASS" if success else "❌ FAIL"
214
+ print(f"{status} - {name}")
215
+
216
+ print(f"\n📈 Results: {passed}/{total} tests passed")
217
+
218
+ if passed == total:
219
+ print("\n🎉 All tests passed!")
220
+ else:
221
+ print(f"\n⚠️ {total - passed} test(s) failed")
222
+
223
+ return passed == total
224
+
225
+
226
+ if __name__ == "__main__":
227
+ success = run_all_tests()
228
+ sys.exit(0 if success else 1)