| 
									
										
										
										
											2015-10-03 00:20:56 +02:00
										 |  |  | import errno | 
					
						
							| 
									
										
										
										
											2015-09-26 10:38:01 +02:00
										 |  |  | import os | 
					
						
							|  |  |  | import re | 
					
						
							|  |  |  | import sys | 
					
						
							|  |  |  | import warnings | 
					
						
							|  |  |  | from inspect import isabstract | 
					
						
							|  |  |  | from test import support | 
					
						
							| 
									
										
										
										
											2018-02-18 12:41:58 +00:00
										 |  |  | try: | 
					
						
							|  |  |  |     from _abc import _get_dump | 
					
						
							|  |  |  | except ImportError: | 
					
						
							|  |  |  |     def _get_dump(cls): | 
					
						
							|  |  |  |         # For legacy Python version | 
					
						
							|  |  |  |         return (cls._abc_registry, cls._abc_cache, | 
					
						
							|  |  |  |                 cls._abc_negative_cache, cls._abc_negative_cache_version) | 
					
						
							| 
									
										
										
										
											2015-09-26 10:38:01 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def dash_R(the_module, test, indirect_test, huntrleaks): | 
					
						
							|  |  |  |     """Run a test multiple times, looking for reference leaks.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Returns: | 
					
						
							|  |  |  |         False if the test didn't leak references; True if we detected refleaks. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     # This code is hackish and inelegant, but it seems to do the job. | 
					
						
							|  |  |  |     import copyreg | 
					
						
							|  |  |  |     import collections.abc | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if not hasattr(sys, 'gettotalrefcount'): | 
					
						
							|  |  |  |         raise Exception("Tracking reference leaks requires a debug build " | 
					
						
							|  |  |  |                         "of Python") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Save current values for dash_R_cleanup() to restore. | 
					
						
							|  |  |  |     fs = warnings.filters[:] | 
					
						
							|  |  |  |     ps = copyreg.dispatch_table.copy() | 
					
						
							|  |  |  |     pic = sys.path_importer_cache.copy() | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         import zipimport | 
					
						
							|  |  |  |     except ImportError: | 
					
						
							|  |  |  |         zdc = None # Run unmodified on platforms without zipimport support | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         zdc = zipimport._zip_directory_cache.copy() | 
					
						
							|  |  |  |     abcs = {} | 
					
						
							|  |  |  |     for abc in [getattr(collections.abc, a) for a in collections.abc.__all__]: | 
					
						
							|  |  |  |         if not isabstract(abc): | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         for obj in abc.__subclasses__() + [abc]: | 
					
						
							| 
									
										
										
										
											2018-02-18 12:41:58 +00:00
										 |  |  |             abcs[obj] = _get_dump(obj)[0] | 
					
						
							| 
									
										
										
										
											2015-09-26 10:38:01 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-01 13:05:27 +02:00
										 |  |  |     # bpo-31217: Integer pool to get a single integer object for the same | 
					
						
							|  |  |  |     # value. The pool is used to prevent false alarm when checking for memory | 
					
						
							|  |  |  |     # block leaks. Fill the pool with values in -1000..1000 which are the most | 
					
						
							|  |  |  |     # common (reference, memory block, file descriptor) differences. | 
					
						
							|  |  |  |     int_pool = {value: value for value in range(-1000, 1000)} | 
					
						
							|  |  |  |     def get_pooled_int(value): | 
					
						
							|  |  |  |         return int_pool.setdefault(value, value) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-26 10:38:01 +02:00
										 |  |  |     nwarmup, ntracked, fname = huntrleaks | 
					
						
							|  |  |  |     fname = os.path.join(support.SAVEDCWD, fname) | 
					
						
							|  |  |  |     repcount = nwarmup + ntracked | 
					
						
							|  |  |  |     rc_deltas = [0] * repcount | 
					
						
							|  |  |  |     alloc_deltas = [0] * repcount | 
					
						
							| 
									
										
										
										
											2015-10-03 00:20:56 +02:00
										 |  |  |     fd_deltas = [0] * repcount | 
					
						
							| 
									
										
										
										
											2015-09-26 10:38:01 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     print("beginning", repcount, "repetitions", file=sys.stderr) | 
					
						
							| 
									
										
										
										
											2015-09-30 00:48:27 +02:00
										 |  |  |     print(("1234567890"*(repcount//10 + 1))[:repcount], file=sys.stderr, | 
					
						
							|  |  |  |           flush=True) | 
					
						
							| 
									
										
										
										
											2015-09-30 13:51:17 +02:00
										 |  |  |     # initialize variables to make pyflakes quiet | 
					
						
							| 
									
										
										
										
											2015-10-03 00:20:56 +02:00
										 |  |  |     rc_before = alloc_before = fd_before = 0 | 
					
						
							| 
									
										
										
										
											2015-09-26 10:38:01 +02:00
										 |  |  |     for i in range(repcount): | 
					
						
							|  |  |  |         indirect_test() | 
					
						
							| 
									
										
										
										
											2015-10-03 00:20:56 +02:00
										 |  |  |         alloc_after, rc_after, fd_after = dash_R_cleanup(fs, ps, pic, zdc, | 
					
						
							|  |  |  |                                                          abcs) | 
					
						
							| 
									
										
										
										
											2017-02-08 13:06:08 +01:00
										 |  |  |         print('.', end='', file=sys.stderr, flush=True) | 
					
						
							| 
									
										
										
										
											2015-09-26 10:38:01 +02:00
										 |  |  |         if i >= nwarmup: | 
					
						
							| 
									
										
										
										
											2017-09-01 13:05:27 +02:00
										 |  |  |             rc_deltas[i] = get_pooled_int(rc_after - rc_before) | 
					
						
							|  |  |  |             alloc_deltas[i] = get_pooled_int(alloc_after - alloc_before) | 
					
						
							|  |  |  |             fd_deltas[i] = get_pooled_int(fd_after - fd_before) | 
					
						
							| 
									
										
										
										
											2015-10-03 00:20:56 +02:00
										 |  |  |         alloc_before = alloc_after | 
					
						
							|  |  |  |         rc_before = rc_after | 
					
						
							|  |  |  |         fd_before = fd_after | 
					
						
							| 
									
										
										
										
											2015-09-26 10:38:01 +02:00
										 |  |  |     print(file=sys.stderr) | 
					
						
							| 
									
										
										
										
											2017-06-27 02:02:04 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-26 10:38:01 +02:00
										 |  |  |     # These checkers return False on success, True on failure | 
					
						
							|  |  |  |     def check_rc_deltas(deltas): | 
					
						
							| 
									
										
										
										
											2017-06-29 10:32:49 +02:00
										 |  |  |         # Checker for reference counters and memomry blocks. | 
					
						
							|  |  |  |         # | 
					
						
							| 
									
										
										
										
											2017-06-27 02:02:04 +02:00
										 |  |  |         # bpo-30776: Try to ignore false positives: | 
					
						
							|  |  |  |         # | 
					
						
							|  |  |  |         #   [3, 0, 0] | 
					
						
							|  |  |  |         #   [0, 1, 0] | 
					
						
							|  |  |  |         #   [8, -8, 1] | 
					
						
							|  |  |  |         # | 
					
						
							|  |  |  |         # Expected leaks: | 
					
						
							|  |  |  |         # | 
					
						
							|  |  |  |         #   [5, 5, 6] | 
					
						
							|  |  |  |         #   [10, 1, 1] | 
					
						
							|  |  |  |         return all(delta >= 1 for delta in deltas) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def check_fd_deltas(deltas): | 
					
						
							|  |  |  |         return any(deltas) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-26 10:38:01 +02:00
										 |  |  |     failed = False | 
					
						
							|  |  |  |     for deltas, item_name, checker in [ | 
					
						
							|  |  |  |         (rc_deltas, 'references', check_rc_deltas), | 
					
						
							| 
									
										
										
										
											2017-06-29 10:32:49 +02:00
										 |  |  |         (alloc_deltas, 'memory blocks', check_rc_deltas), | 
					
						
							| 
									
										
										
										
											2017-06-27 02:02:04 +02:00
										 |  |  |         (fd_deltas, 'file descriptors', check_fd_deltas) | 
					
						
							|  |  |  |     ]: | 
					
						
							|  |  |  |         # ignore warmup runs | 
					
						
							|  |  |  |         deltas = deltas[nwarmup:] | 
					
						
							| 
									
										
										
										
											2015-09-26 10:38:01 +02:00
										 |  |  |         if checker(deltas): | 
					
						
							|  |  |  |             msg = '%s leaked %s %s, sum=%s' % ( | 
					
						
							| 
									
										
										
										
											2017-06-27 02:02:04 +02:00
										 |  |  |                 test, deltas, item_name, sum(deltas)) | 
					
						
							| 
									
										
										
										
											2015-09-30 00:48:27 +02:00
										 |  |  |             print(msg, file=sys.stderr, flush=True) | 
					
						
							| 
									
										
										
										
											2015-09-26 10:38:01 +02:00
										 |  |  |             with open(fname, "a") as refrep: | 
					
						
							|  |  |  |                 print(msg, file=refrep) | 
					
						
							|  |  |  |                 refrep.flush() | 
					
						
							|  |  |  |             failed = True | 
					
						
							|  |  |  |     return failed | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def dash_R_cleanup(fs, ps, pic, zdc, abcs): | 
					
						
							|  |  |  |     import gc, copyreg | 
					
						
							| 
									
										
										
										
											2016-11-11 11:46:44 +02:00
										 |  |  |     import collections.abc | 
					
						
							| 
									
										
										
										
											2015-09-26 10:38:01 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Restore some original values. | 
					
						
							|  |  |  |     warnings.filters[:] = fs | 
					
						
							|  |  |  |     copyreg.dispatch_table.clear() | 
					
						
							|  |  |  |     copyreg.dispatch_table.update(ps) | 
					
						
							|  |  |  |     sys.path_importer_cache.clear() | 
					
						
							|  |  |  |     sys.path_importer_cache.update(pic) | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         import zipimport | 
					
						
							|  |  |  |     except ImportError: | 
					
						
							|  |  |  |         pass # Run unmodified on platforms without zipimport support | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         zipimport._zip_directory_cache.clear() | 
					
						
							|  |  |  |         zipimport._zip_directory_cache.update(zdc) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # clear type cache | 
					
						
							|  |  |  |     sys._clear_type_cache() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Clear ABC registries, restoring previously saved ABC registries. | 
					
						
							| 
									
										
										
										
											2017-03-05 19:15:20 +01:00
										 |  |  |     abs_classes = [getattr(collections.abc, a) for a in collections.abc.__all__] | 
					
						
							|  |  |  |     abs_classes = filter(isabstract, abs_classes) | 
					
						
							|  |  |  |     for abc in abs_classes: | 
					
						
							| 
									
										
										
										
											2015-09-26 10:38:01 +02:00
										 |  |  |         for obj in abc.__subclasses__() + [abc]: | 
					
						
							| 
									
										
										
										
											2018-02-18 12:41:58 +00:00
										 |  |  |             for ref in abcs.get(obj, set()): | 
					
						
							|  |  |  |                 if ref() is not None: | 
					
						
							|  |  |  |                     obj.register(ref()) | 
					
						
							|  |  |  |             obj._abc_caches_clear() | 
					
						
							| 
									
										
										
										
											2015-09-26 10:38:01 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-11 11:46:44 +02:00
										 |  |  |     clear_caches() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Collect cyclic trash and read memory statistics immediately after. | 
					
						
							|  |  |  |     func1 = sys.getallocatedblocks | 
					
						
							|  |  |  |     func2 = sys.gettotalrefcount | 
					
						
							|  |  |  |     gc.collect() | 
					
						
							| 
									
										
										
										
											2017-07-22 13:22:54 +02:00
										 |  |  |     return func1(), func2(), support.fd_count() | 
					
						
							| 
									
										
										
										
											2016-11-11 11:46:44 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def clear_caches(): | 
					
						
							|  |  |  |     import gc | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Clear the warnings registry, so they can be displayed again | 
					
						
							|  |  |  |     for mod in sys.modules.values(): | 
					
						
							|  |  |  |         if hasattr(mod, '__warningregistry__'): | 
					
						
							|  |  |  |             del mod.__warningregistry__ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-26 10:38:01 +02:00
										 |  |  |     # Flush standard output, so that buffered data is sent to the OS and | 
					
						
							|  |  |  |     # associated Python objects are reclaimed. | 
					
						
							|  |  |  |     for stream in (sys.stdout, sys.stderr, sys.__stdout__, sys.__stderr__): | 
					
						
							|  |  |  |         if stream is not None: | 
					
						
							|  |  |  |             stream.flush() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Clear assorted module caches. | 
					
						
							| 
									
										
										
										
											2016-11-11 11:46:44 +02:00
										 |  |  |     # Don't worry about resetting the cache if the module is not loaded | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         distutils_dir_util = sys.modules['distutils.dir_util'] | 
					
						
							|  |  |  |     except KeyError: | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         distutils_dir_util._path_created.clear() | 
					
						
							| 
									
										
										
										
											2015-09-26 10:38:01 +02:00
										 |  |  |     re.purge() | 
					
						
							| 
									
										
										
										
											2016-11-11 11:46:44 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-26 10:38:01 +02:00
										 |  |  |     try: | 
					
						
							| 
									
										
										
										
											2016-11-11 11:46:44 +02:00
										 |  |  |         _strptime = sys.modules['_strptime'] | 
					
						
							|  |  |  |     except KeyError: | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         _strptime._regex_cache.clear() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         urllib_parse = sys.modules['urllib.parse'] | 
					
						
							|  |  |  |     except KeyError: | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         urllib_parse.clear_cache() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         urllib_request = sys.modules['urllib.request'] | 
					
						
							|  |  |  |     except KeyError: | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         urllib_request.urlcleanup() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         linecache = sys.modules['linecache'] | 
					
						
							|  |  |  |     except KeyError: | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         linecache.clearcache() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         mimetypes = sys.modules['mimetypes'] | 
					
						
							|  |  |  |     except KeyError: | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         mimetypes._default_mime_types() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         filecmp = sys.modules['filecmp'] | 
					
						
							|  |  |  |     except KeyError: | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         filecmp._cache.clear() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         struct = sys.modules['struct'] | 
					
						
							|  |  |  |     except KeyError: | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         struct._clearcache() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         doctest = sys.modules['doctest'] | 
					
						
							|  |  |  |     except KeyError: | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         doctest.master = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         ctypes = sys.modules['ctypes'] | 
					
						
							|  |  |  |     except KeyError: | 
					
						
							| 
									
										
										
										
											2015-09-26 10:38:01 +02:00
										 |  |  |         pass | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         ctypes._reset_cache() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-09 23:51:54 +02:00
										 |  |  |     try: | 
					
						
							|  |  |  |         typing = sys.modules['typing'] | 
					
						
							|  |  |  |     except KeyError: | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         for f in typing._cleanups: | 
					
						
							|  |  |  |             f() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-26 10:38:01 +02:00
										 |  |  |     gc.collect() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def warm_caches(): | 
					
						
							|  |  |  |     # char cache | 
					
						
							|  |  |  |     s = bytes(range(256)) | 
					
						
							|  |  |  |     for i in range(256): | 
					
						
							|  |  |  |         s[i:i+1] | 
					
						
							|  |  |  |     # unicode cache | 
					
						
							| 
									
										
										
										
											2015-09-30 13:51:17 +02:00
										 |  |  |     [chr(i) for i in range(256)] | 
					
						
							| 
									
										
										
										
											2015-09-26 10:38:01 +02:00
										 |  |  |     # int cache | 
					
						
							| 
									
										
										
										
											2015-09-30 13:51:17 +02:00
										 |  |  |     list(range(-5, 257)) |