|
182 | 182 | import warnings |
183 | 183 | from inspect import isabstract |
184 | 184 |
|
| 185 | +try: |
| 186 | + import threading |
| 187 | +except ImportError: |
| 188 | + threading = None |
| 189 | +try: |
| 190 | + import multiprocessing.process |
| 191 | +except ImportError: |
| 192 | + multiprocessing = None |
| 193 | + |
185 | 194 |
|
186 | 195 | # Some times __path__ and __file__ are not absolute (e.g. while running from |
187 | 196 | # Lib/) and, if we change the CWD to run the tests in a temporary dir, some |
@@ -930,7 +939,8 @@ def __init__(self, testname, verbose=0, quiet=False): |
930 | 939 | 'os.environ', 'sys.path', 'sys.path_hooks', '__import__', |
931 | 940 | 'warnings.filters', 'asyncore.socket_map', |
932 | 941 | 'logging._handlers', 'logging._handlerList', 'sys.gettrace', |
933 | | - 'sys.warnoptions') |
| 942 | + 'sys.warnoptions', 'threading._dangling', |
| 943 | + 'multiprocessing.process._dangling') |
934 | 944 |
|
935 | 945 | def get_sys_argv(self): |
936 | 946 | return id(sys.argv), sys.argv, sys.argv[:] |
@@ -1023,6 +1033,31 @@ def restore_sys_warnoptions(self, saved_options): |
1023 | 1033 | sys.warnoptions = saved_options[1] |
1024 | 1034 | sys.warnoptions[:] = saved_options[2] |
1025 | 1035 |
|
| 1036 | + # Controlling dangling references to Thread objects can make it easier |
| 1037 | + # to track reference leaks. |
| 1038 | + def get_threading__dangling(self): |
| 1039 | + if not threading: |
| 1040 | + return None |
| 1041 | + # This copies the weakrefs without making any strong reference |
| 1042 | + return threading._dangling.copy() |
| 1043 | + def restore_threading__dangling(self, saved): |
| 1044 | + if not threading: |
| 1045 | + return |
| 1046 | + threading._dangling.clear() |
| 1047 | + threading._dangling.update(saved) |
| 1048 | + |
| 1049 | + # Same for Process objects |
| 1050 | + def get_multiprocessing_process__dangling(self): |
| 1051 | + if not multiprocessing: |
| 1052 | + return None |
| 1053 | + # This copies the weakrefs without making any strong reference |
| 1054 | + return multiprocessing.process._dangling.copy() |
| 1055 | + def restore_multiprocessing_process__dangling(self, saved): |
| 1056 | + if not multiprocessing: |
| 1057 | + return |
| 1058 | + multiprocessing.process._dangling.clear() |
| 1059 | + multiprocessing.process._dangling.update(saved) |
| 1060 | + |
1026 | 1061 | def resource_info(self): |
1027 | 1062 | for name in self.resources: |
1028 | 1063 | method_suffix = name.replace('.', '_') |
|
0 commit comments