summaryrefslogtreecommitdiffstatshomepage
path: root/tests/run-tests.py
diff options
context:
space:
mode:
authorDamien George <damien@micropython.org>2021-03-11 16:11:27 +1100
committerDamien George <damien@micropython.org>2021-03-12 19:56:09 +1100
commit2a38d7103672580882fb621a5b76e8d26805d593 (patch)
tree62a85439ab882d56186136347e1e606c0e2f1293 /tests/run-tests.py
parent6129b8e401c36cc68e0f7ba8180da27a40d17621 (diff)
downloadmicropython-2a38d7103672580882fb621a5b76e8d26805d593.tar.gz
micropython-2a38d7103672580882fb621a5b76e8d26805d593.zip
tests/run-tests.py: Reformat with Black.
Signed-off-by: Damien George <damien@micropython.org>
Diffstat (limited to 'tests/run-tests.py')
-rwxr-xr-xtests/run-tests.py582
1 files changed, 352 insertions, 230 deletions
diff --git a/tests/run-tests.py b/tests/run-tests.py
index 5863b23b41..3ab6194b62 100755
--- a/tests/run-tests.py
+++ b/tests/run-tests.py
@@ -13,31 +13,34 @@ from glob import glob
# are guaranteed to always work, this one should though.
BASEPATH = os.path.dirname(os.path.abspath(inspect.getsourcefile(lambda: None)))
+
def base_path(*p):
- return os.path.abspath(os.path.join(BASEPATH, *p)).replace('\\', '/')
+ return os.path.abspath(os.path.join(BASEPATH, *p)).replace("\\", "/")
+
# Tests require at least CPython 3.3. If your default python3 executable
# is of lower version, you can point MICROPY_CPYTHON3 environment var
# to the correct executable.
-if os.name == 'nt':
- CPYTHON3 = os.getenv('MICROPY_CPYTHON3', 'python')
- MICROPYTHON = os.getenv('MICROPY_MICROPYTHON', base_path('../ports/windows/micropython.exe'))
+if os.name == "nt":
+ CPYTHON3 = os.getenv("MICROPY_CPYTHON3", "python")
+ MICROPYTHON = os.getenv("MICROPY_MICROPYTHON", base_path("../ports/windows/micropython.exe"))
else:
- CPYTHON3 = os.getenv('MICROPY_CPYTHON3', 'python3')
- MICROPYTHON = os.getenv('MICROPY_MICROPYTHON', base_path('../ports/unix/micropython'))
+ CPYTHON3 = os.getenv("MICROPY_CPYTHON3", "python3")
+ MICROPYTHON = os.getenv("MICROPY_MICROPYTHON", base_path("../ports/unix/micropython"))
# Use CPython options to not save .pyc files, to only access the core standard library
# (not site packages which may clash with u-module names), and improve start up time.
CPYTHON3_CMD = [CPYTHON3, "-BS"]
# mpy-cross is only needed if --via-mpy command-line arg is passed
-MPYCROSS = os.getenv('MICROPY_MPYCROSS', base_path('../mpy-cross/mpy-cross'))
+MPYCROSS = os.getenv("MICROPY_MPYCROSS", base_path("../mpy-cross/mpy-cross"))
# For diff'ing test output
-DIFF = os.getenv('MICROPY_DIFF', 'diff -u')
+DIFF = os.getenv("MICROPY_DIFF", "diff -u")
# Set PYTHONIOENCODING so that CPython will use utf-8 on systems which set another encoding in the locale
-os.environ['PYTHONIOENCODING'] = 'utf-8'
+os.environ["PYTHONIOENCODING"] = "utf-8"
+
def rm_f(fname):
if os.path.exists(fname):
@@ -48,57 +51,62 @@ def rm_f(fname):
def convert_regex_escapes(line):
cs = []
escape = False
- for c in str(line, 'utf8'):
+ for c in str(line, "utf8"):
if escape:
escape = False
cs.append(c)
- elif c == '\\':
+ elif c == "\\":
escape = True
- elif c in ('(', ')', '[', ']', '{', '}', '.', '*', '+', '^', '$'):
- cs.append('\\' + c)
+ elif c in ("(", ")", "[", "]", "{", "}", ".", "*", "+", "^", "$"):
+ cs.append("\\" + c)
else:
cs.append(c)
# accept carriage-return(s) before final newline
- if cs[-1] == '\n':
- cs[-1] = '\r*\n'
- return bytes(''.join(cs), 'utf8')
+ if cs[-1] == "\n":
+ cs[-1] = "\r*\n"
+ return bytes("".join(cs), "utf8")
def run_micropython(pyb, args, test_file, is_special=False):
special_tests = (
- 'micropython/meminfo.py', 'basics/bytes_compare3.py',
- 'basics/builtin_help.py', 'thread/thread_exc2.py',
- 'esp32/partition_ota.py',
+ "micropython/meminfo.py",
+ "basics/bytes_compare3.py",
+ "basics/builtin_help.py",
+ "thread/thread_exc2.py",
+ "esp32/partition_ota.py",
)
had_crash = False
if pyb is None:
# run on PC
- if test_file.startswith(('cmdline/', base_path('feature_check/'))) or test_file in special_tests:
+ if (
+ test_file.startswith(("cmdline/", base_path("feature_check/")))
+ or test_file in special_tests
+ ):
# special handling for tests of the unix cmdline program
is_special = True
if is_special:
# check for any cmdline options needed for this test
args = [MICROPYTHON]
- with open(test_file, 'rb') as f:
+ with open(test_file, "rb") as f:
line = f.readline()
- if line.startswith(b'# cmdline:'):
+ if line.startswith(b"# cmdline:"):
# subprocess.check_output on Windows only accepts strings, not bytes
- args += [str(c, 'utf-8') for c in line[10:].strip().split()]
+ args += [str(c, "utf-8") for c in line[10:].strip().split()]
# run the test, possibly with redirected input
try:
- if 'repl_' in test_file:
+ if "repl_" in test_file:
# Need to use a PTY to test command line editing
try:
import pty
except ImportError:
# in case pty module is not available, like on Windows
- return b'SKIP\n'
+ return b"SKIP\n"
import select
def get(required=False):
- rv = b''
+ rv = b""
while True:
ready = select.select([master], [], [], 0.02)
if ready[0] == [master]:
@@ -111,14 +119,15 @@ def run_micropython(pyb, args, test_file, is_special=False):
os.write(master, what)
return get()
- with open(test_file, 'rb') as f:
+ with open(test_file, "rb") as f:
# instead of: output_mupy = subprocess.check_output(args, stdin=f)
master, slave = pty.openpty()
- p = subprocess.Popen(args, stdin=slave, stdout=slave,
- stderr=subprocess.STDOUT, bufsize=0)
+ p = subprocess.Popen(
+ args, stdin=slave, stdout=slave, stderr=subprocess.STDOUT, bufsize=0
+ )
banner = get(True)
- output_mupy = banner + b''.join(send_get(line) for line in f)
- send_get(b'\x04') # exit the REPL, so coverage info is saved
+ output_mupy = banner + b"".join(send_get(line) for line in f)
+ send_get(b"\x04") # exit the REPL, so coverage info is saved
# At this point the process might have exited already, but trying to
# kill it 'again' normally doesn't result in exceptions as Python and/or
# the OS seem to try to handle this nicely. When running Linux on WSL
@@ -132,22 +141,28 @@ def run_micropython(pyb, args, test_file, is_special=False):
os.close(master)
os.close(slave)
else:
- output_mupy = subprocess.check_output(args + [test_file], stderr=subprocess.STDOUT)
+ output_mupy = subprocess.check_output(
+ args + [test_file], stderr=subprocess.STDOUT
+ )
except subprocess.CalledProcessError:
- return b'CRASH'
+ return b"CRASH"
else:
# a standard test run on PC
# create system command
- cmdlist = [MICROPYTHON, '-X', 'emit=' + args.emit]
+ cmdlist = [MICROPYTHON, "-X", "emit=" + args.emit]
if args.heapsize is not None:
- cmdlist.extend(['-X', 'heapsize=' + args.heapsize])
+ cmdlist.extend(["-X", "heapsize=" + args.heapsize])
# if running via .mpy, first compile the .py file
if args.via_mpy:
- subprocess.check_output([MPYCROSS] + args.mpy_cross_flags.split() + ['-o', 'mpytest.mpy', '-X', 'emit=' + args.emit, test_file])
- cmdlist.extend(['-m', 'mpytest'])
+ subprocess.check_output(
+ [MPYCROSS]
+ + args.mpy_cross_flags.split()
+ + ["-o", "mpytest.mpy", "-X", "emit=" + args.emit, test_file]
+ )
+ cmdlist.extend(["-m", "mpytest"])
else:
cmdlist.append(test_file)
@@ -156,11 +171,11 @@ def run_micropython(pyb, args, test_file, is_special=False):
output_mupy = subprocess.check_output(cmdlist, stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as er:
had_crash = True
- output_mupy = er.output + b'CRASH'
+ output_mupy = er.output + b"CRASH"
# clean up if we had an intermediate .mpy file
if args.via_mpy:
- rm_f('mpytest.mpy')
+ rm_f("mpytest.mpy")
else:
# run on pyboard
@@ -169,56 +184,58 @@ def run_micropython(pyb, args, test_file, is_special=False):
output_mupy = pyb.execfile(test_file)
except pyboard.PyboardError as e:
had_crash = True
- if not is_special and e.args[0] == 'exception':
- output_mupy = e.args[1] + e.args[2] + b'CRASH'
+ if not is_special and e.args[0] == "exception":
+ output_mupy = e.args[1] + e.args[2] + b"CRASH"
else:
- output_mupy = b'CRASH'
+ output_mupy = b"CRASH"
# canonical form for all ports/platforms is to use \n for end-of-line
- output_mupy = output_mupy.replace(b'\r\n', b'\n')
+ output_mupy = output_mupy.replace(b"\r\n", b"\n")
# don't try to convert the output if we should skip this test
- if had_crash or output_mupy in (b'SKIP\n', b'CRASH'):
+ if had_crash or output_mupy in (b"SKIP\n", b"CRASH"):
return output_mupy
if is_special or test_file in special_tests:
# convert parts of the output that are not stable across runs
- with open(test_file + '.exp', 'rb') as f:
+ with open(test_file + ".exp", "rb") as f:
lines_exp = []
for line in f.readlines():
- if line == b'########\n':
+ if line == b"########\n":
line = (line,)
else:
line = (line, re.compile(convert_regex_escapes(line)))
lines_exp.append(line)
- lines_mupy = [line + b'\n' for line in output_mupy.split(b'\n')]
- if output_mupy.endswith(b'\n'):
- lines_mupy = lines_mupy[:-1] # remove erroneous last empty line
+ lines_mupy = [line + b"\n" for line in output_mupy.split(b"\n")]
+ if output_mupy.endswith(b"\n"):
+ lines_mupy = lines_mupy[:-1] # remove erroneous last empty line
i_mupy = 0
for i in range(len(lines_exp)):
- if lines_exp[i][0] == b'########\n':
+ if lines_exp[i][0] == b"########\n":
# 8x #'s means match 0 or more whole lines
line_exp = lines_exp[i + 1]
skip = 0
- while i_mupy + skip < len(lines_mupy) and not line_exp[1].match(lines_mupy[i_mupy + skip]):
+ while i_mupy + skip < len(lines_mupy) and not line_exp[1].match(
+ lines_mupy[i_mupy + skip]
+ ):
skip += 1
if i_mupy + skip >= len(lines_mupy):
- lines_mupy[i_mupy] = b'######## FAIL\n'
+ lines_mupy[i_mupy] = b"######## FAIL\n"
break
- del lines_mupy[i_mupy:i_mupy + skip]
- lines_mupy.insert(i_mupy, b'########\n')
+ del lines_mupy[i_mupy : i_mupy + skip]
+ lines_mupy.insert(i_mupy, b"########\n")
i_mupy += 1
else:
# a regex
if lines_exp[i][1].match(lines_mupy[i_mupy]):
lines_mupy[i_mupy] = lines_exp[i][0]
else:
- #print("don't match: %r %s" % (lines_exp[i][1], lines_mupy[i_mupy])) # DEBUG
+ # print("don't match: %r %s" % (lines_exp[i][1], lines_mupy[i_mupy])) # DEBUG
pass
i_mupy += 1
if i_mupy >= len(lines_mupy):
break
- output_mupy = b''.join(lines_mupy)
+ output_mupy = b"".join(lines_mupy)
return output_mupy
@@ -261,193 +278,220 @@ def run_tests(pyb, tests, args, result_dir):
# run-tests.py script itself so use base_path.
# Check if micropython.native is supported, and skip such tests if it's not
- output = run_feature_check(pyb, args, base_path, 'native_check.py')
- if output == b'CRASH':
+ output = run_feature_check(pyb, args, base_path, "native_check.py")
+ if output == b"CRASH":
skip_native = True
# Check if arbitrary-precision integers are supported, and skip such tests if it's not
- output = run_feature_check(pyb, args, base_path, 'int_big.py')
- if output != b'1000000000000000000000000000000000000000000000\n':
+ output = run_feature_check(pyb, args, base_path, "int_big.py")
+ if output != b"1000000000000000000000000000000000000000000000\n":
skip_int_big = True
# Check if bytearray is supported, and skip such tests if it's not
- output = run_feature_check(pyb, args, base_path, 'bytearray.py')
- if output != b'bytearray\n':
+ output = run_feature_check(pyb, args, base_path, "bytearray.py")
+ if output != b"bytearray\n":
skip_bytearray = True
# Check if set type (and set literals) is supported, and skip such tests if it's not
- output = run_feature_check(pyb, args, base_path, 'set_check.py')
- if output == b'CRASH':
+ output = run_feature_check(pyb, args, base_path, "set_check.py")
+ if output == b"CRASH":
skip_set_type = True
# Check if slice is supported, and skip such tests if it's not
- output = run_feature_check(pyb, args, base_path, 'slice.py')
- if output != b'slice\n':
+ output = run_feature_check(pyb, args, base_path, "slice.py")
+ if output != b"slice\n":
skip_slice = True
# Check if async/await keywords are supported, and skip such tests if it's not
- output = run_feature_check(pyb, args, base_path, 'async_check.py')
- if output == b'CRASH':
+ output = run_feature_check(pyb, args, base_path, "async_check.py")
+ if output == b"CRASH":
skip_async = True
# Check if const keyword (MicroPython extension) is supported, and skip such tests if it's not
- output = run_feature_check(pyb, args, base_path, 'const.py')
- if output == b'CRASH':
+ output = run_feature_check(pyb, args, base_path, "const.py")
+ if output == b"CRASH":
skip_const = True
# Check if __rOP__ special methods are supported, and skip such tests if it's not
- output = run_feature_check(pyb, args, base_path, 'reverse_ops.py')
- if output == b'TypeError\n':
+ output = run_feature_check(pyb, args, base_path, "reverse_ops.py")
+ if output == b"TypeError\n":
skip_revops = True
# Check if uio module exists, and skip such tests if it doesn't
- output = run_feature_check(pyb, args, base_path, 'uio_module.py')
- if output != b'uio\n':
+ output = run_feature_check(pyb, args, base_path, "uio_module.py")
+ if output != b"uio\n":
skip_io_module = True
# Check if emacs repl is supported, and skip such tests if it's not
- t = run_feature_check(pyb, args, base_path, 'repl_emacs_check.py')
- if 'True' not in str(t, 'ascii'):
- skip_tests.add('cmdline/repl_emacs_keys.py')
+ t = run_feature_check(pyb, args, base_path, "repl_emacs_check.py")
+ if "True" not in str(t, "ascii"):
+ skip_tests.add("cmdline/repl_emacs_keys.py")
# Check if words movement in repl is supported, and skip such tests if it's not
- t = run_feature_check(pyb, args, base_path, 'repl_words_move_check.py')
- if 'True' not in str(t, 'ascii'):
- skip_tests.add('cmdline/repl_words_move.py')
+ t = run_feature_check(pyb, args, base_path, "repl_words_move_check.py")
+ if "True" not in str(t, "ascii"):
+ skip_tests.add("cmdline/repl_words_move.py")
- upy_byteorder = run_feature_check(pyb, args, base_path, 'byteorder.py')
- upy_float_precision = run_feature_check(pyb, args, base_path, 'float.py')
- if upy_float_precision == b'CRASH':
+ upy_byteorder = run_feature_check(pyb, args, base_path, "byteorder.py")
+ upy_float_precision = run_feature_check(pyb, args, base_path, "float.py")
+ if upy_float_precision == b"CRASH":
upy_float_precision = 0
else:
upy_float_precision = int(upy_float_precision)
- has_complex = run_feature_check(pyb, args, base_path, 'complex.py') == b'complex\n'
- has_coverage = run_feature_check(pyb, args, base_path, 'coverage.py') == b'coverage\n'
- cpy_byteorder = subprocess.check_output(CPYTHON3_CMD + [base_path('feature_check/byteorder.py')])
- skip_endian = (upy_byteorder != cpy_byteorder)
+ has_complex = run_feature_check(pyb, args, base_path, "complex.py") == b"complex\n"
+ has_coverage = run_feature_check(pyb, args, base_path, "coverage.py") == b"coverage\n"
+ cpy_byteorder = subprocess.check_output(
+ CPYTHON3_CMD + [base_path("feature_check/byteorder.py")]
+ )
+ skip_endian = upy_byteorder != cpy_byteorder
# These tests don't test slice explicitly but rather use it to perform the test
misc_slice_tests = (
- 'builtin_range',
- 'class_super',
- 'containment',
- 'errno1',
- 'fun_str',
- 'generator1',
- 'globals_del',
- 'memoryview1',
- 'memoryview_gc',
- 'object1',
- 'python34',
- 'struct_endian',
+ "builtin_range",
+ "class_super",
+ "containment",
+ "errno1",
+ "fun_str",
+ "generator1",
+ "globals_del",
+ "memoryview1",
+ "memoryview_gc",
+ "object1",
+ "python34",
+ "struct_endian",
)
# Some tests shouldn't be run on GitHub Actions
- if os.getenv('GITHUB_ACTIONS') == 'true':
- skip_tests.add('thread/stress_schedule.py') # has reliability issues
+ if os.getenv("GITHUB_ACTIONS") == "true":
+ skip_tests.add("thread/stress_schedule.py") # has reliability issues
if upy_float_precision == 0:
- skip_tests.add('extmod/uctypes_le_float.py')
- skip_tests.add('extmod/uctypes_native_float.py')
- skip_tests.add('extmod/uctypes_sizeof_float.py')
- skip_tests.add('extmod/ujson_dumps_float.py')
- skip_tests.add('extmod/ujson_loads_float.py')
- skip_tests.add('extmod/urandom_extra_float.py')
- skip_tests.add('misc/rge_sm.py')
+ skip_tests.add("extmod/uctypes_le_float.py")
+ skip_tests.add("extmod/uctypes_native_float.py")
+ skip_tests.add("extmod/uctypes_sizeof_float.py")
+ skip_tests.add("extmod/ujson_dumps_float.py")
+ skip_tests.add("extmod/ujson_loads_float.py")
+ skip_tests.add("extmod/urandom_extra_float.py")
+ skip_tests.add("misc/rge_sm.py")
if upy_float_precision < 32:
- skip_tests.add('float/float2int_intbig.py') # requires fp32, there's float2int_fp30_intbig.py instead
- skip_tests.add('float/string_format.py') # requires fp32, there's string_format_fp30.py instead
- skip_tests.add('float/bytes_construct.py') # requires fp32
- skip_tests.add('float/bytearray_construct.py') # requires fp32
+ skip_tests.add(
+ "float/float2int_intbig.py"
+ ) # requires fp32, there's float2int_fp30_intbig.py instead
+ skip_tests.add(
+ "float/string_format.py"
+ ) # requires fp32, there's string_format_fp30.py instead
+ skip_tests.add("float/bytes_construct.py") # requires fp32
+ skip_tests.add("float/bytearray_construct.py") # requires fp32
if upy_float_precision < 64:
- skip_tests.add('float/float_divmod.py') # tested by float/float_divmod_relaxed.py instead
- skip_tests.add('float/float2int_doubleprec_intbig.py')
- skip_tests.add('float/float_parse_doubleprec.py')
+ skip_tests.add("float/float_divmod.py") # tested by float/float_divmod_relaxed.py instead
+ skip_tests.add("float/float2int_doubleprec_intbig.py")
+ skip_tests.add("float/float_parse_doubleprec.py")
if not has_complex:
- skip_tests.add('float/complex1.py')
- skip_tests.add('float/complex1_intbig.py')
- skip_tests.add('float/complex_special_methods.py')
- skip_tests.add('float/int_big_float.py')
- skip_tests.add('float/true_value.py')
- skip_tests.add('float/types.py')
+ skip_tests.add("float/complex1.py")
+ skip_tests.add("float/complex1_intbig.py")
+ skip_tests.add("float/complex_special_methods.py")
+ skip_tests.add("float/int_big_float.py")
+ skip_tests.add("float/true_value.py")
+ skip_tests.add("float/types.py")
if not has_coverage:
- skip_tests.add('cmdline/cmd_parsetree.py')
+ skip_tests.add("cmdline/cmd_parsetree.py")
# Some tests shouldn't be run on a PC
- if args.target == 'unix':
+ if args.target == "unix":
# unix build does not have the GIL so can't run thread mutation tests
for t in tests:
- if t.startswith('thread/mutate_'):
+ if t.startswith("thread/mutate_"):
skip_tests.add(t)
# Some tests shouldn't be run on pyboard
- if args.target != 'unix':
- skip_tests.add('basics/exception_chain.py') # warning is not printed
- skip_tests.add('micropython/meminfo.py') # output is very different to PC output
- skip_tests.add('extmod/machine_mem.py') # raw memory access not supported
-
- if args.target == 'wipy':
- skip_tests.add('misc/print_exception.py') # requires error reporting full
- skip_tests.update({'extmod/uctypes_%s.py' % t for t in 'bytearray le native_le ptr_le ptr_native_le sizeof sizeof_native array_assign_le array_assign_native_le'.split()}) # requires uctypes
- skip_tests.add('extmod/zlibd_decompress.py') # requires zlib
- skip_tests.add('extmod/uheapq1.py') # uheapq not supported by WiPy
- skip_tests.add('extmod/urandom_basic.py') # requires urandom
- skip_tests.add('extmod/urandom_extra.py') # requires urandom
- elif args.target == 'esp8266':
- skip_tests.add('misc/rge_sm.py') # too large
- elif args.target == 'minimal':
- skip_tests.add('basics/class_inplace_op.py') # all special methods not supported
- skip_tests.add('basics/subclass_native_init.py')# native subclassing corner cases not support
- skip_tests.add('misc/rge_sm.py') # too large
- skip_tests.add('micropython/opt_level.py') # don't assume line numbers are stored
- elif args.target == 'nrf':
- skip_tests.add('basics/memoryview1.py') # no item assignment for memoryview
- skip_tests.add('extmod/urandom_basic.py') # unimplemented: urandom.seed
- skip_tests.add('micropython/opt_level.py') # no support for line numbers
- skip_tests.add('misc/non_compliant.py') # no item assignment for bytearray
+ if args.target != "unix":
+ skip_tests.add("basics/exception_chain.py") # warning is not printed
+ skip_tests.add("micropython/meminfo.py") # output is very different to PC output
+ skip_tests.add("extmod/machine_mem.py") # raw memory access not supported
+
+ if args.target == "wipy":
+ skip_tests.add("misc/print_exception.py") # requires error reporting full
+ skip_tests.update(
+ {
+ "extmod/uctypes_%s.py" % t
+ for t in "bytearray le native_le ptr_le ptr_native_le sizeof sizeof_native array_assign_le array_assign_native_le".split()
+ }
+ ) # requires uctypes
+ skip_tests.add("extmod/zlibd_decompress.py") # requires zlib
+ skip_tests.add("extmod/uheapq1.py") # uheapq not supported by WiPy
+ skip_tests.add("extmod/urandom_basic.py") # requires urandom
+ skip_tests.add("extmod/urandom_extra.py") # requires urandom
+ elif args.target == "esp8266":
+ skip_tests.add("misc/rge_sm.py") # too large
+ elif args.target == "minimal":
+ skip_tests.add("basics/class_inplace_op.py") # all special methods not supported
+ skip_tests.add(
+ "basics/subclass_native_init.py"
+ ) # native subclassing corner cases not support
+ skip_tests.add("misc/rge_sm.py") # too large
+ skip_tests.add("micropython/opt_level.py") # don't assume line numbers are stored
+ elif args.target == "nrf":
+ skip_tests.add("basics/memoryview1.py") # no item assignment for memoryview
+ skip_tests.add("extmod/urandom_basic.py") # unimplemented: urandom.seed
+ skip_tests.add("micropython/opt_level.py") # no support for line numbers
+ skip_tests.add("misc/non_compliant.py") # no item assignment for bytearray
for t in tests:
- if t.startswith('basics/io_'):
+ if t.startswith("basics/io_"):
skip_tests.add(t)
- elif args.target == 'qemu-arm':
- skip_tests.add('misc/print_exception.py') # requires sys stdfiles
+ elif args.target == "qemu-arm":
+ skip_tests.add("misc/print_exception.py") # requires sys stdfiles
# Some tests are known to fail on 64-bit machines
- if pyb is None and platform.architecture()[0] == '64bit':
+ if pyb is None and platform.architecture()[0] == "64bit":
pass
# Some tests use unsupported features on Windows
- if os.name == 'nt':
- skip_tests.add('import/import_file.py') # works but CPython prints forward slashes
+ if os.name == "nt":
+ skip_tests.add("import/import_file.py") # works but CPython prints forward slashes
# Some tests are known to fail with native emitter
# Remove them from the below when they work
- if args.emit == 'native':
- skip_tests.update({'basics/%s.py' % t for t in 'gen_yield_from_close generator_name'.split()}) # require raise_varargs, generator name
- skip_tests.update({'basics/async_%s.py' % t for t in 'with with2 with_break with_return'.split()}) # require async_with
- skip_tests.update({'basics/%s.py' % t for t in 'try_reraise try_reraise2'.split()}) # require raise_varargs
- skip_tests.add('basics/annotate_var.py') # requires checking for unbound local
- skip_tests.add('basics/del_deref.py') # requires checking for unbound local
- skip_tests.add('basics/del_local.py') # requires checking for unbound local
- skip_tests.add('basics/exception_chain.py') # raise from is not supported
- skip_tests.add('basics/scope_implicit.py') # requires checking for unbound local
- skip_tests.add('basics/try_finally_return2.py') # requires raise_varargs
- skip_tests.add('basics/unboundlocal.py') # requires checking for unbound local
- skip_tests.add('extmod/uasyncio_event.py') # unknown issue
- skip_tests.add('extmod/uasyncio_lock.py') # requires async with
- skip_tests.add('extmod/uasyncio_micropython.py') # unknown issue
- skip_tests.add('extmod/uasyncio_wait_for.py') # unknown issue
- skip_tests.add('misc/features.py') # requires raise_varargs
- skip_tests.add('misc/print_exception.py') # because native doesn't have proper traceback info
- skip_tests.add('misc/sys_exc_info.py') # sys.exc_info() is not supported for native
- skip_tests.add('micropython/emg_exc.py') # because native doesn't have proper traceback info
- skip_tests.add('micropython/heapalloc_traceback.py') # because native doesn't have proper traceback info
- skip_tests.add('micropython/opt_level_lineno.py') # native doesn't have proper traceback info
- skip_tests.add('micropython/schedule.py') # native code doesn't check pending events
+ if args.emit == "native":
+ skip_tests.update(
+ {"basics/%s.py" % t for t in "gen_yield_from_close generator_name".split()}
+ ) # require raise_varargs, generator name
+ skip_tests.update(
+ {"basics/async_%s.py" % t for t in "with with2 with_break with_return".split()}
+ ) # require async_with
+ skip_tests.update(
+ {"basics/%s.py" % t for t in "try_reraise try_reraise2".split()}
+ ) # require raise_varargs
+ skip_tests.add("basics/annotate_var.py") # requires checking for unbound local
+ skip_tests.add("basics/del_deref.py") # requires checking for unbound local
+ skip_tests.add("basics/del_local.py") # requires checking for unbound local
+ skip_tests.add("basics/exception_chain.py") # raise from is not supported
+ skip_tests.add("basics/scope_implicit.py") # requires checking for unbound local
+ skip_tests.add("basics/try_finally_return2.py") # requires raise_varargs
+ skip_tests.add("basics/unboundlocal.py") # requires checking for unbound local
+ skip_tests.add("extmod/uasyncio_event.py") # unknown issue
+ skip_tests.add("extmod/uasyncio_lock.py") # requires async with
+ skip_tests.add("extmod/uasyncio_micropython.py") # unknown issue
+ skip_tests.add("extmod/uasyncio_wait_for.py") # unknown issue
+ skip_tests.add("misc/features.py") # requires raise_varargs
+ skip_tests.add(
+ "misc/print_exception.py"
+ ) # because native doesn't have proper traceback info
+ skip_tests.add("misc/sys_exc_info.py") # sys.exc_info() is not supported for native
+ skip_tests.add(
+ "micropython/emg_exc.py"
+ ) # because native doesn't have proper traceback info
+ skip_tests.add(
+ "micropython/heapalloc_traceback.py"
+ ) # because native doesn't have proper traceback info
+ skip_tests.add(
+ "micropython/opt_level_lineno.py"
+ ) # native doesn't have proper traceback info
+ skip_tests.add("micropython/schedule.py") # native code doesn't check pending events
for test_file in tests:
- test_file = test_file.replace('\\', '/')
+ test_file = test_file.replace("\\", "/")
if args.filters:
# Default verdict is the opposit of the first action
@@ -458,9 +502,13 @@ def run_tests(pyb, tests, args, result_dir):
if verdict == "exclude":
continue
- test_basename = test_file.replace('..', '_').replace('./', '').replace('/', '_')
+ test_basename = test_file.replace("..", "_").replace("./", "").replace("/", "_")
test_name = os.path.splitext(os.path.basename(test_file))[0]
- is_native = test_name.startswith("native_") or test_name.startswith("viper_") or args.emit == "native"
+ is_native = (
+ test_name.startswith("native_")
+ or test_name.startswith("viper_")
+ or args.emit == "native"
+ )
is_endian = test_name.endswith("_endian")
is_int_big = test_name.startswith("int_big") or test_name.endswith("_intbig")
is_bytearray = test_name.startswith("bytearray") or test_name.endswith("_bytearray")
@@ -493,23 +541,23 @@ def run_tests(pyb, tests, args, result_dir):
continue
# get expected output
- test_file_expected = test_file + '.exp'
+ test_file_expected = test_file + ".exp"
if os.path.isfile(test_file_expected):
# expected output given by a file, so read that in
- with open(test_file_expected, 'rb') as f:
+ with open(test_file_expected, "rb") as f:
output_expected = f.read()
else:
# run CPython to work out expected output
try:
output_expected = subprocess.check_output(CPYTHON3_CMD + [test_file])
if args.write_exp:
- with open(test_file_expected, 'wb') as f:
+ with open(test_file_expected, "wb") as f:
f.write(output_expected)
except subprocess.CalledProcessError:
- output_expected = b'CPYTHON3 CRASH'
+ output_expected = b"CPYTHON3 CRASH"
# canonical form for all host platforms is to use \n for end-of-line
- output_expected = output_expected.replace(b'\r\n', b'\n')
+ output_expected = output_expected.replace(b"\r\n", b"\n")
if args.write_exp:
continue
@@ -517,7 +565,7 @@ def run_tests(pyb, tests, args, result_dir):
# run MicroPython
output_mupy = run_micropython(pyb, args, test_file)
- if output_mupy == b'SKIP\n':
+ if output_mupy == b"SKIP\n":
print("skip ", test_file)
skipped_tests.append(test_name)
continue
@@ -549,9 +597,9 @@ def run_tests(pyb, tests, args, result_dir):
print("{} tests passed".format(passed_count))
if len(skipped_tests) > 0:
- print("{} tests skipped: {}".format(len(skipped_tests), ' '.join(skipped_tests)))
+ print("{} tests skipped: {}".format(len(skipped_tests), " ".join(skipped_tests)))
if len(failed_tests) > 0:
- print("{} tests failed: {}".format(len(failed_tests), ' '.join(failed_tests)))
+ print("{} tests failed: {}".format(len(failed_tests), " ".join(failed_tests)))
return False
# all tests succeeded
@@ -559,7 +607,6 @@ def run_tests(pyb, tests, args, result_dir):
class append_filter(argparse.Action):
-
def __init__(self, option_strings, dest, **kwargs):
super().__init__(option_strings, dest, default=[], **kwargs)
@@ -576,7 +623,7 @@ class append_filter(argparse.Action):
def main():
cmd_parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
- description='''Run and manage tests for MicroPython.
+ description="""Run and manage tests for MicroPython.
Tests are discovered by scanning test directories for .py files or using the
specified test files. If test files nor directories are specified, the script
@@ -587,34 +634,81 @@ produced by running the test through CPython unless a <test>.exp file is found,
case it is used as comparison.
If a test fails, run-tests.py produces a pair of <test>.out and <test>.exp files in the result
directory with the MicroPython output and the expectations, respectively.
-''',
- epilog='''\
+""",
+ epilog="""\
Options -i and -e can be multiple and processed in the order given. Regex
"search" (vs "match") operation is used. An action (include/exclude) of
the last matching regex is used:
run-tests.py -i async - exclude all, then include tests containing "async" anywhere
run-tests.py -e '/big.+int' - include all, then exclude by regex
run-tests.py -e async -i async_foo - include all, exclude async, yet still include async_foo
-''')
- cmd_parser.add_argument('--target', default='unix', help='the target platform')
- cmd_parser.add_argument('--device', default='/dev/ttyACM0', help='the serial device or the IP address of the pyboard')
- cmd_parser.add_argument('-b', '--baudrate', default=115200, help='the baud rate of the serial device')
- cmd_parser.add_argument('-u', '--user', default='micro', help='the telnet login username')
- cmd_parser.add_argument('-p', '--password', default='python', help='the telnet login password')
- cmd_parser.add_argument('-d', '--test-dirs', nargs='*', help='input test directories (if no files given)')
- cmd_parser.add_argument('-r', '--result-dir', default=base_path('results'), help='directory for test results')
- cmd_parser.add_argument('-e', '--exclude', action=append_filter, metavar='REGEX', dest='filters', help='exclude test by regex on path/name.py')
- cmd_parser.add_argument('-i', '--include', action=append_filter, metavar='REGEX', dest='filters', help='include test by regex on path/name.py')
- cmd_parser.add_argument('--write-exp', action='store_true', help='use CPython to generate .exp files to run tests w/o CPython')
- cmd_parser.add_argument('--list-tests', action='store_true', help='list tests instead of running them')
- cmd_parser.add_argument('--emit', default='bytecode', help='MicroPython emitter to use (bytecode or native)')
- cmd_parser.add_argument('--heapsize', help='heapsize to use (use default if not specified)')
- cmd_parser.add_argument('--via-mpy', action='store_true', help='compile .py files to .mpy first')
- cmd_parser.add_argument('--mpy-cross-flags', default='-mcache-lookup-bc', help='flags to pass to mpy-cross')
- cmd_parser.add_argument('--keep-path', action='store_true', help='do not clear MICROPYPATH when running tests')
- cmd_parser.add_argument('files', nargs='*', help='input test files')
- cmd_parser.add_argument('--print-failures', action='store_true', help='print the diff of expected vs. actual output for failed tests and exit')
- cmd_parser.add_argument('--clean-failures', action='store_true', help='delete the .exp and .out files from failed tests and exit')
+""",
+ )
+ cmd_parser.add_argument("--target", default="unix", help="the target platform")
+ cmd_parser.add_argument(
+ "--device",
+ default="/dev/ttyACM0",
+ help="the serial device or the IP address of the pyboard",
+ )
+ cmd_parser.add_argument(
+ "-b", "--baudrate", default=115200, help="the baud rate of the serial device"
+ )
+ cmd_parser.add_argument("-u", "--user", default="micro", help="the telnet login username")
+ cmd_parser.add_argument("-p", "--password", default="python", help="the telnet login password")
+ cmd_parser.add_argument(
+ "-d", "--test-dirs", nargs="*", help="input test directories (if no files given)"
+ )
+ cmd_parser.add_argument(
+ "-r", "--result-dir", default=base_path("results"), help="directory for test results"
+ )
+ cmd_parser.add_argument(
+ "-e",
+ "--exclude",
+ action=append_filter,
+ metavar="REGEX",
+ dest="filters",
+ help="exclude test by regex on path/name.py",
+ )
+ cmd_parser.add_argument(
+ "-i",
+ "--include",
+ action=append_filter,
+ metavar="REGEX",
+ dest="filters",
+ help="include test by regex on path/name.py",
+ )
+ cmd_parser.add_argument(
+ "--write-exp",
+ action="store_true",
+ help="use CPython to generate .exp files to run tests w/o CPython",
+ )
+ cmd_parser.add_argument(
+ "--list-tests", action="store_true", help="list tests instead of running them"
+ )
+ cmd_parser.add_argument(
+ "--emit", default="bytecode", help="MicroPython emitter to use (bytecode or native)"
+ )
+ cmd_parser.add_argument("--heapsize", help="heapsize to use (use default if not specified)")
+ cmd_parser.add_argument(
+ "--via-mpy", action="store_true", help="compile .py files to .mpy first"
+ )
+ cmd_parser.add_argument(
+ "--mpy-cross-flags", default="-mcache-lookup-bc", help="flags to pass to mpy-cross"
+ )
+ cmd_parser.add_argument(
+ "--keep-path", action="store_true", help="do not clear MICROPYPATH when running tests"
+ )
+ cmd_parser.add_argument("files", nargs="*", help="input test files")
+ cmd_parser.add_argument(
+ "--print-failures",
+ action="store_true",
+ help="print the diff of expected vs. actual output for failed tests and exit",
+ )
+ cmd_parser.add_argument(
+ "--clean-failures",
+ action="store_true",
+ help="delete the .exp and .out files from failed tests and exit",
+ )
args = cmd_parser.parse_args()
if args.print_failures:
@@ -627,55 +721,82 @@ the last matching regex is used:
sys.exit(0)
if args.clean_failures:
- for f in glob(os.path.join(args.result_dir, "*.exp")) + glob(os.path.join(args.result_dir, "*.out")):
+ for f in glob(os.path.join(args.result_dir, "*.exp")) + glob(
+ os.path.join(args.result_dir, "*.out")
+ ):
os.remove(f)
sys.exit(0)
- LOCAL_TARGETS = ('unix', 'qemu-arm',)
- EXTERNAL_TARGETS = ('pyboard', 'wipy', 'esp8266', 'esp32', 'minimal', 'nrf')
+ LOCAL_TARGETS = (
+ "unix",
+ "qemu-arm",
+ )
+ EXTERNAL_TARGETS = ("pyboard", "wipy", "esp8266", "esp32", "minimal", "nrf")
if args.target in LOCAL_TARGETS or args.list_tests:
pyb = None
elif args.target in EXTERNAL_TARGETS:
global pyboard
- sys.path.append(base_path('../tools'))
+ sys.path.append(base_path("../tools"))
import pyboard
+
pyb = pyboard.Pyboard(args.device, args.baudrate, args.user, args.password)
pyb.enter_raw_repl()
else:
- raise ValueError('target must be one of %s' % ", ".join(LOCAL_TARGETS + EXTERNAL_TARGETS))
+ raise ValueError("target must be one of %s" % ", ".join(LOCAL_TARGETS + EXTERNAL_TARGETS))
if len(args.files) == 0:
if args.test_dirs is None:
- test_dirs = ('basics', 'micropython', 'misc', 'extmod',)
- if args.target == 'pyboard':
+ test_dirs = (
+ "basics",
+ "micropython",
+ "misc",
+ "extmod",
+ )
+ if args.target == "pyboard":
# run pyboard tests
- test_dirs += ('float', 'stress', 'pyb', 'pybnative', 'inlineasm')
- elif args.target in ('esp8266', 'esp32', 'minimal', 'nrf'):
- test_dirs += ('float',)
- elif args.target == 'wipy':
+ test_dirs += ("float", "stress", "pyb", "pybnative", "inlineasm")
+ elif args.target in ("esp8266", "esp32", "minimal", "nrf"):
+ test_dirs += ("float",)
+ elif args.target == "wipy":
# run WiPy tests
- test_dirs += ('wipy',)
- elif args.target == 'unix':
+ test_dirs += ("wipy",)
+ elif args.target == "unix":
# run PC tests
- test_dirs += ('float', 'import', 'io', 'stress', 'unicode', 'unix', 'cmdline',)
- elif args.target == 'qemu-arm':
+ test_dirs += (
+ "float",
+ "import",
+ "io",
+ "stress",
+ "unicode",
+ "unix",
+ "cmdline",
+ )
+ elif args.target == "qemu-arm":
if not args.write_exp:
- raise ValueError('--target=qemu-arm must be used with --write-exp')
+ raise ValueError("--target=qemu-arm must be used with --write-exp")
# Generate expected output files for qemu run.
# This list should match the test_dirs tuple in tinytest-codegen.py.
- test_dirs += ('float', 'inlineasm', 'qemu-arm',)
+ test_dirs += (
+ "float",
+ "inlineasm",
+ "qemu-arm",
+ )
else:
# run tests from these directories
test_dirs = args.test_dirs
- tests = sorted(test_file for test_files in (glob('{}/*.py'.format(dir)) for dir in test_dirs) for test_file in test_files)
+ tests = sorted(
+ test_file
+ for test_files in (glob("{}/*.py".format(dir)) for dir in test_dirs)
+ for test_file in test_files
+ )
else:
# tests explicitly given
tests = args.files
if not args.keep_path:
# clear search path to make sure tests use only builtin modules and those in extmod
- os.environ['MICROPYPATH'] = os.pathsep + base_path('../extmod')
+ os.environ["MICROPYPATH"] = os.pathsep + base_path("../extmod")
try:
os.makedirs(args.result_dir, exist_ok=True)
@@ -687,5 +808,6 @@ the last matching regex is used:
if not res:
sys.exit(1)
+
if __name__ == "__main__":
main()