1import math
2import os.path
3import sys
4import textwrap
5from test import support
6
7
8def format_duration(seconds):
9    ms = math.ceil(seconds * 1e3)
10    seconds, ms = divmod(ms, 1000)
11    minutes, seconds = divmod(seconds, 60)
12    hours, minutes = divmod(minutes, 60)
13
14    parts = []
15    if hours:
16        parts.append('%s hour' % hours)
17    if minutes:
18        parts.append('%s min' % minutes)
19    if seconds:
20        if parts:
21            # 2 min 1 sec
22            parts.append('%s sec' % seconds)
23        else:
24            # 1.0 sec
25            parts.append('%.1f sec' % (seconds + ms / 1000))
26    if not parts:
27        return '%s ms' % ms
28
29    parts = parts[:2]
30    return ' '.join(parts)
31
32
33def removepy(names):
34    if not names:
35        return
36    for idx, name in enumerate(names):
37        basename, ext = os.path.splitext(name)
38        if ext == '.py':
39            names[idx] = basename
40
41
42def count(n, word):
43    if n == 1:
44        return "%d %s" % (n, word)
45    else:
46        return "%d %ss" % (n, word)
47
48
49def printlist(x, width=70, indent=4, file=None):
50    """Print the elements of iterable x to stdout.
51
52    Optional arg width (default 70) is the maximum line length.
53    Optional arg indent (default 4) is the number of blanks with which to
54    begin each line.
55    """
56
57    blanks = ' ' * indent
58    # Print the sorted list: 'x' may be a '--random' list or a set()
59    print(textwrap.fill(' '.join(str(elt) for elt in sorted(x)), width,
60                        initial_indent=blanks, subsequent_indent=blanks),
61          file=file)
62
63
64def print_warning(msg):
65    support.print_warning(msg)
66
67
68orig_unraisablehook = None
69
70
71def regrtest_unraisable_hook(unraisable):
72    global orig_unraisablehook
73    support.environment_altered = True
74    support.print_warning("Unraisable exception")
75    old_stderr = sys.stderr
76    try:
77        support.flush_std_streams()
78        sys.stderr = support.print_warning.orig_stderr
79        orig_unraisablehook(unraisable)
80        sys.stderr.flush()
81    finally:
82        sys.stderr = old_stderr
83
84
85def setup_unraisable_hook():
86    global orig_unraisablehook
87    orig_unraisablehook = sys.unraisablehook
88    sys.unraisablehook = regrtest_unraisable_hook
89
90
91orig_threading_excepthook = None
92
93
94def regrtest_threading_excepthook(args):
95    global orig_threading_excepthook
96    support.environment_altered = True
97    support.print_warning(f"Uncaught thread exception: {args.exc_type.__name__}")
98    old_stderr = sys.stderr
99    try:
100        support.flush_std_streams()
101        sys.stderr = support.print_warning.orig_stderr
102        orig_threading_excepthook(args)
103        sys.stderr.flush()
104    finally:
105        sys.stderr = old_stderr
106
107
108def setup_threading_excepthook():
109    global orig_threading_excepthook
110    import threading
111    orig_threading_excepthook = threading.excepthook
112    threading.excepthook = regrtest_threading_excepthook
113
114
115def clear_caches():
116    # Clear the warnings registry, so they can be displayed again
117    for mod in sys.modules.values():
118        if hasattr(mod, '__warningregistry__'):
119            del mod.__warningregistry__
120
121    # Flush standard output, so that buffered data is sent to the OS and
122    # associated Python objects are reclaimed.
123    for stream in (sys.stdout, sys.stderr, sys.__stdout__, sys.__stderr__):
124        if stream is not None:
125            stream.flush()
126
127    # Clear assorted module caches.
128    # Don't worry about resetting the cache if the module is not loaded
129    try:
130        distutils_dir_util = sys.modules['distutils.dir_util']
131    except KeyError:
132        pass
133    else:
134        distutils_dir_util._path_created.clear()
135
136    try:
137        re = sys.modules['re']
138    except KeyError:
139        pass
140    else:
141        re.purge()
142
143    try:
144        _strptime = sys.modules['_strptime']
145    except KeyError:
146        pass
147    else:
148        _strptime._regex_cache.clear()
149
150    try:
151        urllib_parse = sys.modules['urllib.parse']
152    except KeyError:
153        pass
154    else:
155        urllib_parse.clear_cache()
156
157    try:
158        urllib_request = sys.modules['urllib.request']
159    except KeyError:
160        pass
161    else:
162        urllib_request.urlcleanup()
163
164    try:
165        linecache = sys.modules['linecache']
166    except KeyError:
167        pass
168    else:
169        linecache.clearcache()
170
171    try:
172        mimetypes = sys.modules['mimetypes']
173    except KeyError:
174        pass
175    else:
176        mimetypes._default_mime_types()
177
178    try:
179        filecmp = sys.modules['filecmp']
180    except KeyError:
181        pass
182    else:
183        filecmp._cache.clear()
184
185    try:
186        struct = sys.modules['struct']
187    except KeyError:
188        pass
189    else:
190        struct._clearcache()
191
192    try:
193        doctest = sys.modules['doctest']
194    except KeyError:
195        pass
196    else:
197        doctest.master = None
198
199    try:
200        ctypes = sys.modules['ctypes']
201    except KeyError:
202        pass
203    else:
204        ctypes._reset_cache()
205
206    try:
207        typing = sys.modules['typing']
208    except KeyError:
209        pass
210    else:
211        for f in typing._cleanups:
212            f()
213