1*55a74a43SLisandro Dalcinimport os 2*55a74a43SLisandro Dalcinimport sys 3*55a74a43SLisandro Dalcinimport inspect 4*55a74a43SLisandro Dalcinimport textwrap 5*55a74a43SLisandro Dalcin 6*55a74a43SLisandro Dalcin 7*55a74a43SLisandro Dalcindef is_cyfunction(obj): 8*55a74a43SLisandro Dalcin return type(obj).__name__ == 'cython_function_or_method' 9*55a74a43SLisandro Dalcin 10*55a74a43SLisandro Dalcin 11*55a74a43SLisandro Dalcindef is_function(obj): 12*55a74a43SLisandro Dalcin return ( 13*55a74a43SLisandro Dalcin inspect.isbuiltin(obj) 14*55a74a43SLisandro Dalcin or is_cyfunction(obj) 15*55a74a43SLisandro Dalcin or type(obj) is type(ord) 16*55a74a43SLisandro Dalcin ) 17*55a74a43SLisandro Dalcin 18*55a74a43SLisandro Dalcin 19*55a74a43SLisandro Dalcindef is_method(obj): 20*55a74a43SLisandro Dalcin return ( 21*55a74a43SLisandro Dalcin inspect.ismethoddescriptor(obj) 22*55a74a43SLisandro Dalcin or inspect.ismethod(obj) 23*55a74a43SLisandro Dalcin or is_cyfunction(obj) 24*55a74a43SLisandro Dalcin or type(obj) in ( 25*55a74a43SLisandro Dalcin type(str.index), 26*55a74a43SLisandro Dalcin type(str.__add__), 27*55a74a43SLisandro Dalcin type(str.__new__), 28*55a74a43SLisandro Dalcin ) 29*55a74a43SLisandro Dalcin ) 30*55a74a43SLisandro Dalcin 31*55a74a43SLisandro Dalcin 32*55a74a43SLisandro Dalcindef is_classmethod(obj): 33*55a74a43SLisandro Dalcin return ( 34*55a74a43SLisandro Dalcin inspect.isbuiltin(obj) 35*55a74a43SLisandro Dalcin or type(obj).__name__ in ( 36*55a74a43SLisandro Dalcin 'classmethod', 37*55a74a43SLisandro Dalcin 'classmethod_descriptor', 38*55a74a43SLisandro Dalcin ) 39*55a74a43SLisandro Dalcin ) 40*55a74a43SLisandro Dalcin 41*55a74a43SLisandro Dalcin 42*55a74a43SLisandro Dalcindef is_staticmethod(obj): 43*55a74a43SLisandro Dalcin return ( 44*55a74a43SLisandro Dalcin type(obj).__name__ in ( 45*55a74a43SLisandro Dalcin 'staticmethod', 46*55a74a43SLisandro Dalcin ) 47*55a74a43SLisandro Dalcin ) 48*55a74a43SLisandro Dalcin 49*55a74a43SLisandro Dalcindef is_constant(obj): 50*55a74a43SLisandro Dalcin return isinstance(obj, (int, float, str, dict)) 51*55a74a43SLisandro Dalcin 52*55a74a43SLisandro Dalcindef is_datadescr(obj): 53*55a74a43SLisandro Dalcin return inspect.isdatadescriptor(obj) and not hasattr(obj, 'fget') 54*55a74a43SLisandro Dalcin 55*55a74a43SLisandro Dalcin 56*55a74a43SLisandro Dalcindef is_property(obj): 57*55a74a43SLisandro Dalcin return inspect.isdatadescriptor(obj) and hasattr(obj, 'fget') 58*55a74a43SLisandro Dalcin 59*55a74a43SLisandro Dalcin 60*55a74a43SLisandro Dalcindef is_class(obj): 61*55a74a43SLisandro Dalcin return inspect.isclass(obj) or type(obj) is type(int) 62*55a74a43SLisandro Dalcin 63*55a74a43SLisandro Dalcin 64*55a74a43SLisandro Dalcinclass Lines(list): 65*55a74a43SLisandro Dalcin 66*55a74a43SLisandro Dalcin INDENT = " " * 4 67*55a74a43SLisandro Dalcin level = 0 68*55a74a43SLisandro Dalcin 69*55a74a43SLisandro Dalcin @property 70*55a74a43SLisandro Dalcin def add(self): 71*55a74a43SLisandro Dalcin return self 72*55a74a43SLisandro Dalcin 73*55a74a43SLisandro Dalcin @add.setter 74*55a74a43SLisandro Dalcin def add(self, lines): 75*55a74a43SLisandro Dalcin if lines is None: 76*55a74a43SLisandro Dalcin return 77*55a74a43SLisandro Dalcin if isinstance(lines, str): 78*55a74a43SLisandro Dalcin lines = textwrap.dedent(lines).strip().split('\n') 79*55a74a43SLisandro Dalcin indent = self.INDENT * self.level 80*55a74a43SLisandro Dalcin for line in lines: 81*55a74a43SLisandro Dalcin self.append(indent + line) 82*55a74a43SLisandro Dalcin 83*55a74a43SLisandro Dalcin 84*55a74a43SLisandro Dalcindef signature(obj): 85*55a74a43SLisandro Dalcin doc = obj.__doc__ 86*55a74a43SLisandro Dalcin doc = doc or f"{obj.__name__}: Any" # FIXME remove line 87*55a74a43SLisandro Dalcin sig = doc.partition('\n')[0].split('.', 1)[-1] 88*55a74a43SLisandro Dalcin return sig or None 89*55a74a43SLisandro Dalcin 90*55a74a43SLisandro Dalcin 91*55a74a43SLisandro Dalcindef docstring(obj): 92*55a74a43SLisandro Dalcin doc = obj.__doc__ 93*55a74a43SLisandro Dalcin doc = doc or '' # FIXME 94*55a74a43SLisandro Dalcin if is_class(obj): 95*55a74a43SLisandro Dalcin doc = doc.strip() 96*55a74a43SLisandro Dalcin else: 97*55a74a43SLisandro Dalcin doc = doc.partition('\n')[2] 98*55a74a43SLisandro Dalcin summary, _, docbody = doc.partition('\n') 99*55a74a43SLisandro Dalcin summary = summary.strip() 100*55a74a43SLisandro Dalcin docbody = textwrap.dedent(docbody).strip() 101*55a74a43SLisandro Dalcin if docbody: 102*55a74a43SLisandro Dalcin doc = f'"""{summary}\n\n{docbody}\n\n"""' 103*55a74a43SLisandro Dalcin else: 104*55a74a43SLisandro Dalcin doc = f'"""{summary}"""' 105*55a74a43SLisandro Dalcin doc = textwrap.indent(doc, Lines.INDENT) 106*55a74a43SLisandro Dalcin return doc 107*55a74a43SLisandro Dalcin 108*55a74a43SLisandro Dalcin 109*55a74a43SLisandro Dalcindef visit_data(constant): 110*55a74a43SLisandro Dalcin name, value = constant 111*55a74a43SLisandro Dalcin typename = type(value).__name__ 112*55a74a43SLisandro Dalcin kind = "Constant" if isinstance(value, int) else "Object" 113*55a74a43SLisandro Dalcin init = f"_def({typename}, '{name}')" 114*55a74a43SLisandro Dalcin doc = f"#: {kind} ``{name}`` of type :class:`{typename}`" 115*55a74a43SLisandro Dalcin return f"{name}: {typename} = {init} {doc}\n" 116*55a74a43SLisandro Dalcin 117*55a74a43SLisandro Dalcin 118*55a74a43SLisandro Dalcindef visit_function(function): 119*55a74a43SLisandro Dalcin sig = signature(function) 120*55a74a43SLisandro Dalcin doc = docstring(function) 121*55a74a43SLisandro Dalcin body = Lines.INDENT + "..." 122*55a74a43SLisandro Dalcin return f"def {sig}:\n{doc}\n{body}\n" 123*55a74a43SLisandro Dalcin 124*55a74a43SLisandro Dalcin 125*55a74a43SLisandro Dalcindef visit_method(method): 126*55a74a43SLisandro Dalcin sig = signature(method) 127*55a74a43SLisandro Dalcin doc = docstring(method) 128*55a74a43SLisandro Dalcin body = Lines.INDENT + "..." 129*55a74a43SLisandro Dalcin return f"def {sig}:\n{doc}\n{body}\n" 130*55a74a43SLisandro Dalcin 131*55a74a43SLisandro Dalcin 132*55a74a43SLisandro Dalcindef visit_datadescr(datadescr, name=None): 133*55a74a43SLisandro Dalcin sig = signature(datadescr) 134*55a74a43SLisandro Dalcin doc = docstring(datadescr) 135*55a74a43SLisandro Dalcin name = sig.partition(':')[0].strip() or datadescr.__name__ 136*55a74a43SLisandro Dalcin type = sig.partition(':')[2].strip() or 'Any' 137*55a74a43SLisandro Dalcin sig = f"{name}(self) -> {type}" 138*55a74a43SLisandro Dalcin body = Lines.INDENT + "..." 139*55a74a43SLisandro Dalcin return f"@property\ndef {sig}:\n{doc}\n{body}\n" 140*55a74a43SLisandro Dalcin 141*55a74a43SLisandro Dalcin 142*55a74a43SLisandro Dalcindef visit_property(prop, name=None): 143*55a74a43SLisandro Dalcin sig = signature(prop.fget) 144*55a74a43SLisandro Dalcin name = name or prop.fget.__name__ 145*55a74a43SLisandro Dalcin type = sig.rsplit('->', 1)[-1].strip() 146*55a74a43SLisandro Dalcin sig = f"{name}(self) -> {type}" 147*55a74a43SLisandro Dalcin doc = f'"""{prop.__doc__}"""' 148*55a74a43SLisandro Dalcin doc = textwrap.indent(doc, Lines.INDENT) 149*55a74a43SLisandro Dalcin body = Lines.INDENT + "..." 150*55a74a43SLisandro Dalcin return f"@property\ndef {sig}:\n{doc}\n{body}\n" 151*55a74a43SLisandro Dalcin 152*55a74a43SLisandro Dalcin 153*55a74a43SLisandro Dalcindef visit_constructor(cls, name='__init__', args=None): 154*55a74a43SLisandro Dalcin init = (name == '__init__') 155*55a74a43SLisandro Dalcin argname = cls.__mro__[-2].__name__.lower() 156*55a74a43SLisandro Dalcin argtype = cls.__name__ 157*55a74a43SLisandro Dalcin initarg = args or f"{argname}: Optional[{argtype}] = None" 158*55a74a43SLisandro Dalcin selfarg = 'self' if init else 'cls' 159*55a74a43SLisandro Dalcin rettype = 'None' if init else argtype 160*55a74a43SLisandro Dalcin arglist = f"{selfarg}, {initarg}" 161*55a74a43SLisandro Dalcin sig = f"{name}({arglist}) -> {rettype}" 162*55a74a43SLisandro Dalcin ret = '...' if init else 'return super().__new__(cls)' 163*55a74a43SLisandro Dalcin body = Lines.INDENT + ret 164*55a74a43SLisandro Dalcin return f"def {sig}:\n{body}" 165*55a74a43SLisandro Dalcin 166*55a74a43SLisandro Dalcin 167*55a74a43SLisandro Dalcindef visit_class(cls, outer=None, done=None): 168*55a74a43SLisandro Dalcin skip = { 169*55a74a43SLisandro Dalcin '__doc__', 170*55a74a43SLisandro Dalcin '__dict__', 171*55a74a43SLisandro Dalcin '__module__', 172*55a74a43SLisandro Dalcin '__weakref__', 173*55a74a43SLisandro Dalcin '__pyx_vtable__', 174*55a74a43SLisandro Dalcin '__lt__', 175*55a74a43SLisandro Dalcin '__le__', 176*55a74a43SLisandro Dalcin '__ge__', 177*55a74a43SLisandro Dalcin '__gt__', 178*55a74a43SLisandro Dalcin '__enum2str', # FIXME refactor implemetation 179*55a74a43SLisandro Dalcin '_traceback_', # FIXME maybe refactor? 180*55a74a43SLisandro Dalcin } 181*55a74a43SLisandro Dalcin special = { 182*55a74a43SLisandro Dalcin '__len__': "__len__(self) -> int", 183*55a74a43SLisandro Dalcin '__bool__': "__bool__(self) -> bool", 184*55a74a43SLisandro Dalcin '__hash__': "__hash__(self) -> int", 185*55a74a43SLisandro Dalcin '__int__': "__int__(self) -> int", 186*55a74a43SLisandro Dalcin '__index__': "__int__(self) -> int", 187*55a74a43SLisandro Dalcin '__str__': "__str__(self) -> str", 188*55a74a43SLisandro Dalcin '__repr__': "__repr__(self) -> str", 189*55a74a43SLisandro Dalcin '__eq__': "__eq__(self, other: object) -> bool", 190*55a74a43SLisandro Dalcin '__ne__': "__ne__(self, other: object) -> bool", 191*55a74a43SLisandro Dalcin } 192*55a74a43SLisandro Dalcin constructor = ( 193*55a74a43SLisandro Dalcin '__new__', 194*55a74a43SLisandro Dalcin '__init__', 195*55a74a43SLisandro Dalcin ) 196*55a74a43SLisandro Dalcin 197*55a74a43SLisandro Dalcin qualname = cls.__name__ 198*55a74a43SLisandro Dalcin cls_name = cls.__name__ 199*55a74a43SLisandro Dalcin if outer is not None and cls_name.startswith(outer): 200*55a74a43SLisandro Dalcin cls_name = cls_name[len(outer):] 201*55a74a43SLisandro Dalcin qualname = f"{outer}.{cls_name}" 202*55a74a43SLisandro Dalcin 203*55a74a43SLisandro Dalcin override = OVERRIDE.get(qualname, {}) 204*55a74a43SLisandro Dalcin done = set() if done is None else done 205*55a74a43SLisandro Dalcin lines = Lines() 206*55a74a43SLisandro Dalcin 207*55a74a43SLisandro Dalcin base = cls.__base__ 208*55a74a43SLisandro Dalcin if base is object: 209*55a74a43SLisandro Dalcin lines.add = f"class {cls_name}:" 210*55a74a43SLisandro Dalcin else: 211*55a74a43SLisandro Dalcin lines.add = f"class {cls_name}({base.__name__}):" 212*55a74a43SLisandro Dalcin lines.level += 1 213*55a74a43SLisandro Dalcin 214*55a74a43SLisandro Dalcin lines.add = docstring(cls) 215*55a74a43SLisandro Dalcin 216*55a74a43SLisandro Dalcin for name in ('__new__', '__init__', '__hash__'): 217*55a74a43SLisandro Dalcin if name in cls.__dict__: 218*55a74a43SLisandro Dalcin done.add(name) 219*55a74a43SLisandro Dalcin 220*55a74a43SLisandro Dalcin dct = cls.__dict__ 221*55a74a43SLisandro Dalcin keys = list(dct.keys()) 222*55a74a43SLisandro Dalcin 223*55a74a43SLisandro Dalcin def dunder(name): 224*55a74a43SLisandro Dalcin return name.startswith('__') and name.endswith('__') 225*55a74a43SLisandro Dalcin 226*55a74a43SLisandro Dalcin def members(seq): 227*55a74a43SLisandro Dalcin for name in seq: 228*55a74a43SLisandro Dalcin if name in skip: 229*55a74a43SLisandro Dalcin continue 230*55a74a43SLisandro Dalcin if name in done: 231*55a74a43SLisandro Dalcin continue 232*55a74a43SLisandro Dalcin if dunder(name): 233*55a74a43SLisandro Dalcin if name not in special and name not in override: 234*55a74a43SLisandro Dalcin done.add(name) 235*55a74a43SLisandro Dalcin continue 236*55a74a43SLisandro Dalcin yield name 237*55a74a43SLisandro Dalcin 238*55a74a43SLisandro Dalcin for name in members(keys): 239*55a74a43SLisandro Dalcin attr = getattr(cls, name) 240*55a74a43SLisandro Dalcin if is_class(attr): 241*55a74a43SLisandro Dalcin done.add(name) 242*55a74a43SLisandro Dalcin lines.add = visit_class(attr, outer=cls_name) 243*55a74a43SLisandro Dalcin continue 244*55a74a43SLisandro Dalcin 245*55a74a43SLisandro Dalcin for name in members(keys): 246*55a74a43SLisandro Dalcin 247*55a74a43SLisandro Dalcin if name in override: 248*55a74a43SLisandro Dalcin done.add(name) 249*55a74a43SLisandro Dalcin lines.add = override[name] 250*55a74a43SLisandro Dalcin continue 251*55a74a43SLisandro Dalcin 252*55a74a43SLisandro Dalcin if name in special: 253*55a74a43SLisandro Dalcin done.add(name) 254*55a74a43SLisandro Dalcin sig = special[name] 255*55a74a43SLisandro Dalcin lines.add = f"def {sig}: ..." 256*55a74a43SLisandro Dalcin continue 257*55a74a43SLisandro Dalcin 258*55a74a43SLisandro Dalcin attr = getattr(cls, name) 259*55a74a43SLisandro Dalcin 260*55a74a43SLisandro Dalcin if is_method(attr): 261*55a74a43SLisandro Dalcin done.add(name) 262*55a74a43SLisandro Dalcin if name == attr.__name__: 263*55a74a43SLisandro Dalcin obj = dct[name] 264*55a74a43SLisandro Dalcin if is_classmethod(obj): 265*55a74a43SLisandro Dalcin lines.add = "@classmethod" 266*55a74a43SLisandro Dalcin elif is_staticmethod(obj): 267*55a74a43SLisandro Dalcin lines.add = "@staticmethod" 268*55a74a43SLisandro Dalcin lines.add = visit_method(attr) 269*55a74a43SLisandro Dalcin elif False: 270*55a74a43SLisandro Dalcin lines.add = f"{name} = {attr.__name__}" 271*55a74a43SLisandro Dalcin continue 272*55a74a43SLisandro Dalcin 273*55a74a43SLisandro Dalcin if is_datadescr(attr): 274*55a74a43SLisandro Dalcin done.add(name) 275*55a74a43SLisandro Dalcin lines.add = visit_datadescr(attr) 276*55a74a43SLisandro Dalcin continue 277*55a74a43SLisandro Dalcin 278*55a74a43SLisandro Dalcin if is_property(attr): 279*55a74a43SLisandro Dalcin done.add(name) 280*55a74a43SLisandro Dalcin lines.add = visit_property(attr, name) 281*55a74a43SLisandro Dalcin continue 282*55a74a43SLisandro Dalcin 283*55a74a43SLisandro Dalcin if is_constant(attr): 284*55a74a43SLisandro Dalcin done.add(name) 285*55a74a43SLisandro Dalcin lines.add = visit_data((name, attr)) 286*55a74a43SLisandro Dalcin continue 287*55a74a43SLisandro Dalcin 288*55a74a43SLisandro Dalcin leftovers = [name for name in keys if 289*55a74a43SLisandro Dalcin name not in done and name not in skip] 290*55a74a43SLisandro Dalcin if leftovers: 291*55a74a43SLisandro Dalcin raise RuntimeError(f"leftovers: {leftovers}") 292*55a74a43SLisandro Dalcin 293*55a74a43SLisandro Dalcin lines.level -= 1 294*55a74a43SLisandro Dalcin return lines 295*55a74a43SLisandro Dalcin 296*55a74a43SLisandro Dalcin 297*55a74a43SLisandro Dalcindef visit_module(module, done=None): 298*55a74a43SLisandro Dalcin skip = { 299*55a74a43SLisandro Dalcin '__doc__', 300*55a74a43SLisandro Dalcin '__name__', 301*55a74a43SLisandro Dalcin '__loader__', 302*55a74a43SLisandro Dalcin '__spec__', 303*55a74a43SLisandro Dalcin '__file__', 304*55a74a43SLisandro Dalcin '__package__', 305*55a74a43SLisandro Dalcin '__builtins__', 306*55a74a43SLisandro Dalcin '__pyx_capi__', 307*55a74a43SLisandro Dalcin '__pyx_unpickle_Enum', # FIXME review 308*55a74a43SLisandro Dalcin } 309*55a74a43SLisandro Dalcin 310*55a74a43SLisandro Dalcin done = set() if done is None else done 311*55a74a43SLisandro Dalcin lines = Lines() 312*55a74a43SLisandro Dalcin 313*55a74a43SLisandro Dalcin keys = list(module.__dict__.keys()) 314*55a74a43SLisandro Dalcin keys.sort(key=lambda name: name.startswith("_")) 315*55a74a43SLisandro Dalcin 316*55a74a43SLisandro Dalcin constants = [ 317*55a74a43SLisandro Dalcin (name, getattr(module, name)) for name in keys 318*55a74a43SLisandro Dalcin if all(( 319*55a74a43SLisandro Dalcin name not in done and name not in skip, 320*55a74a43SLisandro Dalcin is_constant(getattr(module, name)), 321*55a74a43SLisandro Dalcin )) 322*55a74a43SLisandro Dalcin ] 323*55a74a43SLisandro Dalcin for _, value in constants: 324*55a74a43SLisandro Dalcin cls = type(value) 325*55a74a43SLisandro Dalcin name = cls.__name__ 326*55a74a43SLisandro Dalcin if name in done or name in skip: 327*55a74a43SLisandro Dalcin continue 328*55a74a43SLisandro Dalcin if cls.__module__ == module.__name__: 329*55a74a43SLisandro Dalcin done.add(name) 330*55a74a43SLisandro Dalcin lines.add = visit_class(cls) 331*55a74a43SLisandro Dalcin lines.add = "" 332*55a74a43SLisandro Dalcin for attr in constants: 333*55a74a43SLisandro Dalcin name, value = attr 334*55a74a43SLisandro Dalcin done.add(name) 335*55a74a43SLisandro Dalcin if name in OVERRIDE: 336*55a74a43SLisandro Dalcin lines.add = OVERRIDE[name] 337*55a74a43SLisandro Dalcin else: 338*55a74a43SLisandro Dalcin lines.add = visit_data((name, value)) 339*55a74a43SLisandro Dalcin if constants: 340*55a74a43SLisandro Dalcin lines.add = "" 341*55a74a43SLisandro Dalcin 342*55a74a43SLisandro Dalcin for name in keys: 343*55a74a43SLisandro Dalcin if name in done or name in skip: 344*55a74a43SLisandro Dalcin continue 345*55a74a43SLisandro Dalcin value = getattr(module, name) 346*55a74a43SLisandro Dalcin 347*55a74a43SLisandro Dalcin if is_class(value): 348*55a74a43SLisandro Dalcin done.add(name) 349*55a74a43SLisandro Dalcin if value.__name__ != name: 350*55a74a43SLisandro Dalcin continue 351*55a74a43SLisandro Dalcin if value.__module__ != module.__name__: 352*55a74a43SLisandro Dalcin continue 353*55a74a43SLisandro Dalcin lines.add = visit_class(value) 354*55a74a43SLisandro Dalcin lines.add = "" 355*55a74a43SLisandro Dalcin instances = [ 356*55a74a43SLisandro Dalcin (k, getattr(module, k)) for k in keys 357*55a74a43SLisandro Dalcin if all(( 358*55a74a43SLisandro Dalcin k not in done and k not in skip, 359*55a74a43SLisandro Dalcin type(getattr(module, k)) is value, 360*55a74a43SLisandro Dalcin )) 361*55a74a43SLisandro Dalcin ] 362*55a74a43SLisandro Dalcin for attrname, attrvalue in instances: 363*55a74a43SLisandro Dalcin done.add(attrname) 364*55a74a43SLisandro Dalcin lines.add = visit_data((attrname, attrvalue)) 365*55a74a43SLisandro Dalcin if instances: 366*55a74a43SLisandro Dalcin lines.add = "" 367*55a74a43SLisandro Dalcin continue 368*55a74a43SLisandro Dalcin 369*55a74a43SLisandro Dalcin if is_function(value): 370*55a74a43SLisandro Dalcin done.add(name) 371*55a74a43SLisandro Dalcin if name == value.__name__: 372*55a74a43SLisandro Dalcin lines.add = visit_function(value) 373*55a74a43SLisandro Dalcin else: 374*55a74a43SLisandro Dalcin lines.add = f"{name} = {value.__name__}" 375*55a74a43SLisandro Dalcin continue 376*55a74a43SLisandro Dalcin 377*55a74a43SLisandro Dalcin lines.add = "" 378*55a74a43SLisandro Dalcin for name in keys: 379*55a74a43SLisandro Dalcin if name in done or name in skip: 380*55a74a43SLisandro Dalcin continue 381*55a74a43SLisandro Dalcin value = getattr(module, name) 382*55a74a43SLisandro Dalcin done.add(name) 383*55a74a43SLisandro Dalcin if name in OVERRIDE: 384*55a74a43SLisandro Dalcin lines.add = OVERRIDE[name] 385*55a74a43SLisandro Dalcin else: 386*55a74a43SLisandro Dalcin lines.add = visit_data((name, value)) 387*55a74a43SLisandro Dalcin 388*55a74a43SLisandro Dalcin leftovers = [name for name in keys if 389*55a74a43SLisandro Dalcin name not in done and name not in skip] 390*55a74a43SLisandro Dalcin if leftovers: 391*55a74a43SLisandro Dalcin raise RuntimeError(f"leftovers: {leftovers}") 392*55a74a43SLisandro Dalcin return lines 393*55a74a43SLisandro Dalcin 394*55a74a43SLisandro Dalcin 395*55a74a43SLisandro DalcinIMPORTS = """ 396*55a74a43SLisandro Dalcinfrom __future__ import annotations 397*55a74a43SLisandro Dalcinimport sys 398*55a74a43SLisandro Dalcinfrom typing import ( 399*55a74a43SLisandro Dalcin Any, 400*55a74a43SLisandro Dalcin Union, 401*55a74a43SLisandro Dalcin Literal, 402*55a74a43SLisandro Dalcin Optional, 403*55a74a43SLisandro Dalcin NoReturn, 404*55a74a43SLisandro Dalcin Final, 405*55a74a43SLisandro Dalcin) 406*55a74a43SLisandro Dalcinfrom typing import ( 407*55a74a43SLisandro Dalcin Callable, 408*55a74a43SLisandro Dalcin Hashable, 409*55a74a43SLisandro Dalcin Iterable, 410*55a74a43SLisandro Dalcin Iterator, 411*55a74a43SLisandro Dalcin Sequence, 412*55a74a43SLisandro Dalcin Mapping, 413*55a74a43SLisandro Dalcin) 414*55a74a43SLisandro Dalcinif sys.version_info >= (3, 11): 415*55a74a43SLisandro Dalcin from typing import Self 416*55a74a43SLisandro Dalcinelse: 417*55a74a43SLisandro Dalcin from typing_extensions import Self 418*55a74a43SLisandro Dalcin 419*55a74a43SLisandro Dalcinimport numpy 420*55a74a43SLisandro Dalcinfrom numpy import dtype, ndarray 421*55a74a43SLisandro Dalcinfrom mpi4py.MPI import ( 422*55a74a43SLisandro Dalcin Intracomm, 423*55a74a43SLisandro Dalcin Datatype, 424*55a74a43SLisandro Dalcin Op, 425*55a74a43SLisandro Dalcin) 426*55a74a43SLisandro Dalcin 427*55a74a43SLisandro Dalcinclass _dtype: 428*55a74a43SLisandro Dalcin def __init__(self, name): 429*55a74a43SLisandro Dalcin self.name = name 430*55a74a43SLisandro Dalcin def __repr__(self): 431*55a74a43SLisandro Dalcin return self.name 432*55a74a43SLisandro Dalcin 433*55a74a43SLisandro DalcinIntType: dtype = _dtype('IntType') 434*55a74a43SLisandro DalcinRealType: dtype = _dtype('RealType') 435*55a74a43SLisandro DalcinComplexType: dtype = _dtype('ComplexType') 436*55a74a43SLisandro DalcinScalarType: dtype = _dtype('ScalarType') 437*55a74a43SLisandro Dalcin""" 438*55a74a43SLisandro Dalcin 439*55a74a43SLisandro DalcinHELPERS = """ 440*55a74a43SLisandro Dalcinclass _Int(int): pass 441*55a74a43SLisandro Dalcinclass _Str(str): pass 442*55a74a43SLisandro Dalcinclass _Float(float): pass 443*55a74a43SLisandro Dalcinclass _Dict(dict): pass 444*55a74a43SLisandro Dalcin 445*55a74a43SLisandro Dalcindef _repr(obj): 446*55a74a43SLisandro Dalcin try: 447*55a74a43SLisandro Dalcin return obj._name 448*55a74a43SLisandro Dalcin except AttributeError: 449*55a74a43SLisandro Dalcin return super(obj).__repr__() 450*55a74a43SLisandro Dalcin 451*55a74a43SLisandro Dalcindef _def(cls, name): 452*55a74a43SLisandro Dalcin if cls is int: 453*55a74a43SLisandro Dalcin cls = _Int 454*55a74a43SLisandro Dalcin if cls is str: 455*55a74a43SLisandro Dalcin cls = _Str 456*55a74a43SLisandro Dalcin if cls is float: 457*55a74a43SLisandro Dalcin cls = _Float 458*55a74a43SLisandro Dalcin if cls is dict: 459*55a74a43SLisandro Dalcin cls = _Dict 460*55a74a43SLisandro Dalcin 461*55a74a43SLisandro Dalcin obj = cls() 462*55a74a43SLisandro Dalcin obj._name = name 463*55a74a43SLisandro Dalcin if '__repr__' not in cls.__dict__: 464*55a74a43SLisandro Dalcin cls.__repr__ = _repr 465*55a74a43SLisandro Dalcin return obj 466*55a74a43SLisandro Dalcin""" 467*55a74a43SLisandro Dalcin 468*55a74a43SLisandro DalcinOVERRIDE = { 469*55a74a43SLisandro Dalcin} 470*55a74a43SLisandro Dalcin 471*55a74a43SLisandro DalcinTYPING = """ 472*55a74a43SLisandro Dalcinfrom .typing import * 473*55a74a43SLisandro Dalcin""" 474*55a74a43SLisandro Dalcin 475*55a74a43SLisandro Dalcin 476*55a74a43SLisandro Dalcindef visit_petsc4py_PETSc(done=None): 477*55a74a43SLisandro Dalcin from petsc4py import PETSc 478*55a74a43SLisandro Dalcin lines = Lines() 479*55a74a43SLisandro Dalcin lines.add = f'"""{PETSc.__doc__}"""' 480*55a74a43SLisandro Dalcin lines.add = IMPORTS 481*55a74a43SLisandro Dalcin lines.add = "" 482*55a74a43SLisandro Dalcin lines.add = HELPERS 483*55a74a43SLisandro Dalcin lines.add = "" 484*55a74a43SLisandro Dalcin lines.add = visit_module(PETSc) 485*55a74a43SLisandro Dalcin lines.add = "" 486*55a74a43SLisandro Dalcin lines.add = TYPING 487*55a74a43SLisandro Dalcin return lines 488*55a74a43SLisandro Dalcin 489*55a74a43SLisandro Dalcin 490*55a74a43SLisandro Dalcindef generate(filename): 491*55a74a43SLisandro Dalcin dirname = os.path.dirname(filename) 492*55a74a43SLisandro Dalcin os.makedirs(dirname, exist_ok=True) 493*55a74a43SLisandro Dalcin with open(filename, 'w') as f: 494*55a74a43SLisandro Dalcin for line in visit_petsc4py_PETSc(): 495*55a74a43SLisandro Dalcin print(line, file=f) 496*55a74a43SLisandro Dalcin 497*55a74a43SLisandro Dalcin 498*55a74a43SLisandro Dalcindef load_module(filename, name=None): 499*55a74a43SLisandro Dalcin if name is None: 500*55a74a43SLisandro Dalcin name, _ = os.path.splitext( 501*55a74a43SLisandro Dalcin os.path.basename(filename)) 502*55a74a43SLisandro Dalcin module = type(sys)(name) 503*55a74a43SLisandro Dalcin module.__file__ = filename 504*55a74a43SLisandro Dalcin module.__package__ = name.rsplit('.', 1)[0] 505*55a74a43SLisandro Dalcin old = replace_module(module) 506*55a74a43SLisandro Dalcin with open(filename) as f: 507*55a74a43SLisandro Dalcin exec(f.read(), module.__dict__) # noqa: S102 508*55a74a43SLisandro Dalcin restore_module(old) 509*55a74a43SLisandro Dalcin return module 510*55a74a43SLisandro Dalcin 511*55a74a43SLisandro Dalcin 512*55a74a43SLisandro Dalcin_sys_modules = {} 513*55a74a43SLisandro Dalcin 514*55a74a43SLisandro Dalcin 515*55a74a43SLisandro Dalcindef replace_module(module): 516*55a74a43SLisandro Dalcin name = module.__name__ 517*55a74a43SLisandro Dalcin assert name not in _sys_modules 518*55a74a43SLisandro Dalcin _sys_modules[name] = sys.modules[name] 519*55a74a43SLisandro Dalcin sys.modules[name] = module 520*55a74a43SLisandro Dalcin return _sys_modules[name] 521*55a74a43SLisandro Dalcin 522*55a74a43SLisandro Dalcin 523*55a74a43SLisandro Dalcindef restore_module(module): 524*55a74a43SLisandro Dalcin name = module.__name__ 525*55a74a43SLisandro Dalcin assert name in _sys_modules 526*55a74a43SLisandro Dalcin sys.modules[name] = _sys_modules[name] 527*55a74a43SLisandro Dalcin del _sys_modules[name] 528*55a74a43SLisandro Dalcin 529*55a74a43SLisandro Dalcin 530*55a74a43SLisandro Dalcindef annotate(dest, source): 531*55a74a43SLisandro Dalcin try: 532*55a74a43SLisandro Dalcin dest.__annotations__ = source.__annotations__ 533*55a74a43SLisandro Dalcin except AttributeError: 534*55a74a43SLisandro Dalcin pass 535*55a74a43SLisandro Dalcin if isinstance(dest, type): 536*55a74a43SLisandro Dalcin for name in dest.__dict__.keys(): 537*55a74a43SLisandro Dalcin if hasattr(source, name): 538*55a74a43SLisandro Dalcin obj = getattr(dest, name) 539*55a74a43SLisandro Dalcin annotate(obj, getattr(source, name)) 540*55a74a43SLisandro Dalcin if isinstance(dest, type(sys)): 541*55a74a43SLisandro Dalcin for name in dir(dest): 542*55a74a43SLisandro Dalcin if hasattr(source, name): 543*55a74a43SLisandro Dalcin obj = getattr(dest, name) 544*55a74a43SLisandro Dalcin mod = getattr(obj, '__module__', None) 545*55a74a43SLisandro Dalcin if dest.__name__ == mod: 546*55a74a43SLisandro Dalcin annotate(obj, getattr(source, name)) 547*55a74a43SLisandro Dalcin for name in dir(source): 548*55a74a43SLisandro Dalcin if not hasattr(dest, name): 549*55a74a43SLisandro Dalcin setattr(dest, name, getattr(source, name)) 550*55a74a43SLisandro Dalcin 551*55a74a43SLisandro Dalcin 552*55a74a43SLisandro DalcinOUTDIR = 'reference' 553*55a74a43SLisandro Dalcin 554*55a74a43SLisandro Dalcinif __name__ == '__main__': 555*55a74a43SLisandro Dalcin generate(os.path.join(OUTDIR, 'petsc4py.PETSc.py')) 556