robotframework-browser-tray 1.6.0__tar.gz → 1.7.0__tar.gz

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.
@@ -1,9 +1,9 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.3
2
2
  Name: robotframework-browser-tray
3
- Version: 1.6.0
3
+ Version: 1.7.0
4
4
  Summary: Tray icon and REPL for trying out Browser Library keywords using Chromium or Edge
5
5
  Author-email: Marduk Bolaños <marduk.bolanos@imbus.de>
6
- Requires-Python: >=3.8.2
6
+ Requires-Python: >=3.9.0
7
7
  Description-Content-Type: text/markdown
8
8
  Requires-Dist: pystray>=0.19.5
9
9
  Requires-Dist: robotframework-browser>=18.0.0
@@ -51,7 +51,7 @@ python -m BrowserTray
51
51
  **Hint**: In case your environment does not allow executing ibrowser, call the Python module directly:
52
52
 
53
53
  ```bash
54
- python -m BrowserTray.Repl
54
+ python -m BrowserTray.ibrowser
55
55
  ```
56
56
 
57
57
  ### ibrowser
@@ -103,7 +103,7 @@ If Microsoft Edge is installed on your machine:
103
103
 
104
104
  ## How it works
105
105
 
106
- On start up `browser-tray` checks whether `rfbrowser init` has been executed.
106
+ On start up `ibrowser` checks whether `rfbrowser init` has been executed.
107
107
 
108
108
  If this requirement is met the Playwright wrapper is started with `node site-packages/Browser/wrapper/index.js 4711`.
109
109
 
@@ -39,7 +39,7 @@ python -m BrowserTray
39
39
  **Hint**: In case your environment does not allow executing ibrowser, call the Python module directly:
40
40
 
41
41
  ```bash
42
- python -m BrowserTray.Repl
42
+ python -m BrowserTray.ibrowser
43
43
  ```
44
44
 
45
45
  ### ibrowser
@@ -91,7 +91,7 @@ If Microsoft Edge is installed on your machine:
91
91
 
92
92
  ## How it works
93
93
 
94
- On start up `browser-tray` checks whether `rfbrowser init` has been executed.
94
+ On start up `ibrowser` checks whether `rfbrowser init` has been executed.
95
95
 
96
96
  If this requirement is met the Playwright wrapper is started with `node site-packages/Browser/wrapper/index.js 4711`.
97
97
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "robotframework-browser-tray"
3
- version = "1.6.0"
3
+ version = "1.7.0"
4
4
  description = "Tray icon and REPL for trying out Browser Library keywords using Chromium or Edge"
