Modernize python and update pylint (#5096)
Update code to conform to the newer version of pylint available in
ubuntu-22.04, with few exceptions:
- disabled `import-outside-toplevel` for `main()` in
`jerry_client.py`
- disabled `consider-using-with` for the logfile of `TestSuite` in
`test262-harness.py` as using `with` is not practical in that case
Update test262-harness.py to use argparse instead of the now deprecated
optparse
Rename variables in jerry_client_main.py that redefined python builtins
or shadowed variables from an outer scope
Update python files to use f-stirngs
Add minimum python versions (3.6 and 3.8) to the CI jobs: without it the
default python version did not support the `with` statement for
`subprocess.Popen` used in `build.py` on macos, or in some cases f-stirngs
Remove `from __future__` imports that are no-ops in python 3
Remove shebang from non executable files
Re-enable most pylint checkers, except `missing-docstring`
JerryScript-DCO-1.0-Signed-off-by: Máté Tokodi mate.tokodi@szteszoftver.hu
This commit is contained in:
@@ -40,10 +40,8 @@
|
||||
# This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import logging
|
||||
import optparse
|
||||
import argparse
|
||||
import os
|
||||
from os import path
|
||||
import platform
|
||||
@@ -55,7 +53,6 @@ import xml.dom.minidom
|
||||
from collections import Counter
|
||||
|
||||
import signal
|
||||
import threading
|
||||
import multiprocessing
|
||||
|
||||
#######################################################################
|
||||
@@ -112,7 +109,7 @@ def my_read_dict(lines, indent=""):
|
||||
|
||||
|
||||
def my_read_value(lines, value, indent):
|
||||
if value == ">" or value == "|":
|
||||
if value in (">", "|"):
|
||||
(lines, value) = my_multiline(lines, value == "|")
|
||||
value = value + "\n"
|
||||
return (lines, value)
|
||||
@@ -157,7 +154,7 @@ def my_remove_list_header(indent, line):
|
||||
def my_read_one_line(value):
|
||||
if M_YAML_LIST_PATTERN.match(value):
|
||||
return my_flow_list(value)
|
||||
elif re.match(r"^[-0-9]*$", value):
|
||||
if re.match(r"^[-0-9]*$", value):
|
||||
try:
|
||||
value = int(value)
|
||||
except ValueError:
|
||||
@@ -196,7 +193,7 @@ def my_multiline(lines, preserve_newlines=False):
|
||||
break
|
||||
else:
|
||||
if preserve_newlines:
|
||||
if was_empty != None:
|
||||
if was_empty is not None:
|
||||
value += "\n"
|
||||
else:
|
||||
if was_empty:
|
||||
@@ -248,7 +245,7 @@ _LICENSE_PATTERN = re.compile(
|
||||
def yaml_attr_parser(test_record, attrs, name, onerror=print):
|
||||
parsed = yaml_load(attrs)
|
||||
if parsed is None:
|
||||
onerror("Failed to parse yaml in name %s" % name)
|
||||
onerror(f"Failed to parse yaml in name {name}")
|
||||
return
|
||||
|
||||
for key in parsed:
|
||||
@@ -287,7 +284,7 @@ def parse_test_record(src, name, onerror=print):
|
||||
|
||||
# YAML frontmatter is required for all tests.
|
||||
if frontmatter is None:
|
||||
onerror("Missing frontmatter: %s" % name)
|
||||
onerror(f"Missing frontmatter: {name}")
|
||||
|
||||
# The license shuold be placed before the frontmatter and there shouldn't be
|
||||
# any extra content between the license and the frontmatter.
|
||||
@@ -295,13 +292,13 @@ def parse_test_record(src, name, onerror=print):
|
||||
header_idx = src.index(header)
|
||||
frontmatter_idx = src.index(frontmatter)
|
||||
if header_idx > frontmatter_idx:
|
||||
onerror("Unexpected license after frontmatter: %s" % name)
|
||||
onerror(f"Unexpected license after frontmatter: {name}")
|
||||
|
||||
# Search for any extra test content, but ignore whitespace only or comment lines.
|
||||
extra = src[header_idx + len(header): frontmatter_idx]
|
||||
if extra and any(line.strip() and not line.lstrip().startswith("//") for line in extra.split("\n")):
|
||||
onerror(
|
||||
"Unexpected test content between license and frontmatter: %s" % name)
|
||||
f"Unexpected test content between license and frontmatter: {name}")
|
||||
|
||||
# Remove the license and YAML parts from the actual test content.
|
||||
test = src
|
||||
@@ -319,7 +316,7 @@ def parse_test_record(src, name, onerror=print):
|
||||
|
||||
# Report if the license block is missing in non-generated tests.
|
||||
if header is None and "generated" not in test_record and "hashbang" not in name:
|
||||
onerror("No license found in: %s" % name)
|
||||
onerror(f"No license found in: {name}")
|
||||
|
||||
return test_record
|
||||
|
||||
@@ -339,36 +336,37 @@ def report_error(error_string):
|
||||
|
||||
|
||||
def build_options():
|
||||
result = optparse.OptionParser()
|
||||
result.add_option("--command", default=None,
|
||||
help="The command-line to run")
|
||||
result.add_option("--tests", default=path.abspath('.'),
|
||||
help="Path to the tests")
|
||||
result.add_option("--exclude-list", default=None,
|
||||
help="Path to the excludelist.xml file")
|
||||
result.add_option("--cat", default=False, action="store_true",
|
||||
help="Print packaged test code that would be run")
|
||||
result.add_option("--summary", default=False, action="store_true",
|
||||
help="Print summary after running tests")
|
||||
result.add_option("--full-summary", default=False, action="store_true",
|
||||
help="Print summary and test output after running tests")
|
||||
result.add_option("--strict_only", default=False, action="store_true",
|
||||
help="Test only strict mode")
|
||||
result.add_option("--non_strict_only", default=False, action="store_true",
|
||||
help="Test only non-strict mode")
|
||||
result.add_option("--unmarked_default", default="both",
|
||||
help="default mode for tests of unspecified strictness")
|
||||
result.add_option("-j", "--job-count", default=None, action="store", type=int,
|
||||
help="Number of parallel test jobs to run. In case of '0' cpu count is used.")
|
||||
result.add_option("--logname", help="Filename to save stdout to")
|
||||
result.add_option("--loglevel", default="warning",
|
||||
help="sets log level to debug, info, warning, error, or critical")
|
||||
result.add_option("--print-handle", default="print",
|
||||
help="Command to print from console")
|
||||
result.add_option("--list-includes", default=False, action="store_true",
|
||||
help="List includes required by tests")
|
||||
result.add_option("--module-flag", default="-m",
|
||||
help="List includes required by tests")
|
||||
result = argparse.ArgumentParser()
|
||||
result.add_argument("--command", default=None,
|
||||
help="The command-line to run")
|
||||
result.add_argument("--tests", default=path.abspath('.'),
|
||||
help="Path to the tests")
|
||||
result.add_argument("--exclude-list", default=None,
|
||||
help="Path to the excludelist.xml file")
|
||||
result.add_argument("--cat", default=False, action="store_true",
|
||||
help="Print packaged test code that would be run")
|
||||
result.add_argument("--summary", default=False, action="store_true",
|
||||
help="Print summary after running tests")
|
||||
result.add_argument("--full-summary", default=False, action="store_true",
|
||||
help="Print summary and test output after running tests")
|
||||
result.add_argument("--strict_only", default=False, action="store_true",
|
||||
help="Test only strict mode")
|
||||
result.add_argument("--non_strict_only", default=False, action="store_true",
|
||||
help="Test only non-strict mode")
|
||||
result.add_argument("--unmarked_default", default="both",
|
||||
help="default mode for tests of unspecified strictness")
|
||||
result.add_argument("-j", "--job-count", default=None, action="store", type=int,
|
||||
help="Number of parallel test jobs to run. In case of '0' cpu count is used.")
|
||||
result.add_argument("--logname", help="Filename to save stdout to")
|
||||
result.add_argument("--loglevel", default="warning",
|
||||
help="sets log level to debug, info, warning, error, or critical")
|
||||
result.add_argument("--print-handle", default="print",
|
||||
help="Command to print from console")
|
||||
result.add_argument("--list-includes", default=False, action="store_true",
|
||||
help="List includes required by tests")
|
||||
result.add_argument("--module-flag", default="-m",
|
||||
help="List includes required by tests")
|
||||
result.add_argument("test_list", nargs='*', default=None)
|
||||
return result
|
||||
|
||||
|
||||
@@ -376,15 +374,15 @@ def validate_options(options):
|
||||
if not options.command:
|
||||
report_error("A --command must be specified.")
|
||||
if not path.exists(options.tests):
|
||||
report_error("Couldn't find test path '%s'" % options.tests)
|
||||
report_error(f"Couldn't find test path '{options.tests}'")
|
||||
|
||||
|
||||
def is_windows():
|
||||
actual_platform = platform.system()
|
||||
return (actual_platform == 'Windows') or (actual_platform == 'Microsoft')
|
||||
return actual_platform in ('Windows', 'Microsoft')
|
||||
|
||||
|
||||
class TempFile(object):
|
||||
class TempFile:
|
||||
|
||||
def __init__(self, suffix="", prefix="tmp", text=False):
|
||||
self.suffix = suffix
|
||||
@@ -405,7 +403,7 @@ class TempFile(object):
|
||||
os.write(self.file_desc, string.encode('utf8'))
|
||||
|
||||
def read(self):
|
||||
with open(self.name, "r", newline='') as file_desc:
|
||||
with open(self.name, "r", newline='', encoding='utf8') as file_desc:
|
||||
return file_desc.read()
|
||||
|
||||
def close(self):
|
||||
@@ -417,11 +415,11 @@ class TempFile(object):
|
||||
try:
|
||||
self.close()
|
||||
os.unlink(self.name)
|
||||
except OSError as exception:
|
||||
logging.error("Error disposing temp file: %s", str(exception))
|
||||
except OSError as os_error:
|
||||
logging.error("Error disposing temp file: %s", os_error)
|
||||
|
||||
|
||||
class TestResult(object):
|
||||
class TestResult:
|
||||
|
||||
def __init__(self, exit_code, stdout, stderr, case):
|
||||
self.exit_code = exit_code
|
||||
@@ -433,37 +431,36 @@ class TestResult(object):
|
||||
name = self.case.get_name()
|
||||
mode = self.case.get_mode()
|
||||
|
||||
if self.exit_code != 0 and self.exit_code != 1:
|
||||
sys.stderr.write(u"===%s failed in %s with negative:%s===\n"
|
||||
% (name, mode, self.case.get_negative_type()))
|
||||
if self.exit_code not in (0, 1):
|
||||
sys.stderr.write(f"==={name} failed in {mode} with negative:{self.case.get_negative_type()}===\n")
|
||||
self.write_output(sys.stderr)
|
||||
|
||||
if self.has_unexpected_outcome():
|
||||
if self.case.is_negative():
|
||||
print("=== %s passed in %s, but was expected to fail ===" % (name, mode))
|
||||
print("--- expected error: %s ---\n" % self.case.get_negative_type())
|
||||
print(f"=== {name} passed in {mode}, but was expected to fail ===")
|
||||
print(f"--- expected error: {self.case.get_negative_type()} ---\n")
|
||||
else:
|
||||
if long_format:
|
||||
print("=== %s failed in %s ===" % (name, mode))
|
||||
print(f"=== {name} failed in {mode} ===")
|
||||
else:
|
||||
print("%s in %s: " % (name, mode))
|
||||
print(f"{name} in {mode}: ")
|
||||
self.write_output(sys.stdout)
|
||||
if long_format:
|
||||
print("===")
|
||||
elif self.case.is_negative():
|
||||
print("%s failed in %s as expected" % (name, mode))
|
||||
print(f"{name} failed in {mode} as expected")
|
||||
else:
|
||||
print("%s passed in %s" % (name, mode))
|
||||
print(f"{name} passed in {mode}")
|
||||
|
||||
def write_output(self, target):
|
||||
out = self.stdout.strip()
|
||||
if out:
|
||||
target.write("--- output --- \n %s" % out)
|
||||
target.write(f"--- output --- \n {out}")
|
||||
error = self.stderr.strip()
|
||||
if error:
|
||||
target.write("--- errors --- \n %s" % error)
|
||||
target.write(f"--- errors --- \n {error}")
|
||||
|
||||
target.write("\n--- exit code: %d ---\n" % self.exit_code)
|
||||
target.write(f"\n--- exit code: {self.exit_code} ---\n")
|
||||
|
||||
def has_failed(self):
|
||||
return self.exit_code != 0
|
||||
@@ -486,14 +483,14 @@ class TestResult(object):
|
||||
return self.stdout
|
||||
|
||||
|
||||
class TestCase(object):
|
||||
class TestCase:
|
||||
|
||||
def __init__(self, suite, name, full_path, strict_mode, command_template, module_flag):
|
||||
self.suite = suite
|
||||
self.name = name
|
||||
self.full_path = full_path
|
||||
self.strict_mode = strict_mode
|
||||
with open(self.full_path, "r", newline='') as file_desc:
|
||||
with open(self.full_path, "r", newline='', encoding='utf8') as file_desc:
|
||||
self.contents = file_desc.read()
|
||||
test_record = parse_test_record(self.contents, name)
|
||||
self.test = test_record["test"]
|
||||
@@ -602,25 +599,25 @@ class TestCase(object):
|
||||
@staticmethod
|
||||
def execute(command):
|
||||
if is_windows():
|
||||
args = '%s' % command
|
||||
args = f'{command}'
|
||||
else:
|
||||
args = command.split(" ")
|
||||
stdout = TempFile(prefix="test262-out-")
|
||||
stderr = TempFile(prefix="test262-err-")
|
||||
try:
|
||||
logging.info("exec: %s", str(args))
|
||||
process = subprocess.Popen(
|
||||
with subprocess.Popen(
|
||||
args,
|
||||
shell=False,
|
||||
stdout=stdout.file_desc,
|
||||
stderr=stderr.file_desc
|
||||
)
|
||||
timer = threading.Timer(TEST262_CASE_TIMEOUT, process.kill)
|
||||
timer.start()
|
||||
code = process.wait()
|
||||
timer.cancel()
|
||||
out = stdout.read()
|
||||
err = stderr.read()
|
||||
) as process:
|
||||
try:
|
||||
code = process.wait(timeout=TEST262_CASE_TIMEOUT)
|
||||
except subprocess.TimeoutExpired:
|
||||
process.kill()
|
||||
out = stdout.read()
|
||||
err = stderr.read()
|
||||
finally:
|
||||
stdout.dispose()
|
||||
stderr.dispose()
|
||||
@@ -666,10 +663,10 @@ class TestCase(object):
|
||||
if 'raw' in flags:
|
||||
if 'noStrict' in flags:
|
||||
raise TypeError("The `raw` flag implies the `noStrict` flag")
|
||||
elif 'onlyStrict' in flags:
|
||||
if 'onlyStrict' in flags:
|
||||
raise TypeError(
|
||||
"The `raw` flag is incompatible with the `onlyStrict` flag")
|
||||
elif self.get_include_list():
|
||||
if self.get_include_list():
|
||||
raise TypeError(
|
||||
"The `raw` flag is incompatible with the `includes` tag")
|
||||
|
||||
@@ -683,7 +680,7 @@ def test_case_run_process(case):
|
||||
return case.run()
|
||||
|
||||
|
||||
class ProgressIndicator(object):
|
||||
class ProgressIndicator:
|
||||
|
||||
def __init__(self, count):
|
||||
self.count = count
|
||||
@@ -700,18 +697,11 @@ class ProgressIndicator(object):
|
||||
self.succeeded += 1
|
||||
|
||||
|
||||
def make_plural(num):
|
||||
if num == 1:
|
||||
return (num, "")
|
||||
return (num, "s")
|
||||
|
||||
|
||||
def percent_format(partial, total):
|
||||
return "%i test%s (%.1f%%)" % (make_plural(partial) +
|
||||
((100.0 * partial)/total,))
|
||||
return f"{partial} test{'s' if partial > 1 else ''} ({(100.0 * partial)/total:.1f}%)"
|
||||
|
||||
|
||||
class TestSuite(object):
|
||||
class TestSuite:
|
||||
|
||||
def __init__(self, options):
|
||||
self.test_root = path.join(options.tests, 'test')
|
||||
@@ -760,7 +750,7 @@ class TestSuite(object):
|
||||
if not name in self.include_cache:
|
||||
static = path.join(self.lib_root, name)
|
||||
if path.exists(static):
|
||||
with open(static) as file_desc:
|
||||
with open(static, encoding='utf8') as file_desc:
|
||||
contents = file_desc.read()
|
||||
contents = re.sub(r'\r\n', '\n', contents)
|
||||
self.include_cache[name] = contents + "\n"
|
||||
@@ -815,7 +805,7 @@ class TestSuite(object):
|
||||
count = progress.count
|
||||
succeeded = progress.succeeded
|
||||
failed = progress.failed
|
||||
write(" - Ran %i test%s" % make_plural(count))
|
||||
write(f" - Ran {count} test{'s' if count > 1 else ''}")
|
||||
if progress.failed == 0:
|
||||
write(" - All tests succeeded")
|
||||
else:
|
||||
@@ -827,12 +817,12 @@ class TestSuite(object):
|
||||
print("")
|
||||
write("Failed Tests")
|
||||
for result in positive:
|
||||
write(" %s in %s" % (result.case.get_name(), result.case.get_mode()))
|
||||
write(f" {result.case.get_name()} in {result.case.get_mode()}")
|
||||
if negative:
|
||||
print("")
|
||||
write("Expected to fail but passed ---")
|
||||
for result in negative:
|
||||
write(" %s in %s" % (result.case.get_name(), result.case.get_mode()))
|
||||
write(f" {result.case.get_name()} in {result.case.get_mode()}")
|
||||
|
||||
def print_failure_output(self, progress, logfile):
|
||||
for result in progress.failed_tests:
|
||||
@@ -849,7 +839,7 @@ class TestSuite(object):
|
||||
report_error("No tests to run")
|
||||
progress = ProgressIndicator(len(cases))
|
||||
if logname:
|
||||
self.logf = open(logname, "w")
|
||||
self.logf = open(logname, "w", encoding='utf8') # pylint: disable=consider-using-with
|
||||
|
||||
if job_count == 1:
|
||||
for case in cases:
|
||||
@@ -861,15 +851,11 @@ class TestSuite(object):
|
||||
if job_count == 0:
|
||||
job_count = None # uses multiprocessing.cpu_count()
|
||||
|
||||
pool = multiprocessing.Pool(processes=job_count, initializer=pool_init)
|
||||
try:
|
||||
with multiprocessing.Pool(processes=job_count, initializer=pool_init) as pool:
|
||||
for result in pool.imap(test_case_run_process, cases):
|
||||
if logname:
|
||||
self.write_log(result)
|
||||
progress.has_run(result)
|
||||
except KeyboardInterrupt:
|
||||
pool.terminate()
|
||||
pool.join()
|
||||
|
||||
if print_summary:
|
||||
self.print_summary(progress, logname)
|
||||
@@ -887,17 +873,17 @@ class TestSuite(object):
|
||||
if result.has_unexpected_outcome():
|
||||
if result.case.is_negative():
|
||||
self.logf.write(
|
||||
"=== %s passed in %s, but was expected to fail === \n" % (name, mode))
|
||||
self.logf.write("--- expected error: %s ---\n" % result.case.GetNegativeType())
|
||||
f"=== {name} passed in {mode}, but was expected to fail === \n")
|
||||
self.logf.write(f"--- expected error: {result.case.GetNegativeType()} ---\n")
|
||||
result.write_output(self.logf)
|
||||
else:
|
||||
self.logf.write("=== %s failed in %s === \n" % (name, mode))
|
||||
self.logf.write(f"=== {name} failed in {mode} === \n")
|
||||
result.write_output(self.logf)
|
||||
self.logf.write("===\n")
|
||||
elif result.case.is_negative():
|
||||
self.logf.write("%s failed in %s as expected \n" % (name, mode))
|
||||
self.logf.write(f"{name} failed in {mode} as expected \n")
|
||||
else:
|
||||
self.logf.write("%s passed in %s \n" % (name, mode))
|
||||
self.logf.write(f"{name} passed in {mode} \n")
|
||||
|
||||
def print_source(self, tests):
|
||||
cases = self.enumerate_tests(tests, "")
|
||||
@@ -917,7 +903,8 @@ class TestSuite(object):
|
||||
def main():
|
||||
code = 0
|
||||
parser = build_options()
|
||||
(options, args) = parser.parse_args()
|
||||
options = parser.parse_args()
|
||||
args = options.test_list
|
||||
validate_options(options)
|
||||
|
||||
test_suite = TestSuite(options)
|
||||
@@ -951,5 +938,5 @@ if __name__ == '__main__':
|
||||
try:
|
||||
sys.exit(main())
|
||||
except Test262Error as exception:
|
||||
print("Error: %s" % exception.message)
|
||||
print(f"Error: {exception.message}")
|
||||
sys.exit(1)
|
||||
|
||||
Reference in New Issue
Block a user