portacode 1.3.32__py3-none-any.whl → 1.4.15.dev3__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.
- portacode/_version.py +2 -2
- portacode/cli.py +158 -14
- portacode/connection/client.py +127 -8
- portacode/connection/handlers/WEBSOCKET_PROTOCOL.md +600 -4
- portacode/connection/handlers/__init__.py +30 -1
- portacode/connection/handlers/diff_handlers.py +603 -0
- portacode/connection/handlers/file_handlers.py +674 -17
- portacode/connection/handlers/project_aware_file_handlers.py +11 -0
- portacode/connection/handlers/project_state/file_system_watcher.py +31 -61
- portacode/connection/handlers/project_state/git_manager.py +139 -572
- portacode/connection/handlers/project_state/handlers.py +28 -14
- portacode/connection/handlers/project_state/manager.py +226 -101
- portacode/connection/handlers/proxmox_infra.py +2082 -0
- portacode/connection/handlers/session.py +465 -84
- portacode/connection/handlers/system_handlers.py +311 -9
- portacode/connection/handlers/tab_factory.py +1 -47
- portacode/connection/handlers/test_proxmox_infra.py +13 -0
- portacode/connection/handlers/update_handler.py +61 -0
- portacode/connection/terminal.py +64 -10
- portacode/keypair.py +63 -1
- portacode/link_capture/__init__.py +38 -0
- portacode/link_capture/__pycache__/__init__.cpython-311.pyc +0 -0
- portacode/link_capture/bin/__pycache__/link_capture_wrapper.cpython-311.pyc +0 -0
- portacode/link_capture/bin/elinks +3 -0
- portacode/link_capture/bin/gio-open +3 -0
- portacode/link_capture/bin/gnome-open +3 -0
- portacode/link_capture/bin/gvfs-open +3 -0
- portacode/link_capture/bin/kde-open +3 -0
- portacode/link_capture/bin/kfmclient +3 -0
- portacode/link_capture/bin/link_capture_exec.sh +11 -0
- portacode/link_capture/bin/link_capture_wrapper.py +75 -0
- portacode/link_capture/bin/links +3 -0
- portacode/link_capture/bin/links2 +3 -0
- portacode/link_capture/bin/lynx +3 -0
- portacode/link_capture/bin/mate-open +3 -0
- portacode/link_capture/bin/netsurf +3 -0
- portacode/link_capture/bin/sensible-browser +3 -0
- portacode/link_capture/bin/w3m +3 -0
- portacode/link_capture/bin/x-www-browser +3 -0
- portacode/link_capture/bin/xdg-open +3 -0
- portacode/pairing.py +103 -0
- portacode/static/js/utils/ntp-clock.js +170 -79
- portacode/utils/diff_apply.py +456 -0
- portacode/utils/diff_renderer.py +371 -0
- portacode/utils/ntp_clock.py +45 -131
- {portacode-1.3.32.dist-info → portacode-1.4.15.dev3.dist-info}/METADATA +71 -3
- portacode-1.4.15.dev3.dist-info/RECORD +98 -0
- {portacode-1.3.32.dist-info → portacode-1.4.15.dev3.dist-info}/WHEEL +1 -1
- test_modules/test_device_online.py +1 -1
- test_modules/test_login_flow.py +8 -4
- test_modules/test_play_store_screenshots.py +294 -0
- testing_framework/.env.example +4 -1
- testing_framework/core/playwright_manager.py +63 -9
- portacode-1.3.32.dist-info/RECORD +0 -70
- {portacode-1.3.32.dist-info → portacode-1.4.15.dev3.dist-info}/entry_points.txt +0 -0
- {portacode-1.3.32.dist-info → portacode-1.4.15.dev3.dist-info}/licenses/LICENSE +0 -0
- {portacode-1.3.32.dist-info → portacode-1.4.15.dev3.dist-info}/top_level.txt +0 -0
|
@@ -8,6 +8,7 @@ import logging
|
|
|
8
8
|
import json
|
|
9
9
|
import time
|
|
10
10
|
from datetime import datetime
|
|
11
|
+
from urllib.parse import urlparse
|
|
11
12
|
|
|
12
13
|
try:
|
|
13
14
|
from playwright.async_api import async_playwright, Browser, BrowserContext, Page
|
|
@@ -71,6 +72,13 @@ class PlaywrightManager:
|
|
|
71
72
|
env_headless = os.getenv('TEST_HEADLESS', 'false').lower() in ('true', '1', 'yes')
|
|
72
73
|
env_video_width = int(os.getenv('TEST_VIDEO_WIDTH', '1920'))
|
|
73
74
|
env_video_height = int(os.getenv('TEST_VIDEO_HEIGHT', '1080'))
|
|
75
|
+
env_viewport_width = os.getenv('TEST_VIEWPORT_WIDTH')
|
|
76
|
+
env_viewport_height = os.getenv('TEST_VIEWPORT_HEIGHT')
|
|
77
|
+
env_device_scale = os.getenv('TEST_DEVICE_SCALE_FACTOR')
|
|
78
|
+
env_is_mobile = os.getenv('TEST_IS_MOBILE')
|
|
79
|
+
env_has_touch = os.getenv('TEST_HAS_TOUCH')
|
|
80
|
+
env_user_agent = os.getenv('TEST_USER_AGENT')
|
|
81
|
+
automation_token = os.getenv('TEST_RUNNER_BYPASS_TOKEN')
|
|
74
82
|
|
|
75
83
|
# Use provided values or fall back to environment
|
|
76
84
|
self.base_url = url or env_url
|
|
@@ -124,15 +132,61 @@ class PlaywrightManager:
|
|
|
124
132
|
raise Exception(f"Failed to launch {browser_type} browser: {e}")
|
|
125
133
|
|
|
126
134
|
# Create context with recording enabled and proper viewport
|
|
135
|
+
viewport_size = {
|
|
136
|
+
"width": int(env_viewport_width) if env_viewport_width else env_video_width,
|
|
137
|
+
"height": int(env_viewport_height) if env_viewport_height else env_video_height
|
|
138
|
+
}
|
|
127
139
|
video_size = {"width": env_video_width, "height": env_video_height}
|
|
128
|
-
|
|
129
|
-
record_video_dir
|
|
130
|
-
record_video_size
|
|
131
|
-
record_har_path
|
|
132
|
-
record_har_omit_content
|
|
133
|
-
viewport
|
|
140
|
+
context_kwargs = {
|
|
141
|
+
"record_video_dir": str(self.test_recordings_dir),
|
|
142
|
+
"record_video_size": video_size,
|
|
143
|
+
"record_har_path": str(self.har_path),
|
|
144
|
+
"record_har_omit_content": False,
|
|
145
|
+
"viewport": viewport_size
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if env_device_scale:
|
|
149
|
+
try:
|
|
150
|
+
context_kwargs["device_scale_factor"] = float(env_device_scale)
|
|
151
|
+
except ValueError:
|
|
152
|
+
self.logger.warning(f"Invalid TEST_DEVICE_SCALE_FACTOR '{env_device_scale}' - ignoring")
|
|
153
|
+
|
|
154
|
+
if env_is_mobile:
|
|
155
|
+
context_kwargs["is_mobile"] = env_is_mobile.lower() in ('true', '1', 'yes')
|
|
156
|
+
|
|
157
|
+
if env_has_touch:
|
|
158
|
+
context_kwargs["has_touch"] = env_has_touch.lower() in ('true', '1', 'yes')
|
|
159
|
+
|
|
160
|
+
if env_user_agent:
|
|
161
|
+
context_kwargs["user_agent"] = env_user_agent
|
|
162
|
+
|
|
163
|
+
self.context = await self.browser.new_context(**context_kwargs)
|
|
164
|
+
self.logger.info(
|
|
165
|
+
"Viewport configured: %sx%s (device scale: %s, mobile: %s, touch: %s)",
|
|
166
|
+
viewport_size["width"],
|
|
167
|
+
viewport_size["height"],
|
|
168
|
+
context_kwargs.get("device_scale_factor", 1.0),
|
|
169
|
+
context_kwargs.get("is_mobile", False),
|
|
170
|
+
context_kwargs.get("has_touch", False),
|
|
134
171
|
)
|
|
135
|
-
|
|
172
|
+
if automation_token:
|
|
173
|
+
parsed_base = urlparse(self.base_url)
|
|
174
|
+
target_host = parsed_base.hostname
|
|
175
|
+
target_scheme = parsed_base.scheme or "http"
|
|
176
|
+
header_name = "X-Portacode-Automation"
|
|
177
|
+
|
|
178
|
+
async def automation_header_route(route, request):
|
|
179
|
+
headers = dict(request.headers)
|
|
180
|
+
parsed_request = urlparse(request.url)
|
|
181
|
+
if parsed_request.hostname == target_host and parsed_request.scheme == target_scheme:
|
|
182
|
+
headers[header_name] = automation_token
|
|
183
|
+
else:
|
|
184
|
+
headers.pop(header_name, None)
|
|
185
|
+
await route.continue_(headers=headers)
|
|
186
|
+
|
|
187
|
+
await self.context.route("**/*", automation_header_route)
|
|
188
|
+
self.logger.info("Automation bypass header restricted to same-origin requests")
|
|
189
|
+
|
|
136
190
|
self.logger.info(f"Video recording configured: {env_video_width}x{env_video_height}")
|
|
137
191
|
|
|
138
192
|
# Start tracing
|
|
@@ -178,7 +232,7 @@ class PlaywrightManager:
|
|
|
178
232
|
"""Perform login using provided credentials."""
|
|
179
233
|
try:
|
|
180
234
|
# Navigate to login page first
|
|
181
|
-
login_url = f"{self.base_url}
|
|
235
|
+
login_url = f"{self.base_url}accounts/login/"
|
|
182
236
|
await self.page.goto(login_url)
|
|
183
237
|
await self.log_action("navigate_to_login", {"url": login_url})
|
|
184
238
|
await self.take_screenshot("login_page")
|
|
@@ -463,4 +517,4 @@ class PlaywrightManager:
|
|
|
463
517
|
"actions_count": len(self.actions_log),
|
|
464
518
|
"console_logs_count": len(getattr(self, 'console_logs', [])),
|
|
465
519
|
"websocket_logs_count": len(self.websocket_logs)
|
|
466
|
-
}
|
|
520
|
+
}
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
portacode/README.md,sha256=4dKtpvR8LNgZPVz37GmkQCMWIr_u25Ao63iW56s7Ke4,775
|
|
2
|
-
portacode/__init__.py,sha256=oB3sV1wXr-um-RXio73UG8E5Xx6cF2ZVJveqjNmC-vQ,1086
|
|
3
|
-
portacode/__main__.py,sha256=jmHTGC1hzmo9iKJLv-SSYe9BSIbPPZ2IOpecI03PlTs,296
|
|
4
|
-
portacode/_version.py,sha256=d_JbLCEf2f0Y5ScYYYOP97vUKSwyr-VyTj2aQkfr7KU,706
|
|
5
|
-
portacode/cli.py,sha256=eDqcZMVFHKzqqWxedhhx8ylu5WMVCLqeJQkbPR7RcJE,16333
|
|
6
|
-
portacode/data.py,sha256=5-s291bv8J354myaHm1Y7CQZTZyRzMU3TGe5U4hb-FA,1591
|
|
7
|
-
portacode/keypair.py,sha256=PAcOYqlVLOoZTPYi6LvLjfsY6BkrWbLOhSZLb8r5sHs,3635
|
|
8
|
-
portacode/logging_categories.py,sha256=9m-BYrjyHh1vjZYBQT4JhAh6b_oYUhIWayO-noH1cSE,5063
|
|
9
|
-
portacode/service.py,sha256=p-HHMOAl20QsdcJydcZ74Iqes-wl8G8HItdSim30pUk,16537
|
|
10
|
-
portacode/connection/README.md,sha256=f9rbuIEKa7cTm9C98rCiBbEtbiIXQU11esGSNhSMiJg,883
|
|
11
|
-
portacode/connection/__init__.py,sha256=atqcVGkViIEd7pRa6cP2do07RJOM0UWpbnz5zXjGktU,250
|
|
12
|
-
portacode/connection/client.py,sha256=Uqsy5xzN0j5AY0xkYs2_qd67N7SUopcnpkCbkmOnMgg,9102
|
|
13
|
-
portacode/connection/multiplex.py,sha256=L-TxqJ_ZEbfNEfu1cwxgJ5vUdyRzZjsMy2Kx1diiZys,5237
|
|
14
|
-
portacode/connection/terminal.py,sha256=iz4bi9pppxsiAiOtXEkffcHoyaWkvRG9BkojUyfZ784,42421
|
|
15
|
-
portacode/connection/handlers/README.md,sha256=HsLZG1QK1JNm67HsgL6WoDg9nxzKXxwkc5fJPFJdX5g,12169
|
|
16
|
-
portacode/connection/handlers/WEBSOCKET_PROTOCOL.md,sha256=U-d58S-X2r5T6QAu-6NOzCIJg71FIj_vmOdUGCWFIhw,68211
|
|
17
|
-
portacode/connection/handlers/__init__.py,sha256=4nv3Z4TGYjWcauKPWsbL_FbrTXApI94V7j6oiU1Vv-o,2144
|
|
18
|
-
portacode/connection/handlers/base.py,sha256=oENFb-Fcfzwk99Qx8gJQriEMiwSxwygwjOiuCH36hM4,10231
|
|
19
|
-
portacode/connection/handlers/chunked_content.py,sha256=h6hXRmxSeOgnIxoU8CkmvEf2Odv-ajPrpHIe_W3GKcA,9251
|
|
20
|
-
portacode/connection/handlers/file_handlers.py,sha256=kBj-o3HkqZTKsju2ZxRgBB3Ke42dn4sDQQKGO7APYf8,15451
|
|
21
|
-
portacode/connection/handlers/project_aware_file_handlers.py,sha256=n0M2WmBNWPwzigdIkyZiAsePUQGXVqYSsDyOxm-Nsok,9253
|
|
22
|
-
portacode/connection/handlers/project_state_handlers.py,sha256=v6ZefGW9i7n1aZLq2jOGumJIjYb6aHlPI4m1jkYewm8,1686
|
|
23
|
-
portacode/connection/handlers/registry.py,sha256=qXGE60sYEWg6ZtVQzFcZ5YI2XWR6lMgw4hAL9x5qR1I,6181
|
|
24
|
-
portacode/connection/handlers/session.py,sha256=O7TMI5cRziOiXEBWCfBshkMpEthhjvKqGL0hhNOG1wU,26716
|
|
25
|
-
portacode/connection/handlers/system_handlers.py,sha256=65V5ctT0dIBc-oWG91e62MbdvU0z6x6JCTQuIqCWmZ0,5242
|
|
26
|
-
portacode/connection/handlers/tab_factory.py,sha256=VBZnwtxgeNJCsfBzUjkFWAAGBdijvai4MS2dXnhFY8U,18000
|
|
27
|
-
portacode/connection/handlers/terminal_handlers.py,sha256=HRwHW1GiqG1NtHVEqXHKaYkFfQEzCDDH6YIlHcb4XD8,11866
|
|
28
|
-
portacode/connection/handlers/project_state/README.md,sha256=trdd4ig6ungmwH5SpbSLfyxbL-QgPlGNU-_XrMEiXtw,10114
|
|
29
|
-
portacode/connection/handlers/project_state/__init__.py,sha256=5ucIqk6Iclqg6bKkL8r_wVs5Tlt6B9J7yQH6yQUt7gc,2541
|
|
30
|
-
portacode/connection/handlers/project_state/file_system_watcher.py,sha256=2zingW9BoNKRijghHC2eHHdRoyDRdLmIl1yH1y-iuF8,10831
|
|
31
|
-
portacode/connection/handlers/project_state/git_manager.py,sha256=tVcuiGYKk1GJ0f7dgjoSGNL13IXCHUOtoi_VBc8ZTqQ,88682
|
|
32
|
-
portacode/connection/handlers/project_state/handlers.py,sha256=nhs-3yiENdewAzVZnSdn2Ir-e6TQ9Nz_Bxk3iiFPd9c,37985
|
|
33
|
-
portacode/connection/handlers/project_state/manager.py,sha256=XX3wMgGdPbRgBBs_R1dXtQ4D9j-itETrJR_6IfBeDU0,61296
|
|
34
|
-
portacode/connection/handlers/project_state/models.py,sha256=EZTKvxHKs8QlQUbzI0u2IqfzfRRXZixUIDBwTGCJATI,4313
|
|
35
|
-
portacode/connection/handlers/project_state/utils.py,sha256=LsbQr9TH9Bz30FqikmtTxco4PlB_n0kUIuPKQ6Fb_mo,1665
|
|
36
|
-
portacode/static/js/test-ntp-clock.html,sha256=bUow9sifIuLNPqKvuPbpQozmEE6RhdCI4Plib3CqUmw,2130
|
|
37
|
-
portacode/static/js/utils/ntp-clock.js,sha256=KMeHGT-IlUSlxVRZZ899z25dQCJh6EJbgXjlh8dD8vA,4495
|
|
38
|
-
portacode/utils/NTP_ARCHITECTURE.md,sha256=WkESTbz5SNAgdmDKk3DrHMhtYOPji_Kt3_a9arWdRig,3894
|
|
39
|
-
portacode/utils/__init__.py,sha256=NgBlWTuNJESfIYJzP_3adI1yJQJR0XJLRpSdVNaBAN0,33
|
|
40
|
-
portacode/utils/ntp_clock.py,sha256=6QJOVZr9VQuxIyJt9KNG4dR-nZ3bKNyipMxjqDWP89Y,5152
|
|
41
|
-
portacode-1.3.32.dist-info/licenses/LICENSE,sha256=2FGbCnUDgRYuQTkB1O1dUUpu5CVAjK1j4_p6ack9Z54,1066
|
|
42
|
-
test_modules/README.md,sha256=Do_agkm9WhSzueXjRAkV_xEj6Emy5zB3N3VKY5Roce8,9274
|
|
43
|
-
test_modules/__init__.py,sha256=1LcbHodIHsB0g-g4NGjSn6AMuCoGbymvXPYLOb6Z7F0,53
|
|
44
|
-
test_modules/test_device_online.py,sha256=yiSyVaMwKAugqIX_ZIxmLXiOlmA_8IRXiUp12YmpB98,1653
|
|
45
|
-
test_modules/test_file_operations.py,sha256=KXbh9t8Fah1jZp1pEPlU4_F06iJIJr2fR-yYc4RL6m8,38372
|
|
46
|
-
test_modules/test_git_status_ui.py,sha256=A_qkt-0lFLwxdr7t6YQaM0HqUElDwlZi84mlngg11RA,18734
|
|
47
|
-
test_modules/test_login_flow.py,sha256=eGjoZQj345qYxNm1arvYVNzjJ-TutT81lSdI6_8A5GU,1685
|
|
48
|
-
test_modules/test_navigate_testing_folder.py,sha256=-1EXceUEwof_sYp5paMWUNT3mAv5aIpYJ65_vqFbZew,18233
|
|
49
|
-
test_modules/test_terminal_buffer_performance.py,sha256=YQeDDZVnsQD3ug6udKUZH3NR7PHGP75uZsLZJYya7jg,12183
|
|
50
|
-
test_modules/test_terminal_interaction.py,sha256=AxLb63oKhNLjKrny4hBj4hhFhrmHZ5UGStYDA0KzA0w,3163
|
|
51
|
-
test_modules/test_terminal_loading_race_condition.py,sha256=PsGF8QzWeNNv6G7Fda6kETcBUcXyg_vRYeD-hDHAhCo,4158
|
|
52
|
-
test_modules/test_terminal_start.py,sha256=y3IqG54UfMk-pAQ_fn5LuoM3kki6xRm11oB5AzfC-iE,1978
|
|
53
|
-
testing_framework/.env.example,sha256=lReCwHAx7vxPxRT7TebEKiZ5HpEOQnpgraXJl2k-0xU,541
|
|
54
|
-
testing_framework/README.md,sha256=7o04mS2siNDuHA1UBh3Uu6XCbGomKjgb8gfl8YbClhE,9662
|
|
55
|
-
testing_framework/__init__.py,sha256=safHXo_xBMwAwfiF_5rx0xGcPGfpBSOgkMZx04uj4No,575
|
|
56
|
-
testing_framework/cli.py,sha256=ZHO37QO2IqZpC9VovrAYur2Vfc2AYeDqzi9Nb4lIA-w,13434
|
|
57
|
-
testing_framework/requirements.txt,sha256=VeKSPyqS4MWwLhr0Upu7fImlXZQQjtL8uYeyHOjkYaE,249
|
|
58
|
-
testing_framework/core/__init__.py,sha256=8AJQgqSCa9WgwkQNH_wTsA3JmJ4d4FRCweI-ioDgcNI,40
|
|
59
|
-
testing_framework/core/base_test.py,sha256=0kKQDNCdAJyTQfJiMBzx9_2MMRrmaVfQF0cawhvian4,13149
|
|
60
|
-
testing_framework/core/cli_manager.py,sha256=LDH_tWn-CmO08U_rmBIPpN_O6HLaQKRjdnfKGrtqs8Y,6991
|
|
61
|
-
testing_framework/core/hierarchical_runner.py,sha256=tCeksh2cXbRspurSiE-mQM1M1BOPeY8mKFbjvaBTVHw,26401
|
|
62
|
-
testing_framework/core/playwright_manager.py,sha256=8xl-19b8NQjKNdiRyDjyeXlYyKPZouSSmmlXjDpuI50,19559
|
|
63
|
-
testing_framework/core/runner.py,sha256=j2QwNJmAxVBmJvcbVS7DgPJUKPNzqfLmt_4NNdaKmZU,19297
|
|
64
|
-
testing_framework/core/shared_cli_manager.py,sha256=BESSNtyQb7BOlaOvZmm04T8Uezjms4KCBs2MzTxvzYQ,8790
|
|
65
|
-
testing_framework/core/test_discovery.py,sha256=2FZ9fJ8Dp5dloA-fkgXoJ_gCMC_nYPBnA3Hs2xlagzM,4928
|
|
66
|
-
portacode-1.3.32.dist-info/METADATA,sha256=rTf7KoQ6JhbUqq_aOd-8ASc7UfR53vtrxdaLQ-ANsZ8,6989
|
|
67
|
-
portacode-1.3.32.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
68
|
-
portacode-1.3.32.dist-info/entry_points.txt,sha256=lLUUL-BM6_wwe44Xv0__5NQ1BnAz6jWjSMFvZdWW3zU,48
|
|
69
|
-
portacode-1.3.32.dist-info/top_level.txt,sha256=TGhTYUxfW8SyVZc_zGgzjzc24gGT7nSw8Qf73liVRKM,41
|
|
70
|
-
portacode-1.3.32.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|