5
5
  authors = [
6
6
  {name = "Marduk Bolaños", email = "marduk.bolanos@imbus.de"},
@@ -12,7 +12,7 @@ dependencies = [
12
12
  "robotframework-browser>=18.0.0",
13
13
  "robotframework-debug>=4.5.0",
14
14
  ]
15
- requires-python = ">=3.8.2"
15
+ requires-python = ">=3.9.0"
16
16
  readme = "README.md"
17
17
  license = {text = "Apache 2.0"}
18
18
 
@@ -36,7 +36,7 @@ test = "tox"
36
36
 
37
37
  [project.scripts]
38
38
  browser-tray = "BrowserTray.tray:run"
39
- ibrowser = "BrowserTray.Repl.repl:run"
39
+ ibrowser = "BrowserTray.ibrowser:run"
40
40
 
41
41
  [build-system]
42
42
  requires = ["flit_core>=3.2,<4"]
@@ -0,0 +1,14 @@
1
+ from RobotDebug.RobotDebug import RobotDebug
2
+ from robot.libraries.BuiltIn import BuiltIn
3
+
4
+
5
+ class BrowserRepl(RobotDebug):
6
+ def __init__(self, playwright_process_port, remote_debugging_port, **kwargs):
7
+ super().__init__(**kwargs)
8
+
9
+ self.Library("Browser", "enable_presenter_mode=True", f"playwright_process_port={playwright_process_port}")
10
+ self.connect(remote_debugging_port)
11
+
12
+ def connect(self, remote_debugging_port):
13
+ BuiltIn().run_keyword("Connect To Browser", f"http://localhost:{remote_debugging_port}", "chromium", "use_cdp=True")
14
+ BuiltIn().run_keyword("Set Browser Timeout", "2s")
@@ -0,0 +1,22 @@
1
+ import argparse
2
+ from typing import Tuple
3
+
4
+
5
+ REMOTE_DEBUGGING_PORT = 1234
6
+ PLAYWRIGHT_PROCESS_PORT= 4711
7
+
8
+
9
+ def get_ports() -> Tuple[int, int]:
10
+ MAX_PORT = 2**16
11
+
12
+ arg_parser = argparse.ArgumentParser(add_help=True)
13
+ arg_parser.add_argument("--pw-port", default=PLAYWRIGHT_PROCESS_PORT, type=int, help=f"Playwright process port (default: {PLAYWRIGHT_PROCESS_PORT})")
14
+ arg_parser.add_argument("--cdp-port", default=REMOTE_DEBUGGING_PORT, type=int, help=f"Chromium debugging port (default: {REMOTE_DEBUGGING_PORT})")
15
+ args = arg_parser.parse_args()
16
+ playwright_process_port = args.pw_port
17
+ remote_debugging_port = args.cdp_port
18
+
19
+ if playwright_process_port > MAX_PORT or remote_debugging_port > MAX_PORT:
20
+ raise ValueError(f"Port numbers cannot be larger than {MAX_PORT}")
21
+
22
+ return (playwright_process_port, remote_debugging_port)
@@ -0,0 +1 @@
1
+ from .repl import run
@@ -1,17 +1,22 @@
1
1
  import http.client
2
2
  import re
3
3
  import socket
4
+ from subprocess import Popen
4
5
  import sys
5
6
  import tempfile
6
7
  import time
7
8
  from functools import wraps
8
9
  from pathlib import Path
10
+ from textwrap import dedent
9
11
 
10
12
  import RobotDebug.styles
11
13
  from Browser.base.librarycomponent import LibraryComponent
12
14
  from robot.run import run_cli
13
15
  from robot.api import logger
14
16
 
17
+ from BrowserTray import cmdline_args
18
+ from BrowserTray import playwright
19
+
15
20
 
16
21
  def escape_ansi(line):
17
22
  ansi_escape = re.compile(r'(?:\x1B[@-_]|[\x80-\x9F])[0-?]*[ -/]*[@-~]')
@@ -53,17 +58,22 @@ def wrap_presenter_mode(self, selector, strict):
53
58
  LibraryComponent.presenter_mode = wrap_presenter_mode
54
59
 
55
60
 
56
- TEST_SUITE = b"""
57
- *** Settings ***
58
- Library BrowserTray.Repl repl=${True}
61
+ def test_suite(playwright_process_port, remote_debugging_port):
62
+ return bytes(dedent(
63
+ f"""
64
+ *** Settings ***
65
+ Library BrowserTray.BrowserRepl {playwright_process_port} {remote_debugging_port} repl=${True}
59
66
 
60
- *** Test Cases ***
61
- Robot Framework Debug REPL
62
- Debug
63
- """
67
+ *** Test Cases ***
68
+ Robot Framework Debug REPL
69
+ Debug
70
+ """
71
+ ),
72
+ encoding='utf-8'
73
+ )
64
74
 
65
75
 
66
- def shell():
76
+ def irobot(testsuite: bytes, playwright_proc: Popen):
67
77
  """A standalone robotframework shell."""
68
78
 
69
79
  default_no_logs = [
@@ -83,15 +93,21 @@ def shell():
83
93
  with tempfile.NamedTemporaryFile(
84
94
  prefix="robot-debug-", suffix=".robot", delete=False
85
95
  ) as test_file:
86
- test_file.write(TEST_SUITE)
96
+ test_file.write(testsuite)
87
97
  test_file.flush()
88
98
 
89
99
  if len(sys.argv) > 1:
90
- args = sys.argv[1:] + [test_file.name]
100
+ sys.argv = [
101
+ arg
102
+ for arg in sys.argv
103
+ if not (arg.startswith('--pw-port') or arg.startswith('--cdp-port'))
104
+ ]
105
+ args = sys.argv[1:] + [*default_no_logs, test_file.name]
91
106
  else:
92
107
  args = [*default_no_logs, test_file.name]
93
108
 
94
109
  try:
110
+
95
111
  sys.exit(run_cli(args))
96
112
  finally:
97
113
  test_file.close()
@@ -101,18 +117,22 @@ def shell():
101
117
  file_path = Path(test_file.name)
102
118
  if file_path.exists():
103
119
  file_path.unlink()
120
+
121
+ playwright_proc.terminate()
122
+
104
123
 
124
+ def run():
125
+ playwright_process_port, remote_debugging_port = cmdline_args.get_ports()
105
126
 
106
- def run(timeout=0):
107
127
  try:
108
- http.client.HTTPConnection('127.0.0.1', 1234, timeout=1).connect()
109
- if timeout:
110
- time.sleep(timeout)
111
- sys.exit(0)
112
- shell()
128
+ http.client.HTTPConnection('127.0.0.1', remote_debugging_port, timeout=1).connect()
129
+
130
+ playwright_proc = playwright.run(playwright_process_port)
131
+ irobot(test_suite(playwright_process_port, remote_debugging_port), playwright_proc)
113
132
  except socket.timeout:
114
133
  print("ibrowser needs either:\n" +
115
134
  " - a running Chromium, started using the tray icon or\n" +
116
- " - a running Microsoft Edge started as explained in the documentation: https://pypi.org/project/robotframework-browser-tray/"
135
+ " - a running Microsoft Edge started as explained in the documentation: https://pypi.org/project/robotframework-browser-tray/\n" +
136
+ f"Default remote-debugging-port: {remote_debugging_port}"
117
137
  )
118
138
  sys.exit(1)
@@ -0,0 +1,44 @@
1
+ import http.client
2
+ import site
3
+ import socket
4
+ import subprocess
5
+ import sys
6
+ from pathlib import Path
7
+ from subprocess import Popen
8
+
9
+
10
+ _, site_packages = site.getsitepackages()
11
+ browser_wrapper = Path(site_packages) / "Browser" / "wrapper"
12
+ index_js = browser_wrapper / "index.js"
13
+ node_modules = browser_wrapper / "node_modules"
14
+ playwright_core = node_modules / "playwright-core"
15
+
16
+
17
+ def playwright_is_initialized():
18
+ return node_modules.is_dir() and playwright_core.is_dir()
19
+
20
+
21
+ def start_playwright(playwright_process_port: int) -> Popen:
22
+ return Popen(
23
+ ['node', index_js, str(playwright_process_port)],
24
+ stderr=subprocess.PIPE,
25
+ stdout=subprocess.PIPE
26
+ )
27
+
28
+
29
+ def run(playwright_process_port: int) -> Popen:
30
+ if not playwright_is_initialized():
31
+ print(
32
+ "Playwright has not been initialized.\n" +
33
+ "In order to use Chromium execute 'rfbrowser init chromium'.\n" +
34
+ "If you want to use the Microsoft Edge installed on your system execute 'rfbrowser init --skip-browsers'"
35
+ )
36
+ sys.exit(1)
37
+
38
+ try:
39
+ http.client.HTTPConnection('127.0.0.1', playwright_process_port, timeout=1).connect()
40
+ print(f"The port {playwright_process_port} is already in use. Either browser-tray is already running or another process is using the port.\n" +
41
+ "To start the Playwright wrapper on another port execute `browser-tray --pw-port PORT`")
42
+ sys.exit(1)
43
+ except socket.timeout:
44
+ return start_playwright(playwright_process_port)
@@ -0,0 +1,114 @@
1
+ import os
2
+ import site
3
+ import subprocess
4
+ import sys
5
+ import tkinter as tk
6
+ from os.path import realpath
7
+ from pathlib import Path
8
+ from subprocess import Popen
9
+ from tkinter import messagebox
10
+ from typing import List
11
+
12
+ from PIL import Image
13
+ from pystray import Icon, Menu, MenuItem
14
+
15
+ from BrowserTray import cmdline_args
16
+
17
+
18
+ _, site_packages = site.getsitepackages()
19
+ browser_wrapper = Path(site_packages).resolve() / "Browser" / "wrapper"
20
+ index_js = browser_wrapper / "index.js"
21
+ node_modules = browser_wrapper / "node_modules"
22
+ playwright_core = node_modules / "playwright-core"
23
+
24
+
25
+ def find_chromium(path: Path) -> List[Path]:
26
+ return [
27
+ Path(file.path)
28
+ for file in os.scandir(path)
29
+ if file.is_dir() and file.name.startswith("chromium")
30
+ ]
31
+
32
+
33
+ def get_chromium_dir(node_modules: Path):
34
+ local_browsers = playwright_core / ".local-browsers"
35
+
36
+ if not (node_modules.is_dir() and local_browsers.is_dir() and find_chromium(local_browsers)):
37
+ return None
38
+
39
+ return find_chromium(local_browsers)[0]
40
+
41
+
42
+ def start_chromium(remote_debugging_port: int, incognito: bool):
43
+ chromium_dir = get_chromium_dir(node_modules)
44
+
45
+ if not chromium_dir:
46
+ window = tk.Tk()
47
+ window.withdraw()
48
+ messagebox.showerror("Error", "Chromium is not installed. Execute 'rfbrowser init chromium'.", master=window)
49
+ else:
50
+ incognito_flag = ["-incognito"] if incognito else []
51
+ chrome_exe = chromium_dir / "chrome-win" / "chrome.exe"
52
+ Popen([chrome_exe, f"--remote-debugging-port={remote_debugging_port}", "--test-type"] + incognito_flag)
53
+
54
+
55
+ class TrayIcon:
56
+ def __init__(self, remote_debugging_port: int):
57
+ chromium_icon = Image.open(Path(realpath(__file__)).parent / "chromium.png")
58
+
59
+ self.remote_debugging_port = remote_debugging_port
60
+ self.icon = Icon(
61
+ name='Browser Tray',
62
+ icon=chromium_icon,
63
+ menu=Menu(
64
+ MenuItem(
65
+ 'Open Chromium',
66
+ self.open_chromium,
67
+ default=True
68
+ ),
69
+ MenuItem(
70
+ 'Open Chromium Incognito',
71
+ self.open_chromium_incognito,
72
+ ),
73
+ MenuItem(
74
+ 'Exit',
75
+ self.exit
76
+ )
77
+ )
78
+ )
79
+
80
+ def exit(self):
81
+ self.icon.stop()
82
+
83
+ def open_chromium(self):
84
+ start_chromium(self.remote_debugging_port, False)
85
+
86
+ def open_chromium_incognito(self):
87
+ start_chromium(self.remote_debugging_port, True)
88
+
89
+ def run(self):
90
+ cmd = "browser-tray.exe"
91
+ if is_running(cmd):
92
+ print(f"{cmd} is already running")
93
+ sys.exit(1)
94
+
95
+ self.icon.run()
96
+
97
+
98
+ def is_running(cmd: str) -> bool:
99
+ process_list = subprocess.check_output(
100
+ # Set the character page to 65001 = UTF-8
101
+ f'chcp 65001 | TASKLIST /FI "IMAGENAME eq {cmd}"', shell=True
102
+ ).decode('utf-8').splitlines()
103
+ instances = [
104
+ process
105
+ for process in process_list
106
+ if process.startswith(cmd)
107
+ ]
108
+ return len(instances) > 1
109
+
110
+
111
+ def run():
112
+ playwright_process_port, remote_debugging_port = cmdline_args.get_ports()
113
+ tray_icon = TrayIcon(remote_debugging_port)
114
+ tray_icon.run()
@@ -1,13 +0,0 @@
1
- from RobotDebug.RobotDebug import RobotDebug
2
- from robot.libraries.BuiltIn import BuiltIn
3
-
4
-
5
- class Repl(RobotDebug):
6
- def __init__(self, **kwargs):
7
- super().__init__(**kwargs)
8
-
9
- self.Library("Browser", "enable_presenter_mode=True", "playwright_process_port=4711", "timeout=2s")
10
- self.connect()
11
-
12
- def connect(self):
13
- BuiltIn().run_keyword("Connect To Browser", "http://localhost:1234", "chromium", "use_cdp=True")
@@ -1,176 +0,0 @@
1
- import argparse
2
- import http.client
3
- import os
4
- import site
5
- import socket
6
- import subprocess
7
- import sys
8
- import time
9
- import tkinter as tk
10
- from os.path import realpath
11
- from pathlib import Path
12
- from subprocess import Popen
13
- from tkinter import messagebox
14
- from typing import List, Tuple
15
-
16
- from PIL import Image
17
- from pystray import Icon, Menu, MenuItem
18
-
19
-
20
- REMOTE_DEBUGGING_PORT = 1234
21
- PLAYWRIGHT_PROCESS_PORT= 4711
22
-
23
-
24
- _, site_packages = site.getsitepackages()
25
- browser_wrapper = Path(site_packages) / "Browser" / "wrapper"
26
- index_js = browser_wrapper / "index.js"
27
- node_modules = browser_wrapper / "node_modules"
28
- playwright_core = node_modules / "playwright-core"
29
-
30
-
31
- def find_chromium(path: Path) -> List[Path]:
32
- return [
33
- Path(file.path)
34
- for file in os.scandir(path)
35
- if file.is_dir() and file.name.startswith("chromium")
36
- ]
37
-
38
-
39
- def playwright_is_initialized():
40
- return node_modules.is_dir() and playwright_core.is_dir()
41
-
42
-
43
- def get_chromium_dir(node_modules: Path):
44
- local_browsers = playwright_core / ".local-browsers"
45
-
46
- if not (node_modules.is_dir() and local_browsers.is_dir() and find_chromium(local_browsers)):
47
- return None
48
-
49
- return find_chromium(local_browsers)[0]
50
-
51
-
52
- def start_playwright(playwright_process_port: int) -> Popen:
53
- return Popen(['node', index_js, str(playwright_process_port)])
54
-
55
-
56
- class TrayIcon:
57
- def __init__(self, playwright_process_port: int, remote_debugging_port: int, timeout=0):
58
- chromium_icon = Image.open(Path(realpath(__file__)).parent / "chromium.png")
59
-
60
- playwright_process = start_playwright(playwright_process_port)
61
- time.sleep(2)
62
- return_code = playwright_process.poll()
63
-
64
- if return_code:
65
- sys.exit(return_code)
66
-
67
- if timeout:
68
- time.sleep(timeout)
69
- playwright_process.kill()
70
- sys.exit(0)
71
-
72
- self.processes = [playwright_process]
73
- self.remote_debugging_port = remote_debugging_port
74
- self.icon = Icon(
75
- name='Browser Tray',
76
- icon=chromium_icon,
77
- menu=Menu(
78
- MenuItem(
79
- 'Open Chromium',
80
- self.open_chromium,
81
- default=True
82
- ),
83
- MenuItem(
84
- 'Open Chromium Incognito',
85
- self.open_chromium_incognito,
86
- ),
87
- MenuItem(
88
- 'Exit',
89
- self.exit
90
- )
91
- )
92
- )
93
-
94
- def exit(self):
95
- for proc in self.processes:
96
- proc.terminate()
97
-
98
- self.icon.stop()
99
-
100
- def open_chromium(self):
101
- self.start_chromium(self.remote_debugging_port, False)
102
-
103
- def open_chromium_incognito(self):
104
- self.start_chromium(self.remote_debugging_port, True)
105
-
106
- def run(self):
107
- self.icon.run()
108
-
109
- def start_chromium(self, remote_debugging_port: int, incognito: bool):
110
- chromium_dir = get_chromium_dir(node_modules)
111
-
112
- if not chromium_dir:
113
- window = tk.Tk()
114
- window.withdraw()
115
- messagebox.showerror("Error", "Chromium is not installed. Execute 'rfbrowser init chromium'.", master=window)
116
- else:
117
- incognito_flag = ["-incognito"] if incognito else []
118
- chrome_exe = chromium_dir / "chrome-win" / "chrome.exe"
119
- chromium = Popen([chrome_exe, f"--remote-debugging-port={remote_debugging_port}", "--test-type"] + incognito_flag)
120
- time.sleep(2)
121
- self.processes.append(chromium)
122
-
123
-
124
- def is_running(cmd: str) -> bool:
125
- process_list = subprocess.check_output(
126
- # Set the character page to 65001 = UTF-8
127
- f'chcp 65001 | TASKLIST /FI "IMAGENAME eq {cmd}"', shell=True
128
- ).decode('utf-8').splitlines()
129
- instances = [
130
- process
131
- for process in process_list
132
- if process.startswith(cmd) and os.getlogin().lower() in process.lower()
133
- ]
134
- return len(instances) > 1
135
-
136
-
137
- def get_ports() -> Tuple[int, int]:
138
- MAX_PORT = 2**16
139
-
140
- arg_parser = argparse.ArgumentParser(add_help=True)
141
- arg_parser.add_argument("--pw-port", default=PLAYWRIGHT_PROCESS_PORT, type=int, help=f"Playwright process port (default: {PLAYWRIGHT_PROCESS_PORT})")
142
- arg_parser.add_argument("--cdp-port", default=REMOTE_DEBUGGING_PORT, type=int, help=f"Chromium debugging port (default: {REMOTE_DEBUGGING_PORT})")
143
- args = arg_parser.parse_args()
144
- playwright_process_port = args.pw_port
145
- remote_debugging_port = args.cdp_port
146
-
147
- if playwright_process_port > MAX_PORT or remote_debugging_port > MAX_PORT:
148
- raise ValueError(f"Port numbers cannot be larger than {MAX_PORT}")
149
-
150
- return (playwright_process_port, remote_debugging_port)
151
-
152
-
153
- def run():
154
- cmd = "browser-tray.exe"
155
- if is_running(cmd):
156
- print(f"{cmd} is already running")
157
- sys.exit(1)
158
-
159
- playwright_process_port, remote_debugging_port = get_ports()
160
-
161
- if not playwright_is_initialized():
162
- print(
163
- "Playwright has not been initialized.\n" +
164
- "In order to use Chromium execute 'rfbrowser init chromium'.\n" +
165
- "If you want to use the Microsoft Edge installed on your system execute 'rfbrowser init --skip-browsers'"
166
- )
167
- sys.exit(1)
168
-
169
- try:
170
- http.client.HTTPConnection('127.0.0.1', playwright_process_port, timeout=1).connect()
171
- print("The port 4711 is already in use. Either browser-tray is already running or another process is using the port.\n" +
172
- "To start the Playwright wrapper on another port execute `browser-tray --pw-port PORT`")
173
- sys.exit(1)
174
- except socket.timeout:
175
- tray_icon = TrayIcon(playwright_process_port, remote_debugging_port)
176
- tray_icon.run()