Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use sys.executable to run robot #584

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,9 @@ Supports all [Robot Framework command line options](https://robotframework.org/r
--chunk
Optionally chunk tests to PROCESSES number of robot runs. This can save time because all the suites will share the same setups and teardowns.

--sysexecutable
Changes how pabot calls robot/rebot from their executable wrappers into `python -m` calls using the currently used python interpreter.

Example usages:

pabot test_directory
Expand Down
9 changes: 9 additions & 0 deletions src/pabot/arguments.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import multiprocessing
import re
import sys
from typing import Dict, List, Optional, Tuple

from robot import __version__ as ROBOT_VERSION
Expand Down Expand Up @@ -90,7 +91,9 @@ def _parse_pabot_args(args): # type: (List[str]) -> Tuple[List[str], Dict[str,
"shardindex": 0,
"shardcount": 1,
"chunk": False,
"sysexecutable": False,
}

argumentfiles = []
while args and (
args[0]
Expand All @@ -114,6 +117,7 @@ def _parse_pabot_args(args): # type: (List[str]) -> Tuple[List[str], Dict[str,
"help",
"shard",
"chunk",
"sysexecutable",
]
]
or ARGSMATCHER.match(args[0])
Expand Down Expand Up @@ -183,6 +187,11 @@ def _parse_pabot_args(args): # type: (List[str]) -> Tuple[List[str], Dict[str,
pabot_args["shardindex"], pabot_args["shardcount"] = _parse_shard(args[1])
args = args[2:]
continue
if args[0] == "--sysexecutable":
pabot_args["command"] = [sys.executable, "-m", "robot"]
pabot_args["sysexecutable"] = True
args = args[1:]
continue
match = ARGSMATCHER.match(args[0])
if match:
argumentfiles += [(match.group(1), args[1])]
Expand Down
21 changes: 13 additions & 8 deletions src/pabot/pabot.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@
"""

from __future__ import absolute_import, print_function

import datetime
import hashlib
import os
Expand Down Expand Up @@ -239,15 +238,15 @@ def execute_and_wait_with(item):
process_timeout=item.timeout
)
outputxml_preprocessing(
item.options, outs_dir, name, item.verbose, _make_id(), caller_id
item.options, outs_dir, name, item.verbose, _make_id(), caller_id, item.sysexecutable
)
except:
_write(traceback.format_exc())


def _create_command_for_execution(caller_id, datasources, is_last, item, outs_dir):
options = item.options.copy()
if item.command == ["robot"] and not options["listener"]:
if item.command in [["robot"], [sys.executable, "-m", "robot"]] and not options["listener"]:
options["listener"] = ["RobotStackTracer"]
cmd = (
item.command
Expand Down Expand Up @@ -377,7 +376,7 @@ def _is_ignored(plib, caller_id): # type: (Remote, str) -> bool

# optionally invoke rebot for output.xml preprocessing to get --RemoveKeywords
# and --flattenkeywords applied => result: much smaller output.xml files + faster merging + avoid MemoryErrors
def outputxml_preprocessing(options, outs_dir, item_name, verbose, pool_id, caller_id):
def outputxml_preprocessing(options, outs_dir, item_name, verbose, pool_id, caller_id, sysexecutable):
# type: (Dict[str, Any], str, str, bool, int, str) -> None
try:
remove_keywords = options["removekeywords"]
Expand All @@ -393,9 +392,12 @@ def outputxml_preprocessing(options, outs_dir, item_name, verbose, pool_id, call
flatten_keywords_args += ["--flattenkeywords", k]
outputxmlfile = os.path.join(outs_dir, "output.xml")
oldsize = os.path.getsize(outputxmlfile)
rebot_invoke = ["rebot"]
if sysexecutable:
rebot_invoke = [sys.executable, "-m", "robot.rebot"]
cmd = (
[
"rebot",
rebot_invoke
+ [
"--log",
"NONE",
"--report",
Expand Down Expand Up @@ -1653,7 +1655,8 @@ def __init__(
argfile,
hive=None,
processes=0,
timeout=None
timeout=None,
sysexecutable=False
):
# type: (List[str], str, Dict[str, object], ExecutionItem, List[str], bool, Tuple[str, Optional[str]], Optional[str], int, Optional[int]) -> None
self.datasources = datasources
Expand All @@ -1674,6 +1677,7 @@ def __init__(
self.hive = hive
self.processes = processes
self.timeout = timeout
self.sysexecutable = sysexecutable

@property
def index(self):
Expand Down Expand Up @@ -1751,7 +1755,8 @@ def _create_items(datasources, opts_for_run, outs_dir, pabot_args, suite_group):
argfile,
pabot_args.get("hive"),
pabot_args["processes"],
pabot_args["processtimeout"]
pabot_args["processtimeout"],
pabot_args["sysexecutable"]
)
for suite in suite_group
for argfile in pabot_args["argumentfiles"] or [("", None)]
Expand Down
24 changes: 24 additions & 0 deletions tests/test_pabot.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import tempfile
import shutil
import random
import sys

import pabot.execution_items as execution_items
from pabot import pabot, arguments
Expand Down Expand Up @@ -117,6 +118,29 @@ def test_parse_args(self):
self.assertTrue(pabot_args["testlevelsplit"])
self.assertEqual(datasources, ["suite"])


def test_sys_executable(self):
(
options,
datasources,
pabot_args,
options_for_subprocesses,
) = arguments.parse_args(
[
"--verbose",
"--sysexecutable",
"--removekeywords",
"WUKS",
"suite"
]
)
self.assertEqual(pabot_args["command"], [sys.executable, "-m", "robot"])
# NOTE: calling rebot is quite deep on the call chain and command is
# constructed just before the call so that is not covered. But verified
# it via verbose logging when running manually.
self.assertEqual(pabot_args["verbose"], True)
self.assertEqual(datasources, ["suite"])

def test_start_and_stop_remote_library(self):
lib_process = pabot._start_remote_library(self._pabot_args)
self.assertTrue(lib_process.poll() is None)
Expand Down