mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
Bump up test.support to CPython 3.8.2
This commit is contained in:
1 parent
f5de59a4bd
commit
40451bba6b
2 files changed
+358
-71
No files matched your search
+357
-70
@@ -6,15 +6,16 @@ if __name__ != 'test.support':
|
||||
# import asyncio.events
|
||||
import collections.abc
|
||||
import contextlib
|
||||
import datetime
|
||||
import errno
|
||||
# import faulthandler
|
||||
import fnmatch
|
||||
import functools
|
||||
# import gc
|
||||
import glob
|
||||
import hashlib
|
||||
import importlib
|
||||
import importlib.util
|
||||
import io
|
||||
import locale
|
||||
# import logging.handlers
|
||||
# import nntplib
|
||||
import os
|
||||
@@ -68,6 +69,11 @@ try:
|
||||
except ImportError:
|
||||
resource = None
|
||||
|
||||
try:
|
||||
import _hashlib
|
||||
except ImportError:
|
||||
_hashlib = None
|
||||
|
||||
__all__ = [
|
||||
# globals
|
||||
"PIPE_MAX_SIZE", "verbose", "max_memuse", "use_resources", "failfast",
|
||||
@@ -85,15 +91,15 @@ __all__ = [
|
||||
"create_empty_file", "can_symlink", "fs_is_case_insensitive",
|
||||
# unittest
|
||||
"is_resource_enabled", "requires", "requires_freebsd_version",
|
||||
"requires_linux_version", "requires_mac_ver", "check_syntax_error",
|
||||
"check_syntax_warning",
|
||||
"requires_linux_version", "requires_mac_ver", "requires_hashdigest",
|
||||
"check_syntax_error", "check_syntax_warning",
|
||||
"TransientResource", "time_out", "socket_peer_reset", "ioerror_peer_reset",
|
||||
"transient_internet", "BasicTestRunner", "run_unittest", "run_doctest",
|
||||
"skip_unless_symlink", "requires_gzip", "requires_bz2", "requires_lzma",
|
||||
"bigmemtest", "bigaddrspacetest", "cpython_only", "get_attribute",
|
||||
"requires_IEEE_754", "skip_unless_xattr", "requires_zlib",
|
||||
"anticipate_failure", "load_package_tests", "detect_api_mismatch",
|
||||
"check__all__", "skip_unless_bind_unix_socket",
|
||||
"check__all__", "skip_unless_bind_unix_socket", "skip_if_buggy_ucrt_strfptime",
|
||||
"ignore_warnings",
|
||||
# sys
|
||||
"is_jython", "is_android", "check_impl_detail", "unix_shell",
|
||||
@@ -113,6 +119,7 @@ __all__ = [
|
||||
"run_with_locale", "swap_item",
|
||||
"swap_attr", "Matcher", "set_memlimit", "SuppressCrashReport", "sortdict",
|
||||
"run_with_tz", "PGO", "missing_compiler_executable", "fd_count",
|
||||
"ALWAYS_EQ", "LARGEST", "SMALLEST"
|
||||
]
|
||||
|
||||
class Error(Exception):
|
||||
@@ -645,6 +652,36 @@ def requires_mac_ver(*min_version):
|
||||
return decorator
|
||||
|
||||
|
||||
def requires_hashdigest(digestname, openssl=None):
|
||||
"""Decorator raising SkipTest if a hashing algorithm is not available
|
||||
|
||||
The hashing algorithm could be missing or blocked by a strict crypto
|
||||
policy.
|
||||
|
||||
If 'openssl' is True, then the decorator checks that OpenSSL provides
|
||||
the algorithm. Otherwise the check falls back to built-in
|
||||
implementations.
|
||||
|
||||
ValueError: [digital envelope routines: EVP_DigestInit_ex] disabled for FIPS
|
||||
ValueError: unsupported hash type md4
|
||||
"""
|
||||
def decorator(func):
|
||||
@functools.wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
try:
|
||||
if openssl and _hashlib is not None:
|
||||
_hashlib.new(digestname)
|
||||
else:
|
||||
hashlib.new(digestname)
|
||||
except ValueError:
|
||||
raise unittest.SkipTest(
|
||||
f"hash digest '{digestname}' is not available."
|
||||
)
|
||||
return func(*args, **kwargs)
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
|
||||
HOST = "localhost"
|
||||
HOSTv4 = "127.0.0.1"
|
||||
HOSTv6 = "::1"
|
||||
@@ -757,22 +794,22 @@ def bind_unix_socket(sock, addr):
|
||||
sock.close()
|
||||
raise unittest.SkipTest('cannot bind AF_UNIX sockets')
|
||||
|
||||
# def _is_ipv6_enabled():
|
||||
# """Check whether IPv6 is enabled on this host."""
|
||||
# if socket.has_ipv6:
|
||||
# sock = None
|
||||
# try:
|
||||
# sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
|
||||
# sock.bind((HOSTv6, 0))
|
||||
# return True
|
||||
# except OSError:
|
||||
# pass
|
||||
# finally:
|
||||
# if sock:
|
||||
# sock.close()
|
||||
# return False
|
||||
def _is_ipv6_enabled():
|
||||
"""Check whether IPv6 is enabled on this host."""
|
||||
if socket.has_ipv6:
|
||||
sock = None
|
||||
try:
|
||||
sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
|
||||
sock.bind((HOSTv6, 0))
|
||||
return True
|
||||
except OSError:
|
||||
pass
|
||||
finally:
|
||||
if sock:
|
||||
sock.close()
|
||||
return False
|
||||
|
||||
# IPV6_ENABLED = _is_ipv6_enabled()
|
||||
IPV6_ENABLED = _is_ipv6_enabled()
|
||||
|
||||
def system_must_validate_cert(f):
|
||||
"""Skip the test on TLS certificate validation failures."""
|
||||
@@ -896,25 +933,25 @@ if sys.platform == 'darwin':
|
||||
TESTFN_UNICODE = unicodedata.normalize('NFD', TESTFN_UNICODE)
|
||||
TESTFN_ENCODING = sys.getfilesystemencoding()
|
||||
|
||||
# # TESTFN_UNENCODABLE is a filename (str type) that should *not* be able to be
|
||||
# # encoded by the filesystem encoding (in strict mode). It can be None if we
|
||||
# # cannot generate such filename.
|
||||
# TESTFN_UNENCODABLE = None
|
||||
# if os.name == 'nt':
|
||||
# # skip win32s (0) or Windows 9x/ME (1)
|
||||
# if sys.getwindowsversion().platform >= 2:
|
||||
# # Different kinds of characters from various languages to minimize the
|
||||
# # probability that the whole name is encodable to MBCS (issue #9819)
|
||||
# TESTFN_UNENCODABLE = TESTFN + "-\u5171\u0141\u2661\u0363\uDC80"
|
||||
# try:
|
||||
# TESTFN_UNENCODABLE.encode(TESTFN_ENCODING)
|
||||
# except UnicodeEncodeError:
|
||||
# pass
|
||||
# else:
|
||||
# print('WARNING: The filename %r CAN be encoded by the filesystem encoding (%s). '
|
||||
# 'Unicode filename tests may not be effective'
|
||||
# % (TESTFN_UNENCODABLE, TESTFN_ENCODING))
|
||||
# TESTFN_UNENCODABLE = None
|
||||
# TESTFN_UNENCODABLE is a filename (str type) that should *not* be able to be
|
||||
# encoded by the filesystem encoding (in strict mode). It can be None if we
|
||||
# cannot generate such filename.
|
||||
TESTFN_UNENCODABLE = None
|
||||
if os.name == 'nt':
|
||||
# skip win32s (0) or Windows 9x/ME (1)
|
||||
if sys.getwindowsversion().platform >= 2:
|
||||
# Different kinds of characters from various languages to minimize the
|
||||
# probability that the whole name is encodable to MBCS (issue #9819)
|
||||
TESTFN_UNENCODABLE = TESTFN + "-\u5171\u0141\u2661\u0363\uDC80"
|
||||
try:
|
||||
TESTFN_UNENCODABLE.encode(TESTFN_ENCODING)
|
||||
except UnicodeEncodeError:
|
||||
pass
|
||||
else:
|
||||
print('WARNING: The filename %r CAN be encoded by the filesystem encoding (%s). '
|
||||
'Unicode filename tests may not be effective'
|
||||
% (TESTFN_UNENCODABLE, TESTFN_ENCODING))
|
||||
TESTFN_UNENCODABLE = None
|
||||
# # Mac OS X denies unencodable filenames (invalid utf-8)
|
||||
# elif sys.platform != 'darwin':
|
||||
# try:
|
||||
@@ -929,35 +966,35 @@ TESTFN_ENCODING = sys.getfilesystemencoding()
|
||||
# # the byte 0xff. Skip some unicode filename tests.
|
||||
# pass
|
||||
|
||||
# # TESTFN_UNDECODABLE is a filename (bytes type) that should *not* be able to be
|
||||
# # decoded from the filesystem encoding (in strict mode). It can be None if we
|
||||
# # cannot generate such filename (ex: the latin1 encoding can decode any byte
|
||||
# # sequence). On UNIX, TESTFN_UNDECODABLE can be decoded by os.fsdecode() thanks
|
||||
# # to the surrogateescape error handler (PEP 383), but not from the filesystem
|
||||
# # encoding in strict mode.
|
||||
# TESTFN_UNDECODABLE = None
|
||||
# for name in (
|
||||
# # b'\xff' is not decodable by os.fsdecode() with code page 932. Windows
|
||||
# # accepts it to create a file or a directory, or don't accept to enter to
|
||||
# # such directory (when the bytes name is used). So test b'\xe7' first: it is
|
||||
# # not decodable from cp932.
|
||||
# b'\xe7w\xf0',
|
||||
# # undecodable from ASCII, UTF-8
|
||||
# b'\xff',
|
||||
# # undecodable from iso8859-3, iso8859-6, iso8859-7, cp424, iso8859-8, cp856
|
||||
# # and cp857
|
||||
# b'\xae\xd5'
|
||||
# # undecodable from UTF-8 (UNIX and Mac OS X)
|
||||
# b'\xed\xb2\x80', b'\xed\xb4\x80',
|
||||
# # undecodable from shift_jis, cp869, cp874, cp932, cp1250, cp1251, cp1252,
|
||||
# # cp1253, cp1254, cp1255, cp1257, cp1258
|
||||
# b'\x81\x98',
|
||||
# ):
|
||||
# try:
|
||||
# name.decode(TESTFN_ENCODING)
|
||||
# except UnicodeDecodeError:
|
||||
# TESTFN_UNDECODABLE = os.fsencode(TESTFN) + name
|
||||
# break
|
||||
# TESTFN_UNDECODABLE is a filename (bytes type) that should *not* be able to be
|
||||
# decoded from the filesystem encoding (in strict mode). It can be None if we
|
||||
# cannot generate such filename (ex: the latin1 encoding can decode any byte
|
||||
# sequence). On UNIX, TESTFN_UNDECODABLE can be decoded by os.fsdecode() thanks
|
||||
# to the surrogateescape error handler (PEP 383), but not from the filesystem
|
||||
# encoding in strict mode.
|
||||
TESTFN_UNDECODABLE = None
|
||||
for name in (
|
||||
# b'\xff' is not decodable by os.fsdecode() with code page 932. Windows
|
||||
# accepts it to create a file or a directory, or don't accept to enter to
|
||||
# such directory (when the bytes name is used). So test b'\xe7' first: it is
|
||||
# not decodable from cp932.
|
||||
b'\xe7w\xf0',
|
||||
# undecodable from ASCII, UTF-8
|
||||
b'\xff',
|
||||
# undecodable from iso8859-3, iso8859-6, iso8859-7, cp424, iso8859-8, cp856
|
||||
# and cp857
|
||||
b'\xae\xd5'
|
||||
# undecodable from UTF-8 (UNIX and Mac OS X)
|
||||
b'\xed\xb2\x80', b'\xed\xb4\x80',
|
||||
# undecodable from shift_jis, cp869, cp874, cp932, cp1250, cp1251, cp1252,
|
||||
# cp1253, cp1254, cp1255, cp1257, cp1258
|
||||
b'\x81\x98',
|
||||
):
|
||||
try:
|
||||
name.decode(TESTFN_ENCODING)
|
||||
except UnicodeDecodeError:
|
||||
TESTFN_UNDECODABLE = os.fsencode(TESTFN) + name
|
||||
break
|
||||
|
||||
if FS_NONASCII:
|
||||
TESTFN_NONASCII = TESTFN + '-' + FS_NONASCII
|
||||
@@ -971,6 +1008,10 @@ SAVEDCWD = os.getcwd()
|
||||
# useful for PGO
|
||||
PGO = False
|
||||
|
||||
# Set by libregrtest/main.py if we are running the extended (time consuming)
|
||||
# PGO task. If this is True, PGO is also True.
|
||||
PGO_EXTENDED = False
|
||||
|
||||
@contextlib.contextmanager
|
||||
def temp_dir(path=None, quiet=False):
|
||||
"""Return a context manager that creates a temporary directory.
|
||||
@@ -1025,7 +1066,7 @@ def change_cwd(path, quiet=False):
|
||||
"""
|
||||
saved_dir = os.getcwd()
|
||||
try:
|
||||
os.chdir(path)
|
||||
os.chdir(os.path.realpath(path))
|
||||
except OSError as exc:
|
||||
if not quiet:
|
||||
raise
|
||||
@@ -1490,6 +1531,11 @@ def get_socket_conn_refused_errs():
|
||||
# bpo-31910: socket.create_connection() fails randomly
|
||||
# with EADDRNOTAVAIL on Travis CI
|
||||
errors.append(errno.EADDRNOTAVAIL)
|
||||
if hasattr(errno, 'EHOSTUNREACH'):
|
||||
# bpo-37583: The destination host cannot be reached
|
||||
errors.append(errno.EHOSTUNREACH)
|
||||
if not IPV6_ENABLED:
|
||||
errors.append(errno.EAFNOSUPPORT)
|
||||
return errors
|
||||
|
||||
|
||||
@@ -2500,6 +2546,105 @@ def skip_unless_symlink(test):
|
||||
msg = "Requires functional symlink implementation"
|
||||
return test if ok else unittest.skip(msg)(test)
|
||||
|
||||
_buggy_ucrt = None
|
||||
def skip_if_buggy_ucrt_strfptime(test):
|
||||
"""
|
||||
Skip decorator for tests that use buggy strptime/strftime
|
||||
|
||||
If the UCRT bugs are present time.localtime().tm_zone will be
|
||||
an empty string, otherwise we assume the UCRT bugs are fixed
|
||||
|
||||
See bpo-37552 [Windows] strptime/strftime return invalid
|
||||
results with UCRT version 17763.615
|
||||
"""
|
||||
global _buggy_ucrt
|
||||
if _buggy_ucrt is None:
|
||||
if(sys.platform == 'win32' and
|
||||
locale.getdefaultlocale()[1] == 'cp65001' and
|
||||
time.localtime().tm_zone == ''):
|
||||
_buggy_ucrt = True
|
||||
else:
|
||||
_buggy_ucrt = False
|
||||
return unittest.skip("buggy MSVC UCRT strptime/strftime")(test) if _buggy_ucrt else test
|
||||
|
||||
class PythonSymlink:
|
||||
"""Creates a symlink for the current Python executable"""
|
||||
def __init__(self, link=None):
|
||||
self.link = link or os.path.abspath(TESTFN)
|
||||
self._linked = []
|
||||
self.real = os.path.realpath(sys.executable)
|
||||
self._also_link = []
|
||||
|
||||
self._env = None
|
||||
|
||||
self._platform_specific()
|
||||
|
||||
def _platform_specific(self):
|
||||
pass
|
||||
|
||||
if sys.platform == "win32":
|
||||
def _platform_specific(self):
|
||||
import _winapi
|
||||
|
||||
if os.path.lexists(self.real) and not os.path.exists(self.real):
|
||||
# App symlink appears to not exist, but we want the
|
||||
# real executable here anyway
|
||||
self.real = _winapi.GetModuleFileName(0)
|
||||
|
||||
dll = _winapi.GetModuleFileName(sys.dllhandle)
|
||||
src_dir = os.path.dirname(dll)
|
||||
dest_dir = os.path.dirname(self.link)
|
||||
self._also_link.append((
|
||||
dll,
|
||||
os.path.join(dest_dir, os.path.basename(dll))
|
||||
))
|
||||
for runtime in glob.glob(os.path.join(src_dir, "vcruntime*.dll")):
|
||||
self._also_link.append((
|
||||
runtime,
|
||||
os.path.join(dest_dir, os.path.basename(runtime))
|
||||
))
|
||||
|
||||
self._env = {k.upper(): os.getenv(k) for k in os.environ}
|
||||
self._env["PYTHONHOME"] = os.path.dirname(self.real)
|
||||
if sysconfig.is_python_build(True):
|
||||
self._env["PYTHONPATH"] = os.path.dirname(os.__file__)
|
||||
|
||||
def __enter__(self):
|
||||
os.symlink(self.real, self.link)
|
||||
self._linked.append(self.link)
|
||||
for real, link in self._also_link:
|
||||
os.symlink(real, link)
|
||||
self._linked.append(link)
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, exc_tb):
|
||||
for link in self._linked:
|
||||
try:
|
||||
os.remove(link)
|
||||
except IOError as ex:
|
||||
if verbose:
|
||||
print("failed to clean up {}: {}".format(link, ex))
|
||||
|
||||
def _call(self, python, args, env, returncode):
|
||||
cmd = [python, *args]
|
||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE, env=env)
|
||||
r = p.communicate()
|
||||
if p.returncode != returncode:
|
||||
if verbose:
|
||||
print(repr(r[0]))
|
||||
print(repr(r[1]), file=sys.stderr)
|
||||
raise RuntimeError(
|
||||
'unexpected return code: {0} (0x{0:08X})'.format(p.returncode))
|
||||
return r
|
||||
|
||||
def call_real(self, *args, returncode=0):
|
||||
return self._call(self.real, args, None, returncode)
|
||||
|
||||
def call_link(self, *args, returncode=0):
|
||||
return self._call(self.link, args, self._env, returncode)
|
||||
|
||||
|
||||
_can_xattr = None
|
||||
def can_xattr():
|
||||
global _can_xattr
|
||||
@@ -2537,6 +2682,12 @@ def skip_unless_xattr(test):
|
||||
msg = "no non-broken extended attribute support"
|
||||
return test if ok else unittest.skip(msg)(test)
|
||||
|
||||
def skip_if_pgo_task(test):
|
||||
"""Skip decorator for tests not run in (non-extended) PGO task"""
|
||||
ok = not PGO or PGO_EXTENDED
|
||||
msg = "Not run for (non-extended) PGO task"
|
||||
return test if ok else unittest.skip(msg)(test)
|
||||
|
||||
_bind_nix_socket_error = None
|
||||
def skip_unless_bind_unix_socket(test):
|
||||
"""Decorator for tests requiring a functional bind() for unix sockets."""
|
||||
@@ -2877,7 +3028,7 @@ def fd_count():
|
||||
if sys.platform.startswith(('linux', 'freebsd')):
|
||||
try:
|
||||
names = os.listdir("/proc/self/fd")
|
||||
# Substract one because listdir() opens internally a file
|
||||
# Subtract one because listdir() internally opens a file
|
||||
# descriptor to list the content of the /proc/self/fd/ directory.
|
||||
return len(names) - 1
|
||||
except FileNotFoundError:
|
||||
@@ -2992,6 +3143,41 @@ class FakePath:
|
||||
return self.path
|
||||
|
||||
|
||||
class _ALWAYS_EQ:
|
||||
"""
|
||||
Object that is equal to anything.
|
||||
"""
|
||||
def __eq__(self, other):
|
||||
return True
|
||||
def __ne__(self, other):
|
||||
return False
|
||||
|
||||
ALWAYS_EQ = _ALWAYS_EQ()
|
||||
|
||||
@functools.total_ordering
|
||||
class _LARGEST:
|
||||
"""
|
||||
Object that is greater than anything (except itself).
|
||||
"""
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, _LARGEST)
|
||||
def __lt__(self, other):
|
||||
return False
|
||||
|
||||
LARGEST = _LARGEST()
|
||||
|
||||
@functools.total_ordering
|
||||
class _SMALLEST:
|
||||
"""
|
||||
Object that is less than anything (except itself).
|
||||
"""
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, _SMALLEST)
|
||||
def __gt__(self, other):
|
||||
return False
|
||||
|
||||
SMALLEST = _SMALLEST()
|
||||
|
||||
def maybe_get_event_loop_policy():
|
||||
"""Return the global event loop policy if one is set, else return None."""
|
||||
return asyncio.events._event_loop_policy
|
||||
@@ -3036,3 +3222,104 @@ def collision_stats(nbins, nballs):
|
||||
collisions = k - occupied
|
||||
var = dn*(dn-1)*((dn-2)/dn)**k + meanempty * (1 - meanempty)
|
||||
return float(collisions), float(var.sqrt())
|
||||
|
||||
|
||||
class catch_unraisable_exception:
|
||||
"""
|
||||
Context manager catching unraisable exception using sys.unraisablehook.
|
||||
|
||||
Storing the exception value (cm.unraisable.exc_value) creates a reference
|
||||
cycle. The reference cycle is broken explicitly when the context manager
|
||||
exits.
|
||||
|
||||
Storing the object (cm.unraisable.object) can resurrect it if it is set to
|
||||
an object which is being finalized. Exiting the context manager clears the
|
||||
stored object.
|
||||
|
||||
Usage:
|
||||
|
||||
with support.catch_unraisable_exception() as cm:
|
||||
# code creating an "unraisable exception"
|
||||
...
|
||||
|
||||
# check the unraisable exception: use cm.unraisable
|
||||
...
|
||||
|
||||
# cm.unraisable attribute no longer exists at this point
|
||||
# (to break a reference cycle)
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.unraisable = None
|
||||
self._old_hook = None
|
||||
|
||||
def _hook(self, unraisable):
|
||||
# Storing unraisable.object can resurrect an object which is being
|
||||
# finalized. Storing unraisable.exc_value creates a reference cycle.
|
||||
self.unraisable = unraisable
|
||||
|
||||
def __enter__(self):
|
||||
self._old_hook = sys.unraisablehook
|
||||
sys.unraisablehook = self._hook
|
||||
return self
|
||||
|
||||
def __exit__(self, *exc_info):
|
||||
sys.unraisablehook = self._old_hook
|
||||
del self.unraisable
|
||||
|
||||
|
||||
class catch_threading_exception:
|
||||
"""
|
||||
Context manager catching threading.Thread exception using
|
||||
threading.excepthook.
|
||||
|
||||
Attributes set when an exception is catched:
|
||||
|
||||
* exc_type
|
||||
* exc_value
|
||||
* exc_traceback
|
||||
* thread
|
||||
|
||||
See threading.excepthook() documentation for these attributes.
|
||||
|
||||
These attributes are deleted at the context manager exit.
|
||||
|
||||
Usage:
|
||||
|
||||
with support.catch_threading_exception() as cm:
|
||||
# code spawning a thread which raises an exception
|
||||
...
|
||||
|
||||
# check the thread exception, use cm attributes:
|
||||
# exc_type, exc_value, exc_traceback, thread
|
||||
...
|
||||
|
||||
# exc_type, exc_value, exc_traceback, thread attributes of cm no longer
|
||||
# exists at this point
|
||||
# (to avoid reference cycles)
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.exc_type = None
|
||||
self.exc_value = None
|
||||
self.exc_traceback = None
|
||||
self.thread = None
|
||||
self._old_hook = None
|
||||
|
||||
def _hook(self, args):
|
||||
self.exc_type = args.exc_type
|
||||
self.exc_value = args.exc_value
|
||||
self.exc_traceback = args.exc_traceback
|
||||
self.thread = args.thread
|
||||
|
||||
def __enter__(self):
|
||||
self._old_hook = threading.excepthook
|
||||
threading.excepthook = self._hook
|
||||
return self
|
||||
|
||||
def __exit__(self, *exc_info):
|
||||
threading.excepthook = self._old_hook
|
||||
del self.exc_type
|
||||
del self.exc_value
|
||||
del self.exc_traceback
|
||||
del self.thread
|
||||
@@ -59,7 +59,7 @@ class RegressionTestResult(unittest.TextTestResult):
|
||||
e.set('result', args.pop('result', 'completed'))
|
||||
if self.__start_time:
|
||||
# e.set('time', f'{time.perf_counter() - self.__start_time:0.6f}')
|
||||
e.set('time', f'{time.time() - self.__start_time}')
|
||||
e.set('time', f'{time.time() - self.__start_time:0.6f}')
|
||||
|
||||
if capture:
|
||||
if self._stdout_buffer is not None:
|
||||
|
||||
Reference in new issue
Block a user