155a74a43SLisandro Dalcinimport os 255a74a43SLisandro Dalcinimport sys 355a74a43SLisandro Dalcinimport inspect 455a74a43SLisandro Dalcinimport textwrap 555a74a43SLisandro Dalcin 655a74a43SLisandro Dalcin 755a74a43SLisandro Dalcindef is_cyfunction(obj): 855a74a43SLisandro Dalcin return type(obj).__name__ == 'cython_function_or_method' 955a74a43SLisandro Dalcin 1055a74a43SLisandro Dalcin 1155a74a43SLisandro Dalcindef is_function(obj): 1255a74a43SLisandro Dalcin return ( 1355a74a43SLisandro Dalcin inspect.isbuiltin(obj) 1455a74a43SLisandro Dalcin or is_cyfunction(obj) 1555a74a43SLisandro Dalcin or type(obj) is type(ord) 1655a74a43SLisandro Dalcin ) 1755a74a43SLisandro Dalcin 1855a74a43SLisandro Dalcin 1955a74a43SLisandro Dalcindef is_method(obj): 2055a74a43SLisandro Dalcin return ( 2155a74a43SLisandro Dalcin inspect.ismethoddescriptor(obj) 2255a74a43SLisandro Dalcin or inspect.ismethod(obj) 2355a74a43SLisandro Dalcin or is_cyfunction(obj) 2455a74a43SLisandro Dalcin or type(obj) in ( 2555a74a43SLisandro Dalcin type(str.index), 2655a74a43SLisandro Dalcin type(str.__add__), 2755a74a43SLisandro Dalcin type(str.__new__), 2855a74a43SLisandro Dalcin ) 2955a74a43SLisandro Dalcin ) 3055a74a43SLisandro Dalcin 3155a74a43SLisandro Dalcin 3255a74a43SLisandro Dalcindef is_classmethod(obj): 3355a74a43SLisandro Dalcin return ( 3455a74a43SLisandro Dalcin inspect.isbuiltin(obj) 3555a74a43SLisandro Dalcin or type(obj).__name__ in ( 3655a74a43SLisandro Dalcin 'classmethod', 3755a74a43SLisandro Dalcin 'classmethod_descriptor', 3855a74a43SLisandro Dalcin ) 3955a74a43SLisandro Dalcin ) 4055a74a43SLisandro Dalcin 4155a74a43SLisandro Dalcin 4255a74a43SLisandro Dalcindef is_staticmethod(obj): 4355a74a43SLisandro Dalcin return ( 4455a74a43SLisandro Dalcin type(obj).__name__ in ( 4555a74a43SLisandro Dalcin 'staticmethod', 4655a74a43SLisandro Dalcin ) 4755a74a43SLisandro Dalcin ) 4855a74a43SLisandro Dalcin 4955a74a43SLisandro Dalcindef is_constant(obj): 5055a74a43SLisandro Dalcin return isinstance(obj, (int, float, str, dict)) 5155a74a43SLisandro Dalcin 5255a74a43SLisandro Dalcindef is_datadescr(obj): 5355a74a43SLisandro Dalcin return inspect.isdatadescriptor(obj) and not hasattr(obj, 'fget') 5455a74a43SLisandro Dalcin 5555a74a43SLisandro Dalcin 5655a74a43SLisandro Dalcindef is_property(obj): 5755a74a43SLisandro Dalcin return inspect.isdatadescriptor(obj) and hasattr(obj, 'fget') 5855a74a43SLisandro Dalcin 5955a74a43SLisandro Dalcin 6055a74a43SLisandro Dalcindef is_class(obj): 6155a74a43SLisandro Dalcin return inspect.isclass(obj) or type(obj) is type(int) 6255a74a43SLisandro Dalcin 6355a74a43SLisandro Dalcin 6455a74a43SLisandro Dalcinclass Lines(list): 6555a74a43SLisandro Dalcin 6655a74a43SLisandro Dalcin INDENT = " " * 4 6755a74a43SLisandro Dalcin level = 0 6855a74a43SLisandro Dalcin 6955a74a43SLisandro Dalcin @property 7055a74a43SLisandro Dalcin def add(self): 7155a74a43SLisandro Dalcin return self 7255a74a43SLisandro Dalcin 7355a74a43SLisandro Dalcin @add.setter 7455a74a43SLisandro Dalcin def add(self, lines): 7555a74a43SLisandro Dalcin if lines is None: 7655a74a43SLisandro Dalcin return 7755a74a43SLisandro Dalcin if isinstance(lines, str): 7855a74a43SLisandro Dalcin lines = textwrap.dedent(lines).strip().split('\n') 7955a74a43SLisandro Dalcin indent = self.INDENT * self.level 8055a74a43SLisandro Dalcin for line in lines: 8155a74a43SLisandro Dalcin self.append(indent + line) 8255a74a43SLisandro Dalcin 8355a74a43SLisandro Dalcin 8455a74a43SLisandro Dalcindef signature(obj): 8555a74a43SLisandro Dalcin doc = obj.__doc__ 8655a74a43SLisandro Dalcin doc = doc or f"{obj.__name__}: Any" # FIXME remove line 8755a74a43SLisandro Dalcin sig = doc.partition('\n')[0].split('.', 1)[-1] 8855a74a43SLisandro Dalcin return sig or None 8955a74a43SLisandro Dalcin 90*b3f8c7a1SStefano Zampini# XXX 91*b3f8c7a1SStefano Zampini# baselink = 'https://gitlab.com/petsc/petsc/-/tree/main' 9255a74a43SLisandro Dalcin 9355a74a43SLisandro Dalcindef docstring(obj): 9455a74a43SLisandro Dalcin doc = obj.__doc__ 9555a74a43SLisandro Dalcin doc = doc or '' # FIXME 96*b3f8c7a1SStefano Zampini link = None 9755a74a43SLisandro Dalcin if is_class(obj): 9855a74a43SLisandro Dalcin doc = doc.strip() 9955a74a43SLisandro Dalcin else: 10055a74a43SLisandro Dalcin doc = doc.partition('\n')[2] 101*b3f8c7a1SStefano Zampini doc, _, link = doc.rpartition('\n') 102*b3f8c7a1SStefano Zampini 10355a74a43SLisandro Dalcin summary, _, docbody = doc.partition('\n') 10455a74a43SLisandro Dalcin summary = summary.strip() 10555a74a43SLisandro Dalcin docbody = textwrap.dedent(docbody).strip() 106*b3f8c7a1SStefano Zampini if link: 107*b3f8c7a1SStefano Zampini linkloc = link.replace(':','#L') 108*b3f8c7a1SStefano Zampini section = '' 109*b3f8c7a1SStefano Zampini #section = f'References\n----------`' 110*b3f8c7a1SStefano Zampini #linkbody = f'`Source code at {link} <{baselink}/src/binding/petsc4py/src/{linkloc}>`__' 111*b3f8c7a1SStefano Zampini linkbody = f':sources:`Source code at {link} <{linkloc}>`' 112*b3f8c7a1SStefano Zampini linkbody = f'{section}\n\n{linkbody}' 113*b3f8c7a1SStefano Zampini if docbody: 114*b3f8c7a1SStefano Zampini docbody = f'{docbody}\n\n{linkbody}' 115*b3f8c7a1SStefano Zampini else: 116*b3f8c7a1SStefano Zampini docbody = linkbody 117*b3f8c7a1SStefano Zampini 11855a74a43SLisandro Dalcin if docbody: 11955a74a43SLisandro Dalcin doc = f'"""{summary}\n\n{docbody}\n\n"""' 12055a74a43SLisandro Dalcin else: 12155a74a43SLisandro Dalcin doc = f'"""{summary}"""' 12255a74a43SLisandro Dalcin doc = textwrap.indent(doc, Lines.INDENT) 12355a74a43SLisandro Dalcin return doc 12455a74a43SLisandro Dalcin 12555a74a43SLisandro Dalcin 12655a74a43SLisandro Dalcindef visit_data(constant): 12755a74a43SLisandro Dalcin name, value = constant 12855a74a43SLisandro Dalcin typename = type(value).__name__ 12955a74a43SLisandro Dalcin kind = "Constant" if isinstance(value, int) else "Object" 13055a74a43SLisandro Dalcin init = f"_def({typename}, '{name}')" 13155a74a43SLisandro Dalcin doc = f"#: {kind} ``{name}`` of type :class:`{typename}`" 13255a74a43SLisandro Dalcin return f"{name}: {typename} = {init} {doc}\n" 13355a74a43SLisandro Dalcin 13455a74a43SLisandro Dalcin 13555a74a43SLisandro Dalcindef visit_function(function): 13655a74a43SLisandro Dalcin sig = signature(function) 13755a74a43SLisandro Dalcin doc = docstring(function) 13855a74a43SLisandro Dalcin body = Lines.INDENT + "..." 13955a74a43SLisandro Dalcin return f"def {sig}:\n{doc}\n{body}\n" 14055a74a43SLisandro Dalcin 14155a74a43SLisandro Dalcin 14255a74a43SLisandro Dalcindef visit_method(method): 14355a74a43SLisandro Dalcin sig = signature(method) 14455a74a43SLisandro Dalcin doc = docstring(method) 14555a74a43SLisandro Dalcin body = Lines.INDENT + "..." 14655a74a43SLisandro Dalcin return f"def {sig}:\n{doc}\n{body}\n" 14755a74a43SLisandro Dalcin 14855a74a43SLisandro Dalcin 14955a74a43SLisandro Dalcindef visit_datadescr(datadescr, name=None): 15055a74a43SLisandro Dalcin sig = signature(datadescr) 15155a74a43SLisandro Dalcin doc = docstring(datadescr) 15255a74a43SLisandro Dalcin name = sig.partition(':')[0].strip() or datadescr.__name__ 15355a74a43SLisandro Dalcin type = sig.partition(':')[2].strip() or 'Any' 15455a74a43SLisandro Dalcin sig = f"{name}(self) -> {type}" 15555a74a43SLisandro Dalcin body = Lines.INDENT + "..." 15655a74a43SLisandro Dalcin return f"@property\ndef {sig}:\n{doc}\n{body}\n" 15755a74a43SLisandro Dalcin 15855a74a43SLisandro Dalcin 15955a74a43SLisandro Dalcindef visit_property(prop, name=None): 16055a74a43SLisandro Dalcin sig = signature(prop.fget) 16155a74a43SLisandro Dalcin name = name or prop.fget.__name__ 16255a74a43SLisandro Dalcin type = sig.rsplit('->', 1)[-1].strip() 16355a74a43SLisandro Dalcin sig = f"{name}(self) -> {type}" 16455a74a43SLisandro Dalcin doc = f'"""{prop.__doc__}"""' 16555a74a43SLisandro Dalcin doc = textwrap.indent(doc, Lines.INDENT) 16655a74a43SLisandro Dalcin body = Lines.INDENT + "..." 16755a74a43SLisandro Dalcin return f"@property\ndef {sig}:\n{doc}\n{body}\n" 16855a74a43SLisandro Dalcin 16955a74a43SLisandro Dalcin 17055a74a43SLisandro Dalcindef visit_constructor(cls, name='__init__', args=None): 17155a74a43SLisandro Dalcin init = (name == '__init__') 17255a74a43SLisandro Dalcin argname = cls.__mro__[-2].__name__.lower() 17355a74a43SLisandro Dalcin argtype = cls.__name__ 17455a74a43SLisandro Dalcin initarg = args or f"{argname}: Optional[{argtype}] = None" 17555a74a43SLisandro Dalcin selfarg = 'self' if init else 'cls' 17655a74a43SLisandro Dalcin rettype = 'None' if init else argtype 17755a74a43SLisandro Dalcin arglist = f"{selfarg}, {initarg}" 17855a74a43SLisandro Dalcin sig = f"{name}({arglist}) -> {rettype}" 17955a74a43SLisandro Dalcin ret = '...' if init else 'return super().__new__(cls)' 18055a74a43SLisandro Dalcin body = Lines.INDENT + ret 18155a74a43SLisandro Dalcin return f"def {sig}:\n{body}" 18255a74a43SLisandro Dalcin 18355a74a43SLisandro Dalcin 18455a74a43SLisandro Dalcindef visit_class(cls, outer=None, done=None): 18555a74a43SLisandro Dalcin skip = { 18655a74a43SLisandro Dalcin '__doc__', 18755a74a43SLisandro Dalcin '__dict__', 18855a74a43SLisandro Dalcin '__module__', 18955a74a43SLisandro Dalcin '__weakref__', 19055a74a43SLisandro Dalcin '__pyx_vtable__', 19155a74a43SLisandro Dalcin '__lt__', 19255a74a43SLisandro Dalcin '__le__', 19355a74a43SLisandro Dalcin '__ge__', 19455a74a43SLisandro Dalcin '__gt__', 19555a74a43SLisandro Dalcin '__enum2str', # FIXME refactor implemetation 19655a74a43SLisandro Dalcin '_traceback_', # FIXME maybe refactor? 19755a74a43SLisandro Dalcin } 19855a74a43SLisandro Dalcin special = { 19955a74a43SLisandro Dalcin '__len__': "__len__(self) -> int", 20055a74a43SLisandro Dalcin '__bool__': "__bool__(self) -> bool", 20155a74a43SLisandro Dalcin '__hash__': "__hash__(self) -> int", 20255a74a43SLisandro Dalcin '__int__': "__int__(self) -> int", 20355a74a43SLisandro Dalcin '__index__': "__int__(self) -> int", 20455a74a43SLisandro Dalcin '__str__': "__str__(self) -> str", 20555a74a43SLisandro Dalcin '__repr__': "__repr__(self) -> str", 20655a74a43SLisandro Dalcin '__eq__': "__eq__(self, other: object) -> bool", 20755a74a43SLisandro Dalcin '__ne__': "__ne__(self, other: object) -> bool", 20855a74a43SLisandro Dalcin } 20955a74a43SLisandro Dalcin constructor = ( 21055a74a43SLisandro Dalcin '__new__', 21155a74a43SLisandro Dalcin '__init__', 21255a74a43SLisandro Dalcin ) 21355a74a43SLisandro Dalcin 21455a74a43SLisandro Dalcin qualname = cls.__name__ 21555a74a43SLisandro Dalcin cls_name = cls.__name__ 21655a74a43SLisandro Dalcin if outer is not None and cls_name.startswith(outer): 21755a74a43SLisandro Dalcin cls_name = cls_name[len(outer):] 21855a74a43SLisandro Dalcin qualname = f"{outer}.{cls_name}" 21955a74a43SLisandro Dalcin 22055a74a43SLisandro Dalcin override = OVERRIDE.get(qualname, {}) 22155a74a43SLisandro Dalcin done = set() if done is None else done 22255a74a43SLisandro Dalcin lines = Lines() 22355a74a43SLisandro Dalcin 22455a74a43SLisandro Dalcin base = cls.__base__ 22555a74a43SLisandro Dalcin if base is object: 22655a74a43SLisandro Dalcin lines.add = f"class {cls_name}:" 22755a74a43SLisandro Dalcin else: 22855a74a43SLisandro Dalcin lines.add = f"class {cls_name}({base.__name__}):" 22955a74a43SLisandro Dalcin lines.level += 1 23055a74a43SLisandro Dalcin 23155a74a43SLisandro Dalcin lines.add = docstring(cls) 23255a74a43SLisandro Dalcin 23355a74a43SLisandro Dalcin for name in ('__new__', '__init__', '__hash__'): 23455a74a43SLisandro Dalcin if name in cls.__dict__: 23555a74a43SLisandro Dalcin done.add(name) 23655a74a43SLisandro Dalcin 23755a74a43SLisandro Dalcin dct = cls.__dict__ 23855a74a43SLisandro Dalcin keys = list(dct.keys()) 23955a74a43SLisandro Dalcin 24055a74a43SLisandro Dalcin def dunder(name): 24155a74a43SLisandro Dalcin return name.startswith('__') and name.endswith('__') 24255a74a43SLisandro Dalcin 24355a74a43SLisandro Dalcin def members(seq): 24455a74a43SLisandro Dalcin for name in seq: 24555a74a43SLisandro Dalcin if name in skip: 24655a74a43SLisandro Dalcin continue 24755a74a43SLisandro Dalcin if name in done: 24855a74a43SLisandro Dalcin continue 24955a74a43SLisandro Dalcin if dunder(name): 25055a74a43SLisandro Dalcin if name not in special and name not in override: 25155a74a43SLisandro Dalcin done.add(name) 25255a74a43SLisandro Dalcin continue 25355a74a43SLisandro Dalcin yield name 25455a74a43SLisandro Dalcin 25555a74a43SLisandro Dalcin for name in members(keys): 25655a74a43SLisandro Dalcin attr = getattr(cls, name) 25755a74a43SLisandro Dalcin if is_class(attr): 25855a74a43SLisandro Dalcin done.add(name) 25955a74a43SLisandro Dalcin lines.add = visit_class(attr, outer=cls_name) 26055a74a43SLisandro Dalcin continue 26155a74a43SLisandro Dalcin 26255a74a43SLisandro Dalcin for name in members(keys): 26355a74a43SLisandro Dalcin 26455a74a43SLisandro Dalcin if name in override: 26555a74a43SLisandro Dalcin done.add(name) 26655a74a43SLisandro Dalcin lines.add = override[name] 26755a74a43SLisandro Dalcin continue 26855a74a43SLisandro Dalcin 26955a74a43SLisandro Dalcin if name in special: 27055a74a43SLisandro Dalcin done.add(name) 27155a74a43SLisandro Dalcin sig = special[name] 27255a74a43SLisandro Dalcin lines.add = f"def {sig}: ..." 27355a74a43SLisandro Dalcin continue 27455a74a43SLisandro Dalcin 27555a74a43SLisandro Dalcin attr = getattr(cls, name) 27655a74a43SLisandro Dalcin 27755a74a43SLisandro Dalcin if is_method(attr): 27855a74a43SLisandro Dalcin done.add(name) 27955a74a43SLisandro Dalcin if name == attr.__name__: 28055a74a43SLisandro Dalcin obj = dct[name] 28155a74a43SLisandro Dalcin if is_classmethod(obj): 28255a74a43SLisandro Dalcin lines.add = "@classmethod" 28355a74a43SLisandro Dalcin elif is_staticmethod(obj): 28455a74a43SLisandro Dalcin lines.add = "@staticmethod" 28555a74a43SLisandro Dalcin lines.add = visit_method(attr) 28655a74a43SLisandro Dalcin elif False: 28755a74a43SLisandro Dalcin lines.add = f"{name} = {attr.__name__}" 28855a74a43SLisandro Dalcin continue 28955a74a43SLisandro Dalcin 29055a74a43SLisandro Dalcin if is_datadescr(attr): 29155a74a43SLisandro Dalcin done.add(name) 29255a74a43SLisandro Dalcin lines.add = visit_datadescr(attr) 29355a74a43SLisandro Dalcin continue 29455a74a43SLisandro Dalcin 29555a74a43SLisandro Dalcin if is_property(attr): 29655a74a43SLisandro Dalcin done.add(name) 29755a74a43SLisandro Dalcin lines.add = visit_property(attr, name) 29855a74a43SLisandro Dalcin continue 29955a74a43SLisandro Dalcin 30055a74a43SLisandro Dalcin if is_constant(attr): 30155a74a43SLisandro Dalcin done.add(name) 30255a74a43SLisandro Dalcin lines.add = visit_data((name, attr)) 30355a74a43SLisandro Dalcin continue 30455a74a43SLisandro Dalcin 30555a74a43SLisandro Dalcin leftovers = [name for name in keys if 30655a74a43SLisandro Dalcin name not in done and name not in skip] 30755a74a43SLisandro Dalcin if leftovers: 30855a74a43SLisandro Dalcin raise RuntimeError(f"leftovers: {leftovers}") 30955a74a43SLisandro Dalcin 31055a74a43SLisandro Dalcin lines.level -= 1 31155a74a43SLisandro Dalcin return lines 31255a74a43SLisandro Dalcin 31355a74a43SLisandro Dalcin 31455a74a43SLisandro Dalcindef visit_module(module, done=None): 31555a74a43SLisandro Dalcin skip = { 31655a74a43SLisandro Dalcin '__doc__', 31755a74a43SLisandro Dalcin '__name__', 31855a74a43SLisandro Dalcin '__loader__', 31955a74a43SLisandro Dalcin '__spec__', 32055a74a43SLisandro Dalcin '__file__', 32155a74a43SLisandro Dalcin '__package__', 32255a74a43SLisandro Dalcin '__builtins__', 32355a74a43SLisandro Dalcin '__pyx_capi__', 32455a74a43SLisandro Dalcin '__pyx_unpickle_Enum', # FIXME review 32555a74a43SLisandro Dalcin } 32655a74a43SLisandro Dalcin 32755a74a43SLisandro Dalcin done = set() if done is None else done 32855a74a43SLisandro Dalcin lines = Lines() 32955a74a43SLisandro Dalcin 33055a74a43SLisandro Dalcin keys = list(module.__dict__.keys()) 33155a74a43SLisandro Dalcin keys.sort(key=lambda name: name.startswith("_")) 33255a74a43SLisandro Dalcin 33355a74a43SLisandro Dalcin constants = [ 33455a74a43SLisandro Dalcin (name, getattr(module, name)) for name in keys 33555a74a43SLisandro Dalcin if all(( 33655a74a43SLisandro Dalcin name not in done and name not in skip, 33755a74a43SLisandro Dalcin is_constant(getattr(module, name)), 33855a74a43SLisandro Dalcin )) 33955a74a43SLisandro Dalcin ] 34055a74a43SLisandro Dalcin for _, value in constants: 34155a74a43SLisandro Dalcin cls = type(value) 34255a74a43SLisandro Dalcin name = cls.__name__ 34355a74a43SLisandro Dalcin if name in done or name in skip: 34455a74a43SLisandro Dalcin continue 34555a74a43SLisandro Dalcin if cls.__module__ == module.__name__: 34655a74a43SLisandro Dalcin done.add(name) 34755a74a43SLisandro Dalcin lines.add = visit_class(cls) 34855a74a43SLisandro Dalcin lines.add = "" 34955a74a43SLisandro Dalcin for attr in constants: 35055a74a43SLisandro Dalcin name, value = attr 35155a74a43SLisandro Dalcin done.add(name) 35255a74a43SLisandro Dalcin if name in OVERRIDE: 35355a74a43SLisandro Dalcin lines.add = OVERRIDE[name] 35455a74a43SLisandro Dalcin else: 35555a74a43SLisandro Dalcin lines.add = visit_data((name, value)) 35655a74a43SLisandro Dalcin if constants: 35755a74a43SLisandro Dalcin lines.add = "" 35855a74a43SLisandro Dalcin 35955a74a43SLisandro Dalcin for name in keys: 36055a74a43SLisandro Dalcin if name in done or name in skip: 36155a74a43SLisandro Dalcin continue 36255a74a43SLisandro Dalcin value = getattr(module, name) 36355a74a43SLisandro Dalcin 36455a74a43SLisandro Dalcin if is_class(value): 36555a74a43SLisandro Dalcin done.add(name) 36655a74a43SLisandro Dalcin if value.__name__ != name: 36755a74a43SLisandro Dalcin continue 36855a74a43SLisandro Dalcin if value.__module__ != module.__name__: 36955a74a43SLisandro Dalcin continue 37055a74a43SLisandro Dalcin lines.add = visit_class(value) 37155a74a43SLisandro Dalcin lines.add = "" 37255a74a43SLisandro Dalcin instances = [ 37355a74a43SLisandro Dalcin (k, getattr(module, k)) for k in keys 37455a74a43SLisandro Dalcin if all(( 37555a74a43SLisandro Dalcin k not in done and k not in skip, 37655a74a43SLisandro Dalcin type(getattr(module, k)) is value, 37755a74a43SLisandro Dalcin )) 37855a74a43SLisandro Dalcin ] 37955a74a43SLisandro Dalcin for attrname, attrvalue in instances: 38055a74a43SLisandro Dalcin done.add(attrname) 38155a74a43SLisandro Dalcin lines.add = visit_data((attrname, attrvalue)) 38255a74a43SLisandro Dalcin if instances: 38355a74a43SLisandro Dalcin lines.add = "" 38455a74a43SLisandro Dalcin continue 38555a74a43SLisandro Dalcin 38655a74a43SLisandro Dalcin if is_function(value): 38755a74a43SLisandro Dalcin done.add(name) 38855a74a43SLisandro Dalcin if name == value.__name__: 38955a74a43SLisandro Dalcin lines.add = visit_function(value) 39055a74a43SLisandro Dalcin else: 39155a74a43SLisandro Dalcin lines.add = f"{name} = {value.__name__}" 39255a74a43SLisandro Dalcin continue 39355a74a43SLisandro Dalcin 39455a74a43SLisandro Dalcin lines.add = "" 39555a74a43SLisandro Dalcin for name in keys: 39655a74a43SLisandro Dalcin if name in done or name in skip: 39755a74a43SLisandro Dalcin continue 39855a74a43SLisandro Dalcin value = getattr(module, name) 39955a74a43SLisandro Dalcin done.add(name) 40055a74a43SLisandro Dalcin if name in OVERRIDE: 40155a74a43SLisandro Dalcin lines.add = OVERRIDE[name] 40255a74a43SLisandro Dalcin else: 40355a74a43SLisandro Dalcin lines.add = visit_data((name, value)) 40455a74a43SLisandro Dalcin 40555a74a43SLisandro Dalcin leftovers = [name for name in keys if 40655a74a43SLisandro Dalcin name not in done and name not in skip] 40755a74a43SLisandro Dalcin if leftovers: 40855a74a43SLisandro Dalcin raise RuntimeError(f"leftovers: {leftovers}") 40955a74a43SLisandro Dalcin return lines 41055a74a43SLisandro Dalcin 41155a74a43SLisandro Dalcin 41255a74a43SLisandro DalcinIMPORTS = """ 41355a74a43SLisandro Dalcinfrom __future__ import annotations 41455a74a43SLisandro Dalcinimport sys 41555a74a43SLisandro Dalcinfrom typing import ( 41655a74a43SLisandro Dalcin Any, 41755a74a43SLisandro Dalcin Union, 41855a74a43SLisandro Dalcin Literal, 41955a74a43SLisandro Dalcin Optional, 42055a74a43SLisandro Dalcin NoReturn, 42155a74a43SLisandro Dalcin Final, 42255a74a43SLisandro Dalcin) 42355a74a43SLisandro Dalcinfrom typing import ( 42455a74a43SLisandro Dalcin Callable, 42555a74a43SLisandro Dalcin Hashable, 42655a74a43SLisandro Dalcin Iterable, 42755a74a43SLisandro Dalcin Iterator, 42855a74a43SLisandro Dalcin Sequence, 42955a74a43SLisandro Dalcin Mapping, 43055a74a43SLisandro Dalcin) 43155a74a43SLisandro Dalcinif sys.version_info >= (3, 11): 43255a74a43SLisandro Dalcin from typing import Self 43355a74a43SLisandro Dalcinelse: 43455a74a43SLisandro Dalcin from typing_extensions import Self 43555a74a43SLisandro Dalcin 43655a74a43SLisandro Dalcinimport numpy 43755a74a43SLisandro Dalcinfrom numpy import dtype, ndarray 43855a74a43SLisandro Dalcinfrom mpi4py.MPI import ( 43955a74a43SLisandro Dalcin Intracomm, 44055a74a43SLisandro Dalcin Datatype, 44155a74a43SLisandro Dalcin Op, 44255a74a43SLisandro Dalcin) 44355a74a43SLisandro Dalcin 44455a74a43SLisandro Dalcinclass _dtype: 44555a74a43SLisandro Dalcin def __init__(self, name): 44655a74a43SLisandro Dalcin self.name = name 44755a74a43SLisandro Dalcin def __repr__(self): 44855a74a43SLisandro Dalcin return self.name 44955a74a43SLisandro Dalcin 45055a74a43SLisandro DalcinIntType: dtype = _dtype('IntType') 45155a74a43SLisandro DalcinRealType: dtype = _dtype('RealType') 45255a74a43SLisandro DalcinComplexType: dtype = _dtype('ComplexType') 45355a74a43SLisandro DalcinScalarType: dtype = _dtype('ScalarType') 45455a74a43SLisandro Dalcin""" 45555a74a43SLisandro Dalcin 45655a74a43SLisandro DalcinHELPERS = """ 45755a74a43SLisandro Dalcinclass _Int(int): pass 45855a74a43SLisandro Dalcinclass _Str(str): pass 45955a74a43SLisandro Dalcinclass _Float(float): pass 46055a74a43SLisandro Dalcinclass _Dict(dict): pass 46155a74a43SLisandro Dalcin 46255a74a43SLisandro Dalcindef _repr(obj): 46355a74a43SLisandro Dalcin try: 46455a74a43SLisandro Dalcin return obj._name 46555a74a43SLisandro Dalcin except AttributeError: 46655a74a43SLisandro Dalcin return super(obj).__repr__() 46755a74a43SLisandro Dalcin 46855a74a43SLisandro Dalcindef _def(cls, name): 46955a74a43SLisandro Dalcin if cls is int: 47055a74a43SLisandro Dalcin cls = _Int 47155a74a43SLisandro Dalcin if cls is str: 47255a74a43SLisandro Dalcin cls = _Str 47355a74a43SLisandro Dalcin if cls is float: 47455a74a43SLisandro Dalcin cls = _Float 47555a74a43SLisandro Dalcin if cls is dict: 47655a74a43SLisandro Dalcin cls = _Dict 47755a74a43SLisandro Dalcin 47855a74a43SLisandro Dalcin obj = cls() 47955a74a43SLisandro Dalcin obj._name = name 48055a74a43SLisandro Dalcin if '__repr__' not in cls.__dict__: 48155a74a43SLisandro Dalcin cls.__repr__ = _repr 48255a74a43SLisandro Dalcin return obj 48355a74a43SLisandro Dalcin""" 48455a74a43SLisandro Dalcin 48555a74a43SLisandro DalcinOVERRIDE = { 48655a74a43SLisandro Dalcin} 48755a74a43SLisandro Dalcin 48855a74a43SLisandro DalcinTYPING = """ 48955a74a43SLisandro Dalcinfrom .typing import * 49055a74a43SLisandro Dalcin""" 49155a74a43SLisandro Dalcin 49255a74a43SLisandro Dalcin 49355a74a43SLisandro Dalcindef visit_petsc4py_PETSc(done=None): 49455a74a43SLisandro Dalcin from petsc4py import PETSc 49555a74a43SLisandro Dalcin lines = Lines() 49655a74a43SLisandro Dalcin lines.add = f'"""{PETSc.__doc__}"""' 49755a74a43SLisandro Dalcin lines.add = IMPORTS 49855a74a43SLisandro Dalcin lines.add = "" 49955a74a43SLisandro Dalcin lines.add = HELPERS 50055a74a43SLisandro Dalcin lines.add = "" 50155a74a43SLisandro Dalcin lines.add = visit_module(PETSc) 50255a74a43SLisandro Dalcin lines.add = "" 50355a74a43SLisandro Dalcin lines.add = TYPING 50455a74a43SLisandro Dalcin return lines 50555a74a43SLisandro Dalcin 50655a74a43SLisandro Dalcin 50755a74a43SLisandro Dalcindef generate(filename): 50855a74a43SLisandro Dalcin dirname = os.path.dirname(filename) 50955a74a43SLisandro Dalcin os.makedirs(dirname, exist_ok=True) 51055a74a43SLisandro Dalcin with open(filename, 'w') as f: 51155a74a43SLisandro Dalcin for line in visit_petsc4py_PETSc(): 51255a74a43SLisandro Dalcin print(line, file=f) 51355a74a43SLisandro Dalcin 51455a74a43SLisandro Dalcin 51555a74a43SLisandro Dalcindef load_module(filename, name=None): 51655a74a43SLisandro Dalcin if name is None: 51755a74a43SLisandro Dalcin name, _ = os.path.splitext( 51855a74a43SLisandro Dalcin os.path.basename(filename)) 51955a74a43SLisandro Dalcin module = type(sys)(name) 52055a74a43SLisandro Dalcin module.__file__ = filename 52155a74a43SLisandro Dalcin module.__package__ = name.rsplit('.', 1)[0] 52255a74a43SLisandro Dalcin old = replace_module(module) 52355a74a43SLisandro Dalcin with open(filename) as f: 52455a74a43SLisandro Dalcin exec(f.read(), module.__dict__) # noqa: S102 52555a74a43SLisandro Dalcin restore_module(old) 52655a74a43SLisandro Dalcin return module 52755a74a43SLisandro Dalcin 52855a74a43SLisandro Dalcin 52955a74a43SLisandro Dalcin_sys_modules = {} 53055a74a43SLisandro Dalcin 53155a74a43SLisandro Dalcin 53255a74a43SLisandro Dalcindef replace_module(module): 53355a74a43SLisandro Dalcin name = module.__name__ 53455a74a43SLisandro Dalcin assert name not in _sys_modules 53555a74a43SLisandro Dalcin _sys_modules[name] = sys.modules[name] 53655a74a43SLisandro Dalcin sys.modules[name] = module 53755a74a43SLisandro Dalcin return _sys_modules[name] 53855a74a43SLisandro Dalcin 53955a74a43SLisandro Dalcin 54055a74a43SLisandro Dalcindef restore_module(module): 54155a74a43SLisandro Dalcin name = module.__name__ 54255a74a43SLisandro Dalcin assert name in _sys_modules 54355a74a43SLisandro Dalcin sys.modules[name] = _sys_modules[name] 54455a74a43SLisandro Dalcin del _sys_modules[name] 54555a74a43SLisandro Dalcin 54655a74a43SLisandro Dalcin 54755a74a43SLisandro Dalcindef annotate(dest, source): 54855a74a43SLisandro Dalcin try: 54955a74a43SLisandro Dalcin dest.__annotations__ = source.__annotations__ 55055a74a43SLisandro Dalcin except AttributeError: 55155a74a43SLisandro Dalcin pass 55255a74a43SLisandro Dalcin if isinstance(dest, type): 55355a74a43SLisandro Dalcin for name in dest.__dict__.keys(): 55455a74a43SLisandro Dalcin if hasattr(source, name): 55555a74a43SLisandro Dalcin obj = getattr(dest, name) 55655a74a43SLisandro Dalcin annotate(obj, getattr(source, name)) 55755a74a43SLisandro Dalcin if isinstance(dest, type(sys)): 55855a74a43SLisandro Dalcin for name in dir(dest): 55955a74a43SLisandro Dalcin if hasattr(source, name): 56055a74a43SLisandro Dalcin obj = getattr(dest, name) 56155a74a43SLisandro Dalcin mod = getattr(obj, '__module__', None) 56255a74a43SLisandro Dalcin if dest.__name__ == mod: 56355a74a43SLisandro Dalcin annotate(obj, getattr(source, name)) 56455a74a43SLisandro Dalcin for name in dir(source): 56555a74a43SLisandro Dalcin if not hasattr(dest, name): 56655a74a43SLisandro Dalcin setattr(dest, name, getattr(source, name)) 56755a74a43SLisandro Dalcin 56855a74a43SLisandro Dalcin 56955a74a43SLisandro DalcinOUTDIR = 'reference' 57055a74a43SLisandro Dalcin 57155a74a43SLisandro Dalcinif __name__ == '__main__': 57255a74a43SLisandro Dalcin generate(os.path.join(OUTDIR, 'petsc4py.PETSc.py')) 573