cucu 1.0.4__py3-none-any.whl → 1.0.7__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 cucu might be problematic. Click here for more details.

cucu/cli/core.py CHANGED
@@ -4,6 +4,7 @@ import json
4
4
  import os
5
5
  import shutil
6
6
  import signal
7
+ import sys
7
8
  import time
8
9
  import xml.etree.ElementTree as ET
9
10
  from importlib.metadata import version
@@ -189,6 +190,7 @@ def main():
189
190
  "--workers",
190
191
  default=None,
191
192
  help="Specifies the number of workers to use to run tests in parallel",
193
+ type=int,
192
194
  )
193
195
  @click.option(
194
196
  "--verbose/--no-verbose",
@@ -338,11 +340,20 @@ def run(
338
340
  if os.path.isdir(filepath):
339
341
  basepath = os.path.join(filepath, "**/*.feature")
340
342
  feature_filepaths = list(glob.iglob(basepath, recursive=True))
341
-
342
343
  else:
343
344
  feature_filepaths = [filepath]
344
345
 
345
- with WorkerPool(n_jobs=int(workers), start_method="spawn") as pool:
346
+ if sys.platform == "darwin":
347
+ logger.info(
348
+ "MAC OS detected, using 'forkserver' start method since 'fork' is unstable"
349
+ )
350
+ start_method = "forkserver"
351
+ else:
352
+ start_method = "fork"
353
+
354
+ with WorkerPool(
355
+ n_jobs=int(workers), start_method=start_method
356
+ ) as pool:
346
357
  # Each feature file is applied to the pool as an async task.
347
358
  # It then polls the async result of each task. It the result
348
359
  # is ready, it removes the result from the list of results that
@@ -364,6 +375,34 @@ def run(
364
375
  timer = Timer(runtime_timeout, runtime_exit)
365
376
  timer.start()
366
377
 
378
+ def kill_workers():
379
+ for worker in pool._workers:
380
+ try:
381
+ worker_proc = psutil.Process(worker.pid)
382
+ for child in worker_proc.children():
383
+ child.kill()
384
+
385
+ worker_proc.kill()
386
+ except psutil.NoSuchProcess:
387
+ pass
388
+
389
+ def handle_kill_signal(signum, frame):
390
+ signal.signal(
391
+ signum, signal.SIG_IGN
392
+ ) # ignore additional signals
393
+ logger.warn(
394
+ f"received signal {signum}, sending kill signal to workers"
395
+ )
396
+ kill_workers()
397
+ if timer:
398
+ timer.cancel()
399
+
400
+ os.kill(os.getpid(), signal.SIGINT)
401
+
402
+ # This is for local runs where you want to cancel the run with a ctrl+c or SIGTERM
403
+ signal.signal(signal.SIGINT, handle_kill_signal)
404
+ signal.signal(signal.SIGTERM, handle_kill_signal)
405
+
367
406
  async_results = {}
368
407
  for feature_filepath in feature_filepaths:
369
408
  async_results[feature_filepath] = pool.apply_async(
@@ -430,15 +469,7 @@ def run(
430
469
 
431
470
  if timeout_reached:
432
471
  logger.warn("Timeout reached, send kill signal to workers")
433
- for worker in pool._workers:
434
- try:
435
- worker_proc = psutil.Process(worker.pid)
436
- for child in worker_proc.children():
437
- child.kill()
438
-
439
- worker_proc.kill()
440
- except psutil.NoSuchProcess:
441
- pass
472
+ kill_workers()
442
473
 
443
474
  task_failed.update(async_results)
444
475
 
@@ -41,30 +41,125 @@ def upload_file_to_input(ctx, filepath, name):
41
41
 
42
42
 
43
43
  JS_DROP_FILE = """
44
- var target = arguments[0],
45
- offsetX = arguments[1],
46
- offsetY = arguments[2],
47
- document = target.ownerDocument || document,
48
- window = document.defaultView || window;
49
-
50
- var input = document.createElement('INPUT');
51
- input.type = 'file';
52
- input.onchange = function () {
53
- var rect = target.getBoundingClientRect(),
54
- x = rect.left + (offsetX || (rect.width >> 1)),
55
- y = rect.top + (offsetY || (rect.height >> 1)),
56
- dataTransfer = { files: this.files };
57
-
58
- ['dragenter', 'dragover', 'drop'].forEach(function (name) {
59
- var evt = document.createEvent('MouseEvent');
60
- evt.initMouseEvent(name, !0, !0, window, 0, 0, 0, x, y, !1, !1, !1, !1, 0, null);
61
- evt.dataTransfer = dataTransfer;
62
- target.dispatchEvent(evt);
63
- });
64
-
65
- setTimeout(function () { document.body.removeChild(input); }, 25);
44
+ var args = arguments,
45
+ element = args[0],
46
+ offsetX = args[1],
47
+ offsetY = args[2],
48
+ doc = element.ownerDocument || document;
49
+
50
+ var box = element.getBoundingClientRect(),
51
+ clientX = box.left + (offsetX || box.width / 2),
52
+ clientY = box.top + (offsetY || box.height / 2),
53
+ target = doc.elementFromPoint(clientX, clientY);
54
+ if (!(target && element.contains(target))) {
55
+ element.scrollIntoView({
56
+ behavior: "instant",
57
+ block: "center",
58
+ inline: "center",
59
+ });
60
+ var box = element.getBoundingClientRect(),
61
+ clientX = box.left + (offsetX || box.width / 2),
62
+ clientY = box.top + (offsetY || box.height / 2),
63
+ target = doc.elementFromPoint(clientX, clientY);
64
+
65
+ if (!(target && element.contains(target))) {
66
+ // Scrolling didn't do the trick, so give up
67
+ var ex = new Error("Element not interactable");
68
+ ex.code = 15;
69
+ throw ex;
70
+ }
71
+ }
72
+
73
+ var input = doc.createElement("INPUT");
74
+ input.setAttribute("type", "file");
75
+ input.setAttribute("multiple", "");
76
+ input.setAttribute("style", "position:fixed;z-index:2147483647;left:0;top:0;");
77
+ input.onchange = function (ev) {
78
+ input.parentElement.removeChild(input);
79
+ ev.stopPropagation();
80
+
81
+ var dataTransfer = {
82
+ constructor: DataTransfer,
83
+ effectAllowed: "all",
84
+ dropEffect: "none",
85
+ types: ["Files"],
86
+ files: input.files,
87
+ setData: function setData() {},
88
+ getData: function getData() {},
89
+ clearData: function clearData() {},
90
+ setDragImage: function setDragImage() {},
66
91
  };
67
- document.body.appendChild(input);
92
+
93
+ if (window.DataTransferItemList) {
94
+ dataTransfer.items = Object.setPrototypeOf(
95
+ Array.prototype.map.call(input.files, function (f) {
96
+ return {
97
+ constructor: DataTransferItem,
98
+ kind: "file",
99
+ type: f.type,
100
+ getAsFile: function getAsFile() {
101
+ return f;
102
+ },
103
+ getAsString: function getAsString(callback) {
104
+ var reader = new FileReader();
105
+ reader.onload = function (ev) {
106
+ callback(ev.target.result);
107
+ };
108
+ reader.readAsText(f);
109
+ },
110
+ webkitGetAsEntry: function webkitGetAsEntry() {
111
+ return {
112
+ constructor: window.FileSystemEntry || window.Entry,
113
+ name: f.name,
114
+ fullPath: "/" + f.name,
115
+ isFile: true,
116
+ isDirectory: false,
117
+ file: function file(callback) {
118
+ callback(f);
119
+ },
120
+ };
121
+ },
122
+ };
123
+ }),
124
+ {
125
+ constructor: DataTransferItemList,
126
+ add: function add() {},
127
+ clear: function clear() {},
128
+ remove: function remove() {},
129
+ }
130
+ );
131
+ }
132
+
133
+ ["dragenter", "dragover", "drop"].forEach(function (type) {
134
+ var event = doc.createEvent("DragEvent");
135
+ event.initMouseEvent(
136
+ type,
137
+ true,
138
+ true,
139
+ doc.defaultView,
140
+ 0,
141
+ 0,
142
+ 0,
143
+ clientX,
144
+ clientY,
145
+ false,
146
+ false,
147
+ false,
148
+ false,
149
+ 0,
150
+ null
151
+ );
152
+
153
+ Object.setPrototypeOf(event, null);
154
+ event.dataTransfer = dataTransfer;
155
+ Object.setPrototypeOf(event, DragEvent.prototype);
156
+
157
+ target.dispatchEvent(event);
158
+ });
159
+ };
160
+
161
+ doc.documentElement.appendChild(input);
162
+ input.getBoundingClientRect(); /* force reflow for Firefox */
68
163
  return input;
69
164
  """
70
165
 
@@ -1,10 +1,11 @@
1
+ import socket
1
2
  from functools import partial
2
3
  from http.server import HTTPServer, SimpleHTTPRequestHandler
3
4
  from threading import Thread
4
5
 
5
6
  from behave import step
6
7
 
7
- from cucu import register_after_this_scenario_hook
8
+ from cucu import logger, register_after_this_scenario_hook
8
9
  from cucu.config import CONFIG
9
10
 
10
11
 
@@ -33,6 +34,9 @@ def run_webserver_for_scenario(ctx, directory, variable):
33
34
  _, port = httpd.server_address
34
35
  CONFIG[variable] = str(port)
35
36
 
37
+ with socket.create_connection(("localhost", port), timeout=5):
38
+ logger.debug(f"Webserver is running at {port=}port")
39
+
36
40
  def shutdown_webserver(_):
37
41
  httpd.shutdown()
38
42
  thread.join()
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: cucu
3
- Version: 1.0.4
3
+ Version: 1.0.7
4
4
  Summary: Easy BDD web testing
5
5
  Project-URL: Homepage, https://github.com/dominodatalab/cucu
6
6
  Project-URL: Download, https://pypi.org/project/cucu/
@@ -34,14 +34,14 @@ Requires-Dist: geckodriver-autoinstaller~=0.1.0
34
34
  Requires-Dist: humanize~=4.8.0
35
35
  Requires-Dist: importlib-metadata~=8.0.0
36
36
  Requires-Dist: ipdb~=0.13.13
37
- Requires-Dist: jellyfish~=1.0.1
37
+ Requires-Dist: jellyfish~=1.1.3
38
38
  Requires-Dist: jinja2~=3.1.3
39
39
  Requires-Dist: lsprotocol~=2023.0.1
40
40
  Requires-Dist: mpire~=2.10.2
41
41
  Requires-Dist: psutil~=6.0.0
42
42
  Requires-Dist: pygls~=1.3.1
43
43
  Requires-Dist: pyyaml~=6.0.1
44
- Requires-Dist: requests~=2.31.0
44
+ Requires-Dist: requests<3.0.0,>=2.31.0
45
45
  Requires-Dist: selenium~=4.15
46
46
  Requires-Dist: tabulate~=0.9.0
47
47
  Requires-Dist: tenacity~=9.0.0
@@ -14,7 +14,7 @@ cucu/browser/frames.py,sha256=IW7kzRJn5PkbMaovIelAeCWO-T-2sOTwqaYBw-0-LKU,3545
14
14
  cucu/browser/selenium.py,sha256=c3B6IShD8Es-TGW-dxxNibGItJ4WEQI_xJpgc6uL6-E,11613
15
15
  cucu/browser/selenium_tweaks.py,sha256=oUIhWVhBZbc9qsmQUJMpIr9uUWKxtgZBcnySWU6Yttk,879
16
16
  cucu/cli/__init__.py,sha256=uXX5yVG1konJ_INdlrcfMg-Tt_5_cSx29Ed8R8v908A,62
17
- cucu/cli/core.py,sha256=OAdjT0_4I4sPCOgEssYW0ihKLu-z2vuses-H5MUQRgU,23089
17
+ cucu/cli/core.py,sha256=qFEEmTrj2avKoyYtPqQjd-tgvHp8R21NCtP_pknwEos,24225
18
18
  cucu/cli/run.py,sha256=e2JR77YF-7YSC4nCjogPcIsfoH7T43dAz5x_eeeue6k,5906
19
19
  cucu/cli/steps.py,sha256=hxsLymlYvF0uqUkDVq3s6heABkYnRo_SdQCpBdpb0e0,4009
20
20
  cucu/cli/thread_dumper.py,sha256=Z3XnYSxidx6pqjlQ7zu-TKMIYZWk4z9c5YLdPkcemiU,1593
@@ -60,7 +60,7 @@ cucu/steps/command_steps.py,sha256=nVCc8-TEitetk-zhk4z1wa0owqLQyHeQVH5THioUw-k,5
60
60
  cucu/steps/comment_steps.py,sha256=KcU0Ya8XSjYEh8gdUGh0qsAxgB_Ru977E84yJaXrvz0,379
61
61
  cucu/steps/draggable_steps.py,sha256=lnQLicp0GZJaxD_Qm2P13ruUZAsl3mptwaI5-SQ6XJ0,4655
62
62
  cucu/steps/dropdown_steps.py,sha256=abykG--m79kDQ4LU1tm73fNLFPmrKDavyFzJb2MYCu0,15601
63
- cucu/steps/file_input_steps.py,sha256=U-glhJN62cBGZMsqhegoCVvqo_GLGQowVb9VO2WmQ98,2812
63
+ cucu/steps/file_input_steps.py,sha256=LLMAozVpceLMD-kJOE-auKHAdWLbNprH8eCfVQuNoGg,5523
64
64
  cucu/steps/filesystem_steps.py,sha256=8l37A-yPxT4Mzdi1JNSTShZkwyFxgSwnh6C0V-hM_RA,4741
65
65
  cucu/steps/flow_control_steps.py,sha256=vlW0CsphVS9NvrOnpT8wSS2ngHmO3Z87H9siKIQwsAw,6365
66
66
  cucu/steps/image_steps.py,sha256=4X6bdumsIybcJBuao83TURxWAIshZyCvKi1uTJEoy1k,941
@@ -75,9 +75,9 @@ cucu/steps/table_steps.py,sha256=XB-NTwuue5LCXGlLZLex0QcRKOSrc4UA_F4Kj6l-J78,137
75
75
  cucu/steps/tables.js,sha256=Os2a7Fo-cg03XVli7USvcnBVad4N7idXr-HBuzdLvVQ,945
76
76
  cucu/steps/text_steps.py,sha256=Jj_GHoHeemNwVdUOdqcehArNp7WM-WMjljA4w0pLXuw,2576
77
77
  cucu/steps/variable_steps.py,sha256=WSctH3_xcxjijGPYZlxp-foC_SIAAKtF__saNtgZJbk,2966
78
- cucu/steps/webserver_steps.py,sha256=_bvqJxF8BSIIufNItZMSyjijEJEEPJbEvwnqPHoM9Tg,1259
79
- cucu-1.0.4.dist-info/METADATA,sha256=yLEP4pCBUrnEfeASyxMahBAy6SEX47S_hAt5HzkmPOk,16238
80
- cucu-1.0.4.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
81
- cucu-1.0.4.dist-info/entry_points.txt,sha256=YEXTyEfIZbcV0GJ9R3Gfu3j6DcOJJK7_XHkJqE3Yiao,39
82
- cucu-1.0.4.dist-info/licenses/LICENSE,sha256=WfgJYF9EaQoL_OeWr2Qd0MxhhFegDfzWSUmvDTwFxis,1721
83
- cucu-1.0.4.dist-info/RECORD,,
78
+ cucu/steps/webserver_steps.py,sha256=wWkpSvcSMdiskPkh4cqlepWx1nkvEpTU2tRXQmPDbyo,1410
79
+ cucu-1.0.7.dist-info/METADATA,sha256=EGuVc5vJmj6BjOYIEwPQByWkoXhr1ip91MbnPcVzAZk,16245
80
+ cucu-1.0.7.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
81
+ cucu-1.0.7.dist-info/entry_points.txt,sha256=YEXTyEfIZbcV0GJ9R3Gfu3j6DcOJJK7_XHkJqE3Yiao,39
82
+ cucu-1.0.7.dist-info/licenses/LICENSE,sha256=WfgJYF9EaQoL_OeWr2Qd0MxhhFegDfzWSUmvDTwFxis,1721
83
+ cucu-1.0.7.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.25.0
2
+ Generator: hatchling 1.27.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any