parsagon 0.10.17__py3-none-any.whl → 0.10.20__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.
parsagon/executor.py CHANGED
@@ -10,6 +10,8 @@ from urllib.parse import urljoin
10
10
  import lxml.html
11
11
  from pyvirtualdisplay import Display
12
12
  import undetected_chromedriver as uc
13
+ from selenium import webdriver
14
+ from selenium.webdriver.chrome.service import Service as ChromeService
13
15
  from selenium.webdriver.chrome.options import Options
14
16
  from selenium.webdriver.common.action_chains import ActionChains
15
17
  from selenium.webdriver.common.by import By
@@ -60,14 +62,19 @@ class Executor:
60
62
  Executes code produced by GPT with the proper context. Records custom_function usage along the way.
61
63
  """
62
64
 
63
- def __init__(self, headless=False, infer=False):
65
+ def __init__(self, headless=False, infer=False, use_uc=False):
64
66
  self.headless = headless
65
67
  if self.headless:
66
68
  self.display = Display(visible=False, size=(1280, 1050)).start()
67
- chrome_options = uc.ChromeOptions()
68
- chrome_options.add_argument("--start-maximized")
69
- driver_exec_path = ChromeDriverManager().install()
70
- self.driver = uc.Chrome(driver_executable_path=driver_exec_path, options=chrome_options)
69
+ driver_executable_path = ChromeDriverManager().install()
70
+ if use_uc:
71
+ chrome_options = uc.ChromeOptions()
72
+ chrome_options.add_argument("--start-maximized")
73
+ self.driver = uc.Chrome(driver_executable_path=driver_executable_path, options=chrome_options)
74
+ else:
75
+ chrome_options = webdriver.ChromeOptions()
76
+ chrome_options.add_argument("--start-maximized")
77
+ self.driver = webdriver.Chrome(service=ChromeService(driver_executable_path), options=chrome_options)
71
78
  self.max_elem_ids = defaultdict(int)
72
79
  self.execution_context = {
73
80
  "custom_assert": self.custom_assert,
@@ -553,7 +560,10 @@ class Executor:
553
560
  finally:
554
561
  self.driver.quit()
555
562
  for proc in psutil.process_iter():
556
- if proc.name() == "chromedriver":
557
- proc.kill()
563
+ try:
564
+ if proc.name() == "chromedriver":
565
+ proc.kill()
566
+ except psutil.NoSuchProcess:
567
+ continue
558
568
  if self.headless:
559
569
  self.display.stop()
parsagon/highlights.js CHANGED
@@ -128,14 +128,24 @@ function hasValidData(element, dataType) {
128
128
  return true;
129
129
  }
130
130
 
131
- function makeVisible(element) {
132
- const rects = element.getClientRects();
133
- if (rects.length) {
134
- const rect = rects[0];
135
- if (rect.width * rect.height === 0) {
136
- element.style.display = 'block';
131
+ function makeVisible(elements) {
132
+
133
+ let elemsToDisplayBlock = [];
134
+ for (let element of elements) {
135
+ const rects = element.getClientRects();
136
+ if (rects.length) {
137
+ const rect = rects[0];
138
+ if (rect.width * rect.height === 0) {
139
+ elemsToDisplayBlock.push(element);
140
+ }
137
141
  }
138
142
  }
143
+
144
+ requestAnimationFrame(() => {
145
+ for (let elem of elemsToDisplayBlock) {
146
+ elem.style.display = 'block';
147
+ }
148
+ })
139
149
  }
140
150
 
141
151
  const DUMMY_FRAGMENT = document.createDocumentFragment()
@@ -241,28 +251,45 @@ function removeTargetStoredCSS(element) {
241
251
  element.style.removeProperty('position');
242
252
  element.classList.remove(TARGET_STORED_CLASSNAME);
243
253
  if (element.classList.contains(AUTOCOMPLETE_CLASSNAME)) {
244
- addAutocompleteCSS(element);
254
+ addAutocompleteCSS([element]);
245
255
  } else if (element.classList.contains(MOUSE_VISITED_CLASSNAME)) {
246
256
  addMouseVisitedCSS(element);
247
257
  }
248
258
  };
249
- function addAutocompleteCSS(element) {
250
- if (!element.classList.contains(TARGET_STORED_CLASSNAME)) {
251
- element.style.setProperty(
252
- 'outline',
253
- '3px solid rgb(255, 177, 255)',
254
- 'important'
255
- );
256
- element.style.setProperty('outline-offset', '-3px', 'important');
257
- if (
258
- window.getComputedStyle(element)
259
- .position === 'static'
260
- ) {
261
- element.style.setProperty('position', 'relative', 'important');
259
+ function addAutocompleteCSS(elements) {
260
+ let setOutlineElements = [];
261
+ let makeStaticElements = [];
262
+ for (const element of elements) {
263
+ if (!element.classList.contains(TARGET_STORED_CLASSNAME)) {
264
+ setOutlineElements.push(element);
265
+ if (
266
+ window.getComputedStyle(element)
267
+ .position === 'static'
268
+ ) {
269
+ makeStaticElements.push(element);
270
+ }
262
271
  }
263
272
  }
264
- element.classList.add(AUTOCOMPLETE_CLASSNAME);
273
+
274
+ // Perform batch writes
275
+ requestAnimationFrame(() => {
276
+ for (const element of setOutlineElements) {
277
+ element.style.setProperty(
278
+ 'outline',
279
+ '3px solid rgb(255, 177, 255)',
280
+ 'important'
281
+ );
282
+ element.style.setProperty('outline-offset', '-3px', 'important');
283
+ }
284
+ for (const element of makeStaticElements) {
285
+ element.style.setProperty('position', 'relative', 'important');
286
+ }
287
+ for (const element of elements) {
288
+ element.classList.add(AUTOCOMPLETE_CLASSNAME);
289
+ }
290
+ });
265
291
  };
292
+
266
293
  function removeAutocompleteCSS(element) {
267
294
  element.style.removeProperty('outline');
268
295
  element.style.removeProperty('outline-offset');
@@ -300,13 +327,13 @@ function addAutocompletes() {
300
327
  document.querySelectorAll(
301
328
  cssSelector
302
329
  );
303
- for (const elem of similarElems) {
304
- if (elem.classList.contains(TARGET_STORED_CLASSNAME)) {
305
- continue;
306
- }
307
- makeVisible(elem);
308
- addAutocompleteCSS(elem);
309
- }
330
+
331
+ // Set to similarElems where elem.classList.contains(TARGET_STORED_CLASSNAME) === false
332
+ const elemsToMakeVisibleAndAddAutocompleteCSS = Array.from(similarElems).filter((elem) => {
333
+ return !elem.classList.contains(TARGET_STORED_CLASSNAME);
334
+ });
335
+ makeVisible(elemsToMakeVisibleAndAddAutocompleteCSS);
336
+ addAutocompleteCSS(elemsToMakeVisibleAndAddAutocompleteCSS);
310
337
  }
311
338
  };
312
339
 
@@ -496,7 +523,7 @@ function handleMouseMove(e) {
496
523
  return;
497
524
  }
498
525
 
499
- makeVisible(srcElement);
526
+ makeVisible([srcElement]);
500
527
 
501
528
  addMouseVisitedCSS(srcElement);
502
529
  window.prevDOM = srcElement;
parsagon/main.py CHANGED
@@ -325,8 +325,11 @@ def run(program_name, variables={}, headless=False, remote=False, verbose=False)
325
325
  if "display" in globals_locals:
326
326
  globals_locals["display"].stop()
327
327
  for proc in psutil.process_iter():
328
- if proc.name() == "chromedriver":
329
- proc.kill()
328
+ try:
329
+ if proc.name() == "chromedriver":
330
+ proc.kill()
331
+ except psutil.NoSuchProcess:
332
+ continue
330
333
  logger.info("Done.")
331
334
  return globals_locals["output"]
332
335
 
@@ -359,6 +362,8 @@ def batch_runs(batch_name, program_name, runs=[], headless=False, ignore_errors=
359
362
  pbar.set_description(f"An error occurred: {e} - Waiting 60s before retrying (Attempt {j+2}/3)")
360
363
  time.sleep(60)
361
364
  pbar.set_description(default_desc)
365
+ error = None
366
+ error_variables = None
362
367
  continue
363
368
  else:
364
369
  if ignore_errors:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: parsagon
3
- Version: 0.10.17
3
+ Version: 0.10.20
4
4
  Summary: Allows you to create browser automations with natural language
5
5
  Author-email: Sandy Suh <sandy@parsagon.io>
6
6
  Project-URL: Homepage, https://parsagon.io
@@ -17,8 +17,8 @@ Requires-Dist: tqdm ==4.66.1
17
17
  Requires-Dist: PyVirtualDisplay ==3.0
18
18
  Requires-Dist: selenium-wire ==5.1.0
19
19
  Requires-Dist: cssselect ==1.1.0
20
- Requires-Dist: undetected-chromedriver ==3.5.2
21
- Requires-Dist: webdriver-manager ==4.0.0
20
+ Requires-Dist: undetected-chromedriver ==3.5.3
21
+ Requires-Dist: webdriver-manager ==4.0.1
22
22
  Requires-Dist: jsonpath-ng ==1.5.3
23
23
  Requires-Dist: simplejson ==3.19.1
24
24
  Provides-Extra: dev
@@ -75,6 +75,9 @@ parsagon.create('Go to https://www.google.com/. Type "the meaning of life" into
75
75
  # Run a program
76
76
  parsagon.run("My program")
77
77
 
78
+ # Run a program multiple times
79
+ parsagon.batch_runs("My batch name", "My program", runs=[{"variable_name": "value1"}, {"variable_name": "value2"}, ...])
80
+
78
81
  # List your programs
79
82
  parsagon.detail()
80
83
 
@@ -2,9 +2,9 @@ parsagon/__init__.py,sha256=n4-wiFVVuyW_KOJeNiycggAg9BTa5bbBIVpD_DkdOO4,125
2
2
  parsagon/api.py,sha256=eJULOzTyWqA4Mio7tH9PszwTrZyxRBI0uO9t1h3R7rw,6634
3
3
  parsagon/custom_function.py,sha256=oEj28qItaHUnsvLIHD7kg5QL3J3aO6rW6xKKP-H-Drs,770
4
4
  parsagon/exceptions.py,sha256=NYpFaSLZplBTv9fov_1LKPzDPIqb7Ffe7IunnjntxvA,819
5
- parsagon/executor.py,sha256=q_FcRVef8ExE6kP_TRuqCII-ZOXE6ddcvo8ysyUH5eU,22285
6
- parsagon/highlights.js,sha256=bm8OcDMgSMUJw_b_pJ-qN0W2fS-JnGZR14LQrPnIf1U,15690
7
- parsagon/main.py,sha256=jcXbKY3h3ZSvQOX7SRDC_fl3VqDu4N_Zbi8jdn2hQN0,14561
5
+ parsagon/executor.py,sha256=e_e9p5eLvf7wYHk1BNJf0j_qt0H17BfivPb8CoOKMHE,22791
6
+ parsagon/highlights.js,sha256=2UDfUApblU9xtGgTLCq4X7rHRV0wcqDSSFZPmJS6fJg,16643
7
+ parsagon/main.py,sha256=yQbIzqJ7Ea6XZJ3Eolx2lTh7Di87qPJvDI0WRNeoX14,14736
8
8
  parsagon/settings.py,sha256=s5_MsDMFM5tB8U8tfHaFnKibCoEqPnAu8b_ueg07Ftw,2947
9
9
  parsagon/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  parsagon/tests/api_mocks.py,sha256=M8xhiyPa1dI8Vx-odDk7ETopfFAfcjfAf-ApmSqgvfw,3127
@@ -13,8 +13,8 @@ parsagon/tests/conftest.py,sha256=KMlHohc0QT77HzumraIojzKeqroyxarnaT6naJDNvEc,42
13
13
  parsagon/tests/test_executor.py,sha256=n3cmh84r74siSeJqUeAIwjjnNzDVPEdxcvYAeJ4hNX8,645
14
14
  parsagon/tests/test_invalid_args.py,sha256=kOjMpbZvviR1CwvXReteZMxBvuhq_rOv5Tm1muBSzNk,676
15
15
  parsagon/tests/test_pipeline_operations.py,sha256=TpBKCuRA8LHYWx3PD_k9mYCSsA_9SZjrOX-rS4mE8XE,1089
16
- parsagon-0.10.17.dist-info/METADATA,sha256=mqwE98S_AMJtqUVqeJTp5B7z2a_mOAfpyqXeCXxBZOs,2257
17
- parsagon-0.10.17.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
18
- parsagon-0.10.17.dist-info/entry_points.txt,sha256=I1UlPUb4oY2k9idkI8kvdkEcrjKGRSOl5pMbA6uu6kw,48
19
- parsagon-0.10.17.dist-info/top_level.txt,sha256=ih5uYQzW4qjhRKppys-WiHLIbXVZ99YdqDcfAtlcQwk,9
20
- parsagon-0.10.17.dist-info/RECORD,,
16
+ parsagon-0.10.20.dist-info/METADATA,sha256=vA0gDtSRv8FeLScDZJHTNQjSgBw2MaAetLcrDJ9bIaw,2410
17
+ parsagon-0.10.20.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
18
+ parsagon-0.10.20.dist-info/entry_points.txt,sha256=I1UlPUb4oY2k9idkI8kvdkEcrjKGRSOl5pMbA6uu6kw,48
19
+ parsagon-0.10.20.dist-info/top_level.txt,sha256=ih5uYQzW4qjhRKppys-WiHLIbXVZ99YdqDcfAtlcQwk,9
20
+ parsagon-0.10.20.dist-info/RECORD,,