|
| 1 | +#!/usr/bin/env python |
| 2 | + |
| 3 | +# Author: Leonardo Gama (@leogama) |
| 4 | +# Copyright (c) 2022 The Uncertainty Quantification Foundation. |
| 5 | +# License: 3-clause BSD. The full license text is available at: |
| 6 | +# - https://github.com/uqfoundation/dill/blob/master/LICENSE |
| 7 | + |
| 8 | +import io |
| 9 | +import itertools |
| 10 | +import logging |
| 11 | +import multiprocessing |
| 12 | +import os |
| 13 | +import sys |
| 14 | +import warnings |
| 15 | + |
| 16 | +import dill |
| 17 | + |
| 18 | +if not dill._dill.OLD310: |
| 19 | + STDLIB_MODULES = list(sys.stdlib_module_names) |
| 20 | + STDLIB_MODULES += [ |
| 21 | + # From https://docs.python.org/3.11/library/ |
| 22 | + 'collections.abc', 'concurrent.futures', 'curses.ascii', 'curses.panel', 'curses.textpad', |
| 23 | + 'html.entities', 'html.parser', 'http.client', 'http.cookiejar', 'http.cookies', 'http.server', |
| 24 | + 'importlib.metadata', 'importlib.resources', 'importlib.resources.abc', 'logging.config', |
| 25 | + 'logging.handlers', 'multiprocessing.shared_memory', 'os.path', 'test.support', |
| 26 | + 'test.support.bytecode_helper', 'test.support.import_helper', 'test.support.os_helper', |
| 27 | + 'test.support.script_helper', 'test.support.socket_helper', 'test.support.threading_helper', |
| 28 | + 'test.support.warnings_helper', 'tkinter.colorchooser', 'tkinter.dnd', 'tkinter.font', |
| 29 | + 'tkinter.messagebox', 'tkinter.scrolledtext', 'tkinter.tix', 'tkinter.ttk', 'unittest.mock', |
| 30 | + 'urllib.error', 'urllib.parse', 'urllib.request', 'urllib.response', 'urllib.robotparser', |
| 31 | + 'xml.dom', 'xml.dom.minidom', 'xml.dom.pulldom', 'xml.etree.ElementTree', 'xml.parsers.expat', |
| 32 | + 'xml.sax', 'xml.sax.handler', 'xml.sax.saxutils', 'xml.sax.xmlreader', 'xmlrpc.client', |
| 33 | + 'xmlrpc.server', |
| 34 | + ] |
| 35 | + STDLIB_MODULES.sort() |
| 36 | +else: |
| 37 | + STDLIB_MODULES = [ |
| 38 | + # From https://docs.python.org/3.9/library/ |
| 39 | + '__future__', '_thread', 'abc', 'aifc', 'argparse', 'array', 'ast', 'asynchat', 'asyncio', |
| 40 | + 'asyncore', 'atexit', 'audioop', 'base64', 'bdb', 'binascii', 'binhex', 'bisect', 'builtins', |
| 41 | + 'bz2', 'calendar', 'cgi', 'cgitb', 'chunk', 'cmath', 'cmd', 'code', 'codecs', 'codeop', |
| 42 | + 'collections', 'collections.abc', 'colorsys', 'compileall', 'concurrent', 'concurrent.futures', |
| 43 | + 'configparser', 'contextlib', 'contextvars', 'copy', 'copyreg', 'crypt', 'csv', 'ctypes', |
| 44 | + 'curses', 'curses.ascii', 'curses.panel', 'curses.textpad', 'dataclasses', 'datetime', 'dbm', |
| 45 | + 'decimal', 'difflib', 'dis', 'distutils', 'doctest', 'email', 'ensurepip', 'enum', 'errno', |
| 46 | + 'faulthandler', 'fcntl', 'filecmp', 'fileinput', 'fnmatch', 'formatter', 'fractions', 'ftplib', |
| 47 | + 'functools', 'gc', 'getopt', 'getpass', 'gettext', 'glob', 'graphlib', 'grp', 'gzip', 'hashlib', |
| 48 | + 'heapq', 'hmac', 'html', 'html.entities', 'html.parser', 'http', 'http.client', |
| 49 | + 'http.cookiejar', 'http.cookies', 'http.server', 'imaplib', 'imghdr', 'imp', 'importlib', |
| 50 | + 'importlib.metadata', 'inspect', 'io', 'ipaddress', 'itertools', 'json', 'keyword', 'linecache', |
| 51 | + 'locale', 'logging', 'logging.config', 'logging.handlers', 'lzma', 'mailbox', 'mailcap', |
| 52 | + 'marshal', 'math', 'mimetypes', 'mmap', 'modulefinder', 'msilib', 'msvcrt', 'multiprocessing', |
| 53 | + 'multiprocessing.shared_memory', 'netrc', 'nis', 'nntplib', 'numbers', 'operator', 'optparse', |
| 54 | + 'os', 'os.path', 'ossaudiodev', 'parser', 'pathlib', 'pdb', 'pickle', 'pickletools', 'pipes', |
| 55 | + 'pkgutil', 'platform', 'plistlib', 'poplib', 'posix', 'pprint', 'pty', 'pwd', 'py_compile', |
| 56 | + 'pyclbr', 'pydoc', 'queue', 'quopri', 'random', 're', 'readline', 'reprlib', 'resource', |
| 57 | + 'rlcompleter', 'runpy', 'sched', 'secrets', 'select', 'selectors', 'shelve', 'shlex', 'shutil', |
| 58 | + 'signal', 'site', 'site', 'smtpd', 'smtplib', 'sndhdr', 'socket', 'socketserver', 'spwd', |
| 59 | + 'sqlite3', 'ssl', 'stat', 'statistics', 'string', 'stringprep', 'struct', 'subprocess', 'sunau', |
| 60 | + 'symbol', 'symtable', 'sys', 'sysconfig', 'syslog', 'tabnanny', 'tarfile', 'telnetlib', |
| 61 | + 'tempfile', 'termios', 'test', 'test.support', 'test.support.bytecode_helper', |
| 62 | + 'test.support.script_helper', 'test.support.socket_helper', 'textwrap', 'threading', 'time', |
| 63 | + 'timeit', 'tkinter', 'tkinter.colorchooser', 'tkinter.dnd', 'tkinter.font', |
| 64 | + 'tkinter.messagebox', 'tkinter.scrolledtext', 'tkinter.tix', 'tkinter.ttk', 'token', 'tokenize', |
| 65 | + 'trace', 'traceback', 'tracemalloc', 'tty', 'turtle', 'types', 'typing', 'unicodedata', |
| 66 | + 'unittest', 'unittest.mock', 'urllib', 'urllib.error', 'urllib.parse', 'urllib.request', |
| 67 | + 'urllib.response', 'urllib.robotparser', 'uu', 'uuid', 'venv', 'warnings', 'wave', 'weakref', |
| 68 | + 'webbrowser', 'winreg', 'winsound', 'wsgiref', 'xdrlib', 'xml.dom', 'xml.dom.minidom', |
| 69 | + 'xml.dom.pulldom', 'xml.etree.ElementTree', 'xml.parsers.expat', 'xml.sax', 'xml.sax.handler', |
| 70 | + 'xml.sax.saxutils', 'xml.sax.xmlreader', 'xmlrpc', 'xmlrpc.client', 'xmlrpc.server', 'zipapp', |
| 71 | + 'zipfile', 'zipimport', 'zlib', 'zoneinfo', |
| 72 | +] |
| 73 | + |
| 74 | +def _dump_load_module(module_name, refonfail): |
| 75 | + try: |
| 76 | + __import__(module_name) |
| 77 | + except ImportError: |
| 78 | + return None, None |
| 79 | + success_load = None |
| 80 | + buf = io.BytesIO() |
| 81 | + try: |
| 82 | + dill.dump_module(buf, module_name, refonfail=refonfail) |
| 83 | + except Exception: |
| 84 | + print("F", end="") |
| 85 | + success_dump = False |
| 86 | + return success_dump, success_load |
| 87 | + print(":", end="") |
| 88 | + success_dump = True |
| 89 | + buf.seek(0) |
| 90 | + try: |
| 91 | + module = dill.load_module(buf) |
| 92 | + except Exception: |
| 93 | + success_load = False |
| 94 | + return success_dump, success_load |
| 95 | + success_load = True |
| 96 | + return success_dump, success_load |
| 97 | + |
| 98 | +def test_stdlib_modules(): |
| 99 | + modules = [x for x in STDLIB_MODULES if |
| 100 | + not x.startswith('_') |
| 101 | + and not x.startswith('test') |
| 102 | + and x not in ('antigravity', 'this')] |
| 103 | + |
| 104 | + |
| 105 | + print("\nTesting pickling and unpickling of Standard Library modules...") |
| 106 | + message = "Success rate (%s_module, refonfail=%s): %.1f%% [%d/%d]" |
| 107 | + with multiprocessing.Pool(maxtasksperchild=1) as pool: |
| 108 | + for refonfail in (False, True): |
| 109 | + args = zip(modules, itertools.repeat(refonfail)) |
| 110 | + result = pool.starmap(_dump_load_module, args, chunksize=1) |
| 111 | + dump_successes = sum(dumped for dumped, loaded in result if dumped is not None) |
| 112 | + load_successes = sum(loaded for dumped, loaded in result if loaded is not None) |
| 113 | + dump_failures = sum(not dumped for dumped, loaded in result if dumped is not None) |
| 114 | + load_failures = sum(not loaded for dumped, loaded in result if loaded is not None) |
| 115 | + dump_total = dump_successes + dump_failures |
| 116 | + load_total = load_successes + load_failures |
| 117 | + dump_percent = 100 * dump_successes / dump_total |
| 118 | + load_percent = 100 * load_successes / load_total |
| 119 | + print() |
| 120 | + print(message % ("dump", refonfail, dump_percent, dump_successes, dump_total)) |
| 121 | + print(message % ("load", refonfail, load_percent, load_successes, load_total)) |
| 122 | + if refonfail: |
| 123 | + failed_dump = [mod for mod, (dumped, _) in zip(modules, result) if dumped is False] |
| 124 | + failed_load = [mod for mod, (_, loaded) in zip(modules, result) if loaded is False] |
| 125 | + logging.info("dump_module() fails: %s", failed_dump) |
| 126 | + logging.info("load_module() fails: %s", failed_load) |
| 127 | + assert dump_percent > 95 |
| 128 | + |
| 129 | +if __name__ == '__main__': |
| 130 | + logging.basicConfig(level=os.environ.get('PYTHONLOGLEVEL', 'WARNING')) |
| 131 | + warnings.simplefilter('ignore') |
| 132 | + test_stdlib_modules() |
0 commit comments