simplex 1.2.11__py3-none-any.whl → 1.2.12__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 simplex might be problematic. Click here for more details.
- simplex/cli.py +54 -2
- simplex/deploy/push.py +8 -33
- simplex/simplex.py +55 -18
- {simplex-1.2.11.dist-info → simplex-1.2.12.dist-info}/METADATA +1 -1
- simplex-1.2.12.dist-info/RECORD +11 -0
- simplex-1.2.11.dist-info/RECORD +0 -11
- {simplex-1.2.11.dist-info → simplex-1.2.12.dist-info}/LICENSE +0 -0
- {simplex-1.2.11.dist-info → simplex-1.2.12.dist-info}/WHEEL +0 -0
- {simplex-1.2.11.dist-info → simplex-1.2.12.dist-info}/entry_points.txt +0 -0
- {simplex-1.2.11.dist-info → simplex-1.2.12.dist-info}/top_level.txt +0 -0
simplex/cli.py
CHANGED
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
import click
|
|
2
2
|
from .deploy import push_directory, run_directory
|
|
3
|
+
from .simplex import Simplex
|
|
3
4
|
import os
|
|
5
|
+
from dotenv import load_dotenv
|
|
6
|
+
import webbrowser
|
|
7
|
+
from colorama import init, Fore, Style
|
|
8
|
+
import time
|
|
9
|
+
import sys
|
|
10
|
+
|
|
11
|
+
init() # Initialize colorama
|
|
12
|
+
|
|
13
|
+
load_dotenv()
|
|
14
|
+
|
|
15
|
+
def animated_print(message, color=Fore.CYAN):
|
|
16
|
+
"""Print with animated ellipsis"""
|
|
17
|
+
for i in range(3):
|
|
18
|
+
sys.stdout.write(f'\r{color}{message}{"." * (i+1)}{" " * (2-i)}{Style.RESET_ALL}')
|
|
19
|
+
sys.stdout.flush()
|
|
20
|
+
time.sleep(0.5)
|
|
21
|
+
sys.stdout.write('\n')
|
|
4
22
|
|
|
5
23
|
@click.group()
|
|
6
24
|
def cli():
|
|
@@ -13,7 +31,7 @@ def push(directory):
|
|
|
13
31
|
try:
|
|
14
32
|
push_directory(directory)
|
|
15
33
|
except Exception as e:
|
|
16
|
-
print(f"Error running job: {e}")
|
|
34
|
+
print(f"{Fore.RED}[SIMPLEX] Error running job: {e}{Style.RESET_ALL}")
|
|
17
35
|
raise
|
|
18
36
|
|
|
19
37
|
|
|
@@ -24,8 +42,42 @@ def run(directory):
|
|
|
24
42
|
try:
|
|
25
43
|
run_directory(directory)
|
|
26
44
|
except Exception as e:
|
|
27
|
-
print(f"Error running job: {e}")
|
|
45
|
+
print(f"{Fore.RED}[SIMPLEX] Error running job: {e}{Style.RESET_ALL}")
|
|
28
46
|
raise
|
|
29
47
|
|
|
48
|
+
@cli.command()
|
|
49
|
+
@click.argument('website')
|
|
50
|
+
def login(website):
|
|
51
|
+
"""Capture login session for a website"""
|
|
52
|
+
try:
|
|
53
|
+
# Initialize Simplex with API key from environment
|
|
54
|
+
api_key = os.getenv("SIMPLEX_API_KEY")
|
|
55
|
+
if not api_key:
|
|
56
|
+
raise click.ClickException("SIMPLEX_API_KEY environment variable not set")
|
|
57
|
+
|
|
58
|
+
simplex = Simplex(api_key)
|
|
59
|
+
|
|
60
|
+
# Ensure website has proper URL format
|
|
61
|
+
if not website.startswith(('http://', 'https://')):
|
|
62
|
+
website = 'https://' + website
|
|
63
|
+
|
|
64
|
+
animated_print(f"[SIMPLEX] Creating login session for {website}")
|
|
65
|
+
result = simplex.capture_login_session(website)
|
|
66
|
+
|
|
67
|
+
if result.get('succeeded'):
|
|
68
|
+
# Open the login URL in a new browser tab
|
|
69
|
+
login_url = result.get('login_session_url')
|
|
70
|
+
if login_url:
|
|
71
|
+
animated_print("[SIMPLEX] Opening login page in your browser")
|
|
72
|
+
webbrowser.open_new_tab(login_url)
|
|
73
|
+
else:
|
|
74
|
+
print(f"{Fore.YELLOW}[SIMPLEX] Warning: No login URL returned from the server{Style.RESET_ALL}")
|
|
75
|
+
else:
|
|
76
|
+
print(f"{Fore.RED}[SIMPLEX] Failed to capture login session: {result.get('error', 'Unknown error')}{Style.RESET_ALL}")
|
|
77
|
+
except Exception as e:
|
|
78
|
+
raise click.ClickException(str(e))
|
|
79
|
+
finally:
|
|
80
|
+
print(f"{Fore.GREEN}[SIMPLEX] Login session closed.{Style.RESET_ALL}")
|
|
81
|
+
|
|
30
82
|
def main():
|
|
31
83
|
cli()
|
simplex/deploy/push.py
CHANGED
|
@@ -7,8 +7,7 @@ from dotenv import load_dotenv
|
|
|
7
7
|
import requests
|
|
8
8
|
from typing import Optional
|
|
9
9
|
from datetime import datetime, timedelta
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
load_dotenv() # This loads the .env file
|
|
12
11
|
|
|
13
12
|
S3_URL = "https://u3mvtbirxf.us-east-1.awsapprunner.com"
|
|
14
13
|
JOB_URL = "https://simplex--job-scheduler-app-handler.modal.run"
|
|
@@ -42,7 +41,6 @@ def create_archive(directory: str, config: dict) -> str:
|
|
|
42
41
|
|
|
43
42
|
def push_directory(directory: str):
|
|
44
43
|
"""Main function to handle parsing yaml and creating zip archive"""
|
|
45
|
-
|
|
46
44
|
config = read_config(directory)
|
|
47
45
|
archive_path = create_archive(directory, config)
|
|
48
46
|
|
|
@@ -55,7 +53,7 @@ def push_directory(directory: str):
|
|
|
55
53
|
raise ValueError("Cron schedule not specified in simplex.yaml")
|
|
56
54
|
|
|
57
55
|
try:
|
|
58
|
-
s3_uri = upload_files_to_s3(
|
|
56
|
+
s3_uri = upload_files_to_s3(archive_path, project_name)
|
|
59
57
|
except Exception as e:
|
|
60
58
|
print(f"Error uploading project: {e}")
|
|
61
59
|
raise
|
|
@@ -63,7 +61,7 @@ def push_directory(directory: str):
|
|
|
63
61
|
os.unlink(archive_path)
|
|
64
62
|
|
|
65
63
|
try:
|
|
66
|
-
create_job_scheduled(
|
|
64
|
+
create_job_scheduled(project_name, cron_schedule, s3_uri)
|
|
67
65
|
except Exception as e:
|
|
68
66
|
print(f"Error creating job: {e}")
|
|
69
67
|
raise
|
|
@@ -72,13 +70,7 @@ def push_directory(directory: str):
|
|
|
72
70
|
|
|
73
71
|
|
|
74
72
|
|
|
75
|
-
def upload_files_to_s3(
|
|
76
|
-
"""Upload files to S3"""
|
|
77
|
-
# Load .env file from the target directory
|
|
78
|
-
env_path = Path(directory) / '.env'
|
|
79
|
-
if env_path.exists():
|
|
80
|
-
load_dotenv(env_path)
|
|
81
|
-
|
|
73
|
+
def upload_files_to_s3(archive_path: str, project_name: str):
|
|
82
74
|
# Read API key from environment
|
|
83
75
|
api_key = os.getenv('SIMPLEX_API_KEY')
|
|
84
76
|
if not api_key:
|
|
@@ -115,14 +107,8 @@ def upload_files_to_s3(directory: str, archive_path: str, project_name: str):
|
|
|
115
107
|
print(f"Error uploading project: {e}")
|
|
116
108
|
raise
|
|
117
109
|
|
|
118
|
-
def create_job_scheduled(
|
|
110
|
+
def create_job_scheduled(project_name: str, cron_schedule: str, s3_uri: str):
|
|
119
111
|
"""Create a new job via the API"""
|
|
120
|
-
|
|
121
|
-
# Load .env file from the target directory
|
|
122
|
-
env_path = Path(directory) / '.env'
|
|
123
|
-
if env_path.exists():
|
|
124
|
-
load_dotenv(env_path)
|
|
125
|
-
|
|
126
112
|
# Read API key from environment
|
|
127
113
|
api_key = os.getenv('SIMPLEX_API_KEY')
|
|
128
114
|
if not api_key:
|
|
@@ -159,14 +145,8 @@ def create_job_scheduled(directory: str, project_name: str, cron_schedule: str,
|
|
|
159
145
|
raise
|
|
160
146
|
|
|
161
147
|
|
|
162
|
-
def create_job_immediately(
|
|
148
|
+
def create_job_immediately(project_name: str, s3_uri: str):
|
|
163
149
|
"""Create a new job via the API"""
|
|
164
|
-
|
|
165
|
-
# Load .env file from the target directory
|
|
166
|
-
env_path = Path(directory) / '.env'
|
|
167
|
-
if env_path.exists():
|
|
168
|
-
load_dotenv(env_path)
|
|
169
|
-
|
|
170
150
|
# Read API key from environment
|
|
171
151
|
api_key = os.getenv('SIMPLEX_API_KEY')
|
|
172
152
|
if not api_key:
|
|
@@ -205,11 +185,6 @@ def create_job_immediately(directory: str, project_name: str, s3_uri: str):
|
|
|
205
185
|
|
|
206
186
|
def run_directory(directory: str):
|
|
207
187
|
"""Run a directory immediately"""
|
|
208
|
-
# Load .env file from the target directory
|
|
209
|
-
env_path = Path(directory) / '.env'
|
|
210
|
-
if env_path.exists():
|
|
211
|
-
load_dotenv(env_path)
|
|
212
|
-
|
|
213
188
|
config = read_config(directory)
|
|
214
189
|
archive_path = create_archive(directory, config)
|
|
215
190
|
|
|
@@ -218,7 +193,7 @@ def run_directory(directory: str):
|
|
|
218
193
|
raise ValueError("Project name not specified in simplex.yaml")
|
|
219
194
|
|
|
220
195
|
try:
|
|
221
|
-
s3_uri = upload_files_to_s3(
|
|
196
|
+
s3_uri = upload_files_to_s3(archive_path, project_name)
|
|
222
197
|
except Exception as e:
|
|
223
198
|
print(f"Error uploading project: {e}")
|
|
224
199
|
raise
|
|
@@ -227,7 +202,7 @@ def run_directory(directory: str):
|
|
|
227
202
|
os.unlink(archive_path)
|
|
228
203
|
|
|
229
204
|
try:
|
|
230
|
-
create_job_immediately(
|
|
205
|
+
create_job_immediately(project_name, s3_uri)
|
|
231
206
|
except Exception as e:
|
|
232
207
|
print(f"Error creating job: {e}")
|
|
233
208
|
raise
|
simplex/simplex.py
CHANGED
|
@@ -3,24 +3,18 @@ import requests
|
|
|
3
3
|
import atexit
|
|
4
4
|
|
|
5
5
|
BASE_URL = "https://api.simplex.sh"
|
|
6
|
+
|
|
6
7
|
import json
|
|
7
8
|
|
|
8
9
|
class Simplex:
|
|
9
10
|
def __init__(self, api_key: str):
|
|
10
11
|
self.api_key = api_key
|
|
11
12
|
self.session_id = None
|
|
12
|
-
atexit.register(self.
|
|
13
|
-
|
|
14
|
-
def cleanup_session(self):
|
|
15
|
-
if self.session_id:
|
|
16
|
-
try:
|
|
17
|
-
self.close_session(self.session_id)
|
|
18
|
-
except:
|
|
19
|
-
pass
|
|
13
|
+
atexit.register(self.close_session)
|
|
20
14
|
|
|
21
15
|
def close_session(self):
|
|
22
16
|
response = requests.post(
|
|
23
|
-
f"{BASE_URL}/close",
|
|
17
|
+
f"{BASE_URL}/close-session",
|
|
24
18
|
headers={
|
|
25
19
|
'x-api-key': self.api_key
|
|
26
20
|
},
|
|
@@ -41,10 +35,6 @@ class Simplex:
|
|
|
41
35
|
self.session_id = response_json['session_id']
|
|
42
36
|
livestream_url = response_json['livestream_url']
|
|
43
37
|
|
|
44
|
-
print(f"\nSession created successfully!")
|
|
45
|
-
print(f"Session ID: {self.session_id}")
|
|
46
|
-
print(f"Livestream URL: {livestream_url}\n")
|
|
47
|
-
|
|
48
38
|
return self.session_id, livestream_url
|
|
49
39
|
|
|
50
40
|
def goto(self, url: str, cdp_url: str = None):
|
|
@@ -70,7 +60,7 @@ class Simplex:
|
|
|
70
60
|
)
|
|
71
61
|
return response.json()
|
|
72
62
|
|
|
73
|
-
def click(self, element_description: str, cdp_url: str = None):
|
|
63
|
+
def click(self, element_description: str, cdp_url: str = None, use_vision: bool = False):
|
|
74
64
|
if not cdp_url and not self.session_id:
|
|
75
65
|
raise ValueError(f"Must call create_session before calling action click with element_description='{element_description}'")
|
|
76
66
|
|
|
@@ -81,6 +71,9 @@ class Simplex:
|
|
|
81
71
|
else:
|
|
82
72
|
data['session_id'] = self.session_id
|
|
83
73
|
|
|
74
|
+
if use_vision:
|
|
75
|
+
data['use_vision'] = use_vision
|
|
76
|
+
|
|
84
77
|
response = requests.post(
|
|
85
78
|
f"{BASE_URL}/click",
|
|
86
79
|
headers={
|
|
@@ -268,11 +261,55 @@ class Simplex:
|
|
|
268
261
|
)
|
|
269
262
|
return response.json()
|
|
270
263
|
|
|
271
|
-
def
|
|
264
|
+
def click_and_upload(self, element_description: str, file_path: str):
|
|
265
|
+
if not self.session_id:
|
|
266
|
+
raise ValueError(f"Must call create_session before calling action click_and_upload with element_description='{element_description}'")
|
|
267
|
+
|
|
268
|
+
files = {
|
|
269
|
+
'zip_file': open(file_path, 'rb')
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
data = {
|
|
273
|
+
'element_description': element_description
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
data['session_id'] = self.session_id
|
|
277
|
+
|
|
278
|
+
response = requests.post(
|
|
279
|
+
f"{BASE_URL}/click_and_upload",
|
|
280
|
+
headers={
|
|
281
|
+
'x-api-key': self.api_key
|
|
282
|
+
},
|
|
283
|
+
files=files,
|
|
284
|
+
data=data
|
|
285
|
+
)
|
|
286
|
+
return response.json()
|
|
287
|
+
|
|
288
|
+
def click_and_download(self, element_description: str):
|
|
289
|
+
if not self.session_id:
|
|
290
|
+
raise ValueError(f"Must call create_session before calling action click_and_download with element_description='{element_description}'")
|
|
291
|
+
|
|
292
|
+
data = {
|
|
293
|
+
'element_description': element_description
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
data['session_id'] = self.session_id
|
|
297
|
+
|
|
298
|
+
response = requests.post(
|
|
299
|
+
f"{BASE_URL}/click_and_download",
|
|
300
|
+
headers={
|
|
301
|
+
'x-api-key': self.api_key
|
|
302
|
+
},
|
|
303
|
+
data=data
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
return response.json()
|
|
307
|
+
|
|
308
|
+
def exists(self, element_description: str, cdp_url: str = None):
|
|
272
309
|
if not cdp_url and not self.session_id:
|
|
273
|
-
raise ValueError(f"Must call create_session before calling action
|
|
310
|
+
raise ValueError(f"Must call create_session before calling action exists with element_description='{element_description}'")
|
|
274
311
|
|
|
275
|
-
data = {'
|
|
312
|
+
data = {'element_description': element_description}
|
|
276
313
|
|
|
277
314
|
if cdp_url:
|
|
278
315
|
data['cdp_url'] = cdp_url
|
|
@@ -280,7 +317,7 @@ class Simplex:
|
|
|
280
317
|
data['session_id'] = self.session_id
|
|
281
318
|
|
|
282
319
|
response = requests.post(
|
|
283
|
-
f"{BASE_URL}/
|
|
320
|
+
f"{BASE_URL}/exists",
|
|
284
321
|
headers={
|
|
285
322
|
'x-api-key': self.api_key
|
|
286
323
|
},
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
simplex/__init__.py,sha256=1mbM4XUk0FNW161WOkM4ayC1s_QSsaBEls6PZ0iBScY,74
|
|
2
|
+
simplex/cli.py,sha256=yirCLDIF7u0d6LIDY2WWZ5IJJrlxdNsGv9B3H8nh34U,2643
|
|
3
|
+
simplex/simplex.py,sha256=B6IJ1Ua0wLNXZDmEOkDN-WvXtPZmXS5VOgKb48KLB9I,9784
|
|
4
|
+
simplex/deploy/__init__.py,sha256=_JQ81F_Nu7hSAfMA691gzs6a4-8oZ-buJ9h3Au12BKw,96
|
|
5
|
+
simplex/deploy/push.py,sha256=hRAbtFZaECKnBljaOLQ5nzJ6hk7tZgc1c7QdgxKQFoY,6123
|
|
6
|
+
simplex-1.2.12.dist-info/LICENSE,sha256=Xh0SJjYZfNI71pCNMB40aKlBLLuOB0blx5xkTtufFNQ,1075
|
|
7
|
+
simplex-1.2.12.dist-info/METADATA,sha256=-CnNY6j8ZYWSiPUdvFXnDAkXXxxeDJbdRX1qSl7leH0,1350
|
|
8
|
+
simplex-1.2.12.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
9
|
+
simplex-1.2.12.dist-info/entry_points.txt,sha256=3veL2w3c5vxb3dm8I_M8Fs-370n1ZnvD8uu1nSsL7z8,45
|
|
10
|
+
simplex-1.2.12.dist-info/top_level.txt,sha256=cbMH1bYpN0A3gP-ecibPRHasHoqB-01T_2BUFS8p0CE,8
|
|
11
|
+
simplex-1.2.12.dist-info/RECORD,,
|
simplex-1.2.11.dist-info/RECORD
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
simplex/__init__.py,sha256=1mbM4XUk0FNW161WOkM4ayC1s_QSsaBEls6PZ0iBScY,74
|
|
2
|
-
simplex/cli.py,sha256=PkHt3sBKYfu0Smil4aCMoZUD-JbPw8xsBewpFcBYDKM,675
|
|
3
|
-
simplex/simplex.py,sha256=wXys677gzVGlsPPdILNJi03mjNKo6fOfyGntD4Pa3Gg,8624
|
|
4
|
-
simplex/deploy/__init__.py,sha256=_JQ81F_Nu7hSAfMA691gzs6a4-8oZ-buJ9h3Au12BKw,96
|
|
5
|
-
simplex/deploy/push.py,sha256=RB2ZL-jTiLNvdLDD-TqibHM5I9WCmH7DXsIgtWBLjcs,6795
|
|
6
|
-
simplex-1.2.11.dist-info/LICENSE,sha256=Xh0SJjYZfNI71pCNMB40aKlBLLuOB0blx5xkTtufFNQ,1075
|
|
7
|
-
simplex-1.2.11.dist-info/METADATA,sha256=eMWpq4E-4rGapzadf-SJQI5yTFDQ2jz5Ra7zC0dGets,1350
|
|
8
|
-
simplex-1.2.11.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
9
|
-
simplex-1.2.11.dist-info/entry_points.txt,sha256=3veL2w3c5vxb3dm8I_M8Fs-370n1ZnvD8uu1nSsL7z8,45
|
|
10
|
-
simplex-1.2.11.dist-info/top_level.txt,sha256=cbMH1bYpN0A3gP-ecibPRHasHoqB-01T_2BUFS8p0CE,8
|
|
11
|
-
simplex-1.2.11.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|