portacode 1.3.33__py3-none-any.whl → 1.3.34__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.
Potentially problematic release.
This version of portacode might be problematic. Click here for more details.
- portacode/_version.py +2 -2
- portacode/connection/handlers/project_state/handlers.py +7 -8
- portacode/connection/handlers/tab_factory.py +1 -47
- {portacode-1.3.33.dist-info → portacode-1.3.34.dist-info}/METADATA +1 -1
- {portacode-1.3.33.dist-info → portacode-1.3.34.dist-info}/RECORD +11 -11
- testing_framework/.env.example +4 -1
- testing_framework/core/playwright_manager.py +29 -9
- {portacode-1.3.33.dist-info → portacode-1.3.34.dist-info}/WHEEL +0 -0
- {portacode-1.3.33.dist-info → portacode-1.3.34.dist-info}/entry_points.txt +0 -0
- {portacode-1.3.33.dist-info → portacode-1.3.34.dist-info}/licenses/LICENSE +0 -0
- {portacode-1.3.33.dist-info → portacode-1.3.34.dist-info}/top_level.txt +0 -0
portacode/_version.py
CHANGED
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '1.3.
|
|
32
|
-
__version_tuple__ = version_tuple = (1, 3,
|
|
31
|
+
__version__ = version = '1.3.34'
|
|
32
|
+
__version_tuple__ = version_tuple = (1, 3, 34)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -764,14 +764,13 @@ class ProjectStateDiffContentHandler(AsyncHandler):
|
|
|
764
764
|
if content is None or (content_type == "all" and not all([matching_tab.original_content, matching_tab.modified_content])):
|
|
765
765
|
if content_type in ["original", "modified", "all"]:
|
|
766
766
|
# Re-generate the diff content if needed
|
|
767
|
-
await manager.
|
|
768
|
-
source_client_session,
|
|
769
|
-
file_path,
|
|
770
|
-
from_ref,
|
|
771
|
-
to_ref,
|
|
772
|
-
from_hash,
|
|
773
|
-
to_hash
|
|
774
|
-
activate=False # Don't activate, just ensure content is loaded
|
|
767
|
+
await manager.open_diff_tab(
|
|
768
|
+
source_client_session,
|
|
769
|
+
file_path,
|
|
770
|
+
from_ref,
|
|
771
|
+
to_ref,
|
|
772
|
+
from_hash,
|
|
773
|
+
to_hash
|
|
775
774
|
)
|
|
776
775
|
|
|
777
776
|
# Try to get content again after regeneration (use same matching logic)
|
|
@@ -162,53 +162,7 @@ class TabFactory:
|
|
|
162
162
|
await self._load_binary_content(file_path, tab_info, file_size)
|
|
163
163
|
|
|
164
164
|
return TabInfo(**tab_info)
|
|
165
|
-
|
|
166
|
-
async def create_diff_tab(self, file_path: str, original_content: str,
|
|
167
|
-
modified_content: str, tab_id: Optional[str] = None,
|
|
168
|
-
diff_details: Optional[Dict[str, Any]] = None) -> TabInfo:
|
|
169
|
-
"""Create a diff tab for comparing file versions.
|
|
170
|
-
|
|
171
|
-
Args:
|
|
172
|
-
file_path: Path to the file being compared
|
|
173
|
-
original_content: Original version of the file
|
|
174
|
-
modified_content: Modified version of the file
|
|
175
|
-
tab_id: Optional tab ID, will generate UUID if not provided
|
|
176
|
-
diff_details: Optional detailed diff information from diff-match-patch
|
|
177
|
-
|
|
178
|
-
Returns:
|
|
179
|
-
TabInfo object configured for diff viewing
|
|
180
|
-
"""
|
|
181
|
-
if tab_id is None:
|
|
182
|
-
tab_id = str(uuid.uuid4())
|
|
183
|
-
|
|
184
|
-
file_path = Path(file_path)
|
|
185
|
-
|
|
186
|
-
metadata = {'diff_mode': True}
|
|
187
|
-
if diff_details:
|
|
188
|
-
metadata['diff_details'] = diff_details
|
|
189
|
-
|
|
190
|
-
# Cache diff content
|
|
191
|
-
original_hash = generate_content_hash(original_content)
|
|
192
|
-
modified_hash = generate_content_hash(modified_content)
|
|
193
|
-
cache_content(original_hash, original_content)
|
|
194
|
-
cache_content(modified_hash, modified_content)
|
|
195
|
-
|
|
196
|
-
return TabInfo(
|
|
197
|
-
tab_id=tab_id,
|
|
198
|
-
tab_type='diff',
|
|
199
|
-
title=f"{file_path.name} (diff)",
|
|
200
|
-
file_path=str(file_path),
|
|
201
|
-
content=None, # Diff tabs don't use regular content
|
|
202
|
-
original_content=original_content,
|
|
203
|
-
modified_content=modified_content,
|
|
204
|
-
original_content_hash=original_hash,
|
|
205
|
-
modified_content_hash=modified_hash,
|
|
206
|
-
is_dirty=False,
|
|
207
|
-
mime_type=None,
|
|
208
|
-
encoding='utf-8',
|
|
209
|
-
metadata=metadata
|
|
210
|
-
)
|
|
211
|
-
|
|
165
|
+
|
|
212
166
|
async def create_diff_tab_with_title(self, file_path: str, original_content: str,
|
|
213
167
|
modified_content: str, title: str,
|
|
214
168
|
tab_id: Optional[str] = None,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
portacode/README.md,sha256=4dKtpvR8LNgZPVz37GmkQCMWIr_u25Ao63iW56s7Ke4,775
|
|
2
2
|
portacode/__init__.py,sha256=oB3sV1wXr-um-RXio73UG8E5Xx6cF2ZVJveqjNmC-vQ,1086
|
|
3
3
|
portacode/__main__.py,sha256=jmHTGC1hzmo9iKJLv-SSYe9BSIbPPZ2IOpecI03PlTs,296
|
|
4
|
-
portacode/_version.py,sha256=
|
|
4
|
+
portacode/_version.py,sha256=FzZk-nydxD5WVgixf72x-Q7yZ53GL7Ll3WvZRoS7J5w,706
|
|
5
5
|
portacode/cli.py,sha256=eDqcZMVFHKzqqWxedhhx8ylu5WMVCLqeJQkbPR7RcJE,16333
|
|
6
6
|
portacode/data.py,sha256=5-s291bv8J354myaHm1Y7CQZTZyRzMU3TGe5U4hb-FA,1591
|
|
7
7
|
portacode/keypair.py,sha256=PAcOYqlVLOoZTPYi6LvLjfsY6BkrWbLOhSZLb8r5sHs,3635
|
|
@@ -23,13 +23,13 @@ portacode/connection/handlers/project_state_handlers.py,sha256=v6ZefGW9i7n1aZLq2
|
|
|
23
23
|
portacode/connection/handlers/registry.py,sha256=qXGE60sYEWg6ZtVQzFcZ5YI2XWR6lMgw4hAL9x5qR1I,6181
|
|
24
24
|
portacode/connection/handlers/session.py,sha256=XWiD4dofzZB9AH7EDqbWeJ-1CrSNPCUTR2nE2UEZh7Y,35568
|
|
25
25
|
portacode/connection/handlers/system_handlers.py,sha256=65V5ctT0dIBc-oWG91e62MbdvU0z6x6JCTQuIqCWmZ0,5242
|
|
26
|
-
portacode/connection/handlers/tab_factory.py,sha256=
|
|
26
|
+
portacode/connection/handlers/tab_factory.py,sha256=yn93h6GASjD1VpvW1oqpax3EpoT0r7r97zFXxML1wdA,16173
|
|
27
27
|
portacode/connection/handlers/terminal_handlers.py,sha256=HRwHW1GiqG1NtHVEqXHKaYkFfQEzCDDH6YIlHcb4XD8,11866
|
|
28
28
|
portacode/connection/handlers/project_state/README.md,sha256=trdd4ig6ungmwH5SpbSLfyxbL-QgPlGNU-_XrMEiXtw,10114
|
|
29
29
|
portacode/connection/handlers/project_state/__init__.py,sha256=5ucIqk6Iclqg6bKkL8r_wVs5Tlt6B9J7yQH6yQUt7gc,2541
|
|
30
30
|
portacode/connection/handlers/project_state/file_system_watcher.py,sha256=2zingW9BoNKRijghHC2eHHdRoyDRdLmIl1yH1y-iuF8,10831
|
|
31
31
|
portacode/connection/handlers/project_state/git_manager.py,sha256=GO0AEXzHEaKOBGZP043_V2KgGz8zqmSahWJ5KHgC_Cs,88845
|
|
32
|
-
portacode/connection/handlers/project_state/handlers.py,sha256=
|
|
32
|
+
portacode/connection/handlers/project_state/handlers.py,sha256=ay9D2KCPnPx-Luhx3_VAVq_HVFgLDDBwJvgaiKeseak,37889
|
|
33
33
|
portacode/connection/handlers/project_state/manager.py,sha256=XX3wMgGdPbRgBBs_R1dXtQ4D9j-itETrJR_6IfBeDU0,61296
|
|
34
34
|
portacode/connection/handlers/project_state/models.py,sha256=EZTKvxHKs8QlQUbzI0u2IqfzfRRXZixUIDBwTGCJATI,4313
|
|
35
35
|
portacode/connection/handlers/project_state/utils.py,sha256=LsbQr9TH9Bz30FqikmtTxco4PlB_n0kUIuPKQ6Fb_mo,1665
|
|
@@ -38,7 +38,7 @@ portacode/static/js/utils/ntp-clock.js,sha256=KMeHGT-IlUSlxVRZZ899z25dQCJh6EJbgX
|
|
|
38
38
|
portacode/utils/NTP_ARCHITECTURE.md,sha256=WkESTbz5SNAgdmDKk3DrHMhtYOPji_Kt3_a9arWdRig,3894
|
|
39
39
|
portacode/utils/__init__.py,sha256=NgBlWTuNJESfIYJzP_3adI1yJQJR0XJLRpSdVNaBAN0,33
|
|
40
40
|
portacode/utils/ntp_clock.py,sha256=6QJOVZr9VQuxIyJt9KNG4dR-nZ3bKNyipMxjqDWP89Y,5152
|
|
41
|
-
portacode-1.3.
|
|
41
|
+
portacode-1.3.34.dist-info/licenses/LICENSE,sha256=2FGbCnUDgRYuQTkB1O1dUUpu5CVAjK1j4_p6ack9Z54,1066
|
|
42
42
|
test_modules/README.md,sha256=Do_agkm9WhSzueXjRAkV_xEj6Emy5zB3N3VKY5Roce8,9274
|
|
43
43
|
test_modules/__init__.py,sha256=1LcbHodIHsB0g-g4NGjSn6AMuCoGbymvXPYLOb6Z7F0,53
|
|
44
44
|
test_modules/test_device_online.py,sha256=yiSyVaMwKAugqIX_ZIxmLXiOlmA_8IRXiUp12YmpB98,1653
|
|
@@ -50,7 +50,7 @@ test_modules/test_terminal_buffer_performance.py,sha256=YQeDDZVnsQD3ug6udKUZH3NR
|
|
|
50
50
|
test_modules/test_terminal_interaction.py,sha256=AxLb63oKhNLjKrny4hBj4hhFhrmHZ5UGStYDA0KzA0w,3163
|
|
51
51
|
test_modules/test_terminal_loading_race_condition.py,sha256=PsGF8QzWeNNv6G7Fda6kETcBUcXyg_vRYeD-hDHAhCo,4158
|
|
52
52
|
test_modules/test_terminal_start.py,sha256=y3IqG54UfMk-pAQ_fn5LuoM3kki6xRm11oB5AzfC-iE,1978
|
|
53
|
-
testing_framework/.env.example,sha256=
|
|
53
|
+
testing_framework/.env.example,sha256=zGchLcB-p22YUUCU0JIyHLduLpDuFy8c5xPacctHvfY,708
|
|
54
54
|
testing_framework/README.md,sha256=7o04mS2siNDuHA1UBh3Uu6XCbGomKjgb8gfl8YbClhE,9662
|
|
55
55
|
testing_framework/__init__.py,sha256=safHXo_xBMwAwfiF_5rx0xGcPGfpBSOgkMZx04uj4No,575
|
|
56
56
|
testing_framework/cli.py,sha256=ZHO37QO2IqZpC9VovrAYur2Vfc2AYeDqzi9Nb4lIA-w,13434
|
|
@@ -59,12 +59,12 @@ testing_framework/core/__init__.py,sha256=8AJQgqSCa9WgwkQNH_wTsA3JmJ4d4FRCweI-io
|
|
|
59
59
|
testing_framework/core/base_test.py,sha256=0kKQDNCdAJyTQfJiMBzx9_2MMRrmaVfQF0cawhvian4,13149
|
|
60
60
|
testing_framework/core/cli_manager.py,sha256=LDH_tWn-CmO08U_rmBIPpN_O6HLaQKRjdnfKGrtqs8Y,6991
|
|
61
61
|
testing_framework/core/hierarchical_runner.py,sha256=tCeksh2cXbRspurSiE-mQM1M1BOPeY8mKFbjvaBTVHw,26401
|
|
62
|
-
testing_framework/core/playwright_manager.py,sha256=
|
|
62
|
+
testing_framework/core/playwright_manager.py,sha256=kWKmlxzftDY0ZWS891zlHu_Ctdw7ufUIdx20Tsr7BL8,20626
|
|
63
63
|
testing_framework/core/runner.py,sha256=j2QwNJmAxVBmJvcbVS7DgPJUKPNzqfLmt_4NNdaKmZU,19297
|
|
64
64
|
testing_framework/core/shared_cli_manager.py,sha256=BESSNtyQb7BOlaOvZmm04T8Uezjms4KCBs2MzTxvzYQ,8790
|
|
65
65
|
testing_framework/core/test_discovery.py,sha256=2FZ9fJ8Dp5dloA-fkgXoJ_gCMC_nYPBnA3Hs2xlagzM,4928
|
|
66
|
-
portacode-1.3.
|
|
67
|
-
portacode-1.3.
|
|
68
|
-
portacode-1.3.
|
|
69
|
-
portacode-1.3.
|
|
70
|
-
portacode-1.3.
|
|
66
|
+
portacode-1.3.34.dist-info/METADATA,sha256=X9OAC5yDMG6Teny3L5pYj-SQz43H9U0QRHN5BfJhzaY,6989
|
|
67
|
+
portacode-1.3.34.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
68
|
+
portacode-1.3.34.dist-info/entry_points.txt,sha256=lLUUL-BM6_wwe44Xv0__5NQ1BnAz6jWjSMFvZdWW3zU,48
|
|
69
|
+
portacode-1.3.34.dist-info/top_level.txt,sha256=TGhTYUxfW8SyVZc_zGgzjzc24gGT7nSw8Qf73liVRKM,41
|
|
70
|
+
portacode-1.3.34.dist-info/RECORD,,
|
testing_framework/.env.example
CHANGED
|
@@ -15,4 +15,7 @@ TEST_HEADLESS=false # true for headless mode, false for visible browser
|
|
|
15
15
|
# Optional: Test Output Directories
|
|
16
16
|
TEST_RESULTS_DIR=test_results
|
|
17
17
|
TEST_RECORDINGS_DIR=test_recordings
|
|
18
|
-
TEST_LOGS_DIR=test_results
|
|
18
|
+
TEST_LOGS_DIR=test_results
|
|
19
|
+
|
|
20
|
+
# Automation testing token (used by the testing framework to bypass captcha. Same token must be defined in ../main.env)
|
|
21
|
+
TEST_RUNNER_BYPASS_TOKEN=same-as-in-main-env
|
|
@@ -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,7 @@ 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
|
+
automation_token = os.getenv('TEST_RUNNER_BYPASS_TOKEN')
|
|
74
76
|
|
|
75
77
|
# Use provided values or fall back to environment
|
|
76
78
|
self.base_url = url or env_url
|
|
@@ -125,14 +127,32 @@ class PlaywrightManager:
|
|
|
125
127
|
|
|
126
128
|
# Create context with recording enabled and proper viewport
|
|
127
129
|
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
|
|
134
|
-
|
|
135
|
-
|
|
130
|
+
context_kwargs = {
|
|
131
|
+
"record_video_dir": str(self.test_recordings_dir),
|
|
132
|
+
"record_video_size": video_size,
|
|
133
|
+
"record_har_path": str(self.har_path),
|
|
134
|
+
"record_har_omit_content": False,
|
|
135
|
+
"viewport": video_size
|
|
136
|
+
}
|
|
137
|
+
self.context = await self.browser.new_context(**context_kwargs)
|
|
138
|
+
if automation_token:
|
|
139
|
+
parsed_base = urlparse(self.base_url)
|
|
140
|
+
target_host = parsed_base.hostname
|
|
141
|
+
target_scheme = parsed_base.scheme or "http"
|
|
142
|
+
header_name = "X-Portacode-Automation"
|
|
143
|
+
|
|
144
|
+
async def automation_header_route(route, request):
|
|
145
|
+
headers = dict(request.headers)
|
|
146
|
+
parsed_request = urlparse(request.url)
|
|
147
|
+
if parsed_request.hostname == target_host and parsed_request.scheme == target_scheme:
|
|
148
|
+
headers[header_name] = automation_token
|
|
149
|
+
else:
|
|
150
|
+
headers.pop(header_name, None)
|
|
151
|
+
await route.continue_(headers=headers)
|
|
152
|
+
|
|
153
|
+
await self.context.route("**/*", automation_header_route)
|
|
154
|
+
self.logger.info("Automation bypass header restricted to same-origin requests")
|
|
155
|
+
|
|
136
156
|
self.logger.info(f"Video recording configured: {env_video_width}x{env_video_height}")
|
|
137
157
|
|
|
138
158
|
# Start tracing
|
|
@@ -178,7 +198,7 @@ class PlaywrightManager:
|
|
|
178
198
|
"""Perform login using provided credentials."""
|
|
179
199
|
try:
|
|
180
200
|
# Navigate to login page first
|
|
181
|
-
login_url = f"{self.base_url}
|
|
201
|
+
login_url = f"{self.base_url}accounts/login/"
|
|
182
202
|
await self.page.goto(login_url)
|
|
183
203
|
await self.log_action("navigate_to_login", {"url": login_url})
|
|
184
204
|
await self.take_screenshot("login_page")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|