# It's recommended to run this with `python3 -I not_impl_gen.py`, to make sure # that nothing in your global Python environment interferes with what's being # extracted here. import pkgutil import os import sys import warnings sys.path = list( filter( lambda path: "site-packages" not in path and "dist-packages" not in path, sys.path, ) ) def attr_is_not_inherited(type_, attr): """ returns True if type_'s attr is not inherited from any of its base classes """ bases = type_.__mro__[1:] return getattr(type_, attr) not in (getattr(base, attr, None) for base in bases) def gen_methods(header, footer, output): types = [ bool, bytearray, bytes, complex, dict, enumerate, filter, float, frozenset, int, list, map, memoryview, range, set, slice, str, super, tuple, object, zip, classmethod, staticmethod, property, Exception, BaseException, ] objects = [(t.__name__, t.__name__) for t in types] objects.extend([ ('NoneType', 'type(None)'), ]) iters = [ ('bytearray_iterator', 'type(bytearray().__iter__())'), ('bytes_iterator', 'type(bytes().__iter__())'), ('dict_keyiterator', 'type(dict().__iter__())'), ('dict_valueiterator', 'type(dict().values().__iter__())'), ('dict_itemiterator', 'type(dict().items().__iter__())'), ('dict_values', 'type(dict().values())'), ('dict_items', 'type(dict().items())'), ('set_iterator', 'type(set().__iter__())'), ('list_iterator', 'type(list().__iter__())'), ('range_iterator', 'type(range(0).__iter__())'), ('str_iterator', 'type(str().__iter__())'), ('tuple_iterator', 'type(tuple().__iter__())'), ] output.write(header.read()) output.write("expected_methods = {\n") for name, typ_code in objects + iters: typ = eval(typ_code) output.write(f" '{name}': ({typ_code}, [\n") output.write( "\n".join( f" {attr!r}," for attr in dir(typ) if attr_is_not_inherited(typ, attr) ) ) output.write("\n ])," + ("\n" if objects[-1] == typ else "\n\n")) output.write("}\n\n") output.write(footer.read()) def get_module_methods(name): with warnings.catch_warnings(): # ignore warnings caused by importing deprecated modules warnings.filterwarnings("ignore", category=DeprecationWarning) try: return set(dir(__import__(name))) if name not in ("this", "antigravity") else None except ModuleNotFoundError: return None except Exception as e: print("!!! {} skipped because {}: {}".format(name, type(e).__name__, str(e))) def gen_modules(header, footer, output): output.write(header.read()) modules = dict( map( lambda mod: ( mod.name, # check name b/c modules listed have side effects on import, # e.g. printing something or opening a webpage get_module_methods(mod.name) ), pkgutil.iter_modules(), ) ) print( f""" cpymods = {modules!r} libdir = {os.path.abspath("../Lib/").encode('utf8')!r} """, file=output, ) output.write(footer.read()) gen_funcs = {"methods": gen_methods, "modules": gen_modules} for name, gen_func in gen_funcs.items(): gen_func( header=open(f"generator/not_impl_{name}_header.txt"), footer=open(f"generator/not_impl_{name}_footer.txt"), output=open(f"snippets/whats_left_{name}.py", "w"), )