xref: /petsc/src/binding/petsc4py/conf/stubgen.py (revision 55a74a43bb44613d95e937906bec3b8c3581b432)
1*55a74a43SLisandro Dalcinimport os
2*55a74a43SLisandro Dalcinimport inspect
3*55a74a43SLisandro Dalcinimport textwrap
4*55a74a43SLisandro Dalcin
5*55a74a43SLisandro Dalcin
6*55a74a43SLisandro Dalcindef is_cyfunction(obj):
7*55a74a43SLisandro Dalcin    return type(obj).__name__ == 'cython_function_or_method'
8*55a74a43SLisandro Dalcin
9*55a74a43SLisandro Dalcin
10*55a74a43SLisandro Dalcindef is_function(obj):
11*55a74a43SLisandro Dalcin    return (
12*55a74a43SLisandro Dalcin        inspect.isbuiltin(obj)
13*55a74a43SLisandro Dalcin        or is_cyfunction(obj)
14*55a74a43SLisandro Dalcin        or type(obj) is type(ord)
15*55a74a43SLisandro Dalcin    )
16*55a74a43SLisandro Dalcin
17*55a74a43SLisandro Dalcin
18*55a74a43SLisandro Dalcindef is_method(obj):
19*55a74a43SLisandro Dalcin    return (
20*55a74a43SLisandro Dalcin        inspect.ismethoddescriptor(obj)
21*55a74a43SLisandro Dalcin        or inspect.ismethod(obj)
22*55a74a43SLisandro Dalcin        or is_cyfunction(obj)
23*55a74a43SLisandro Dalcin        or type(obj) in (
24*55a74a43SLisandro Dalcin            type(str.index),
25*55a74a43SLisandro Dalcin            type(str.__add__),
26*55a74a43SLisandro Dalcin            type(str.__new__),
27*55a74a43SLisandro Dalcin        )
28*55a74a43SLisandro Dalcin    )
29*55a74a43SLisandro Dalcin
30*55a74a43SLisandro Dalcin
31*55a74a43SLisandro Dalcindef is_classmethod(obj):
32*55a74a43SLisandro Dalcin    return (
33*55a74a43SLisandro Dalcin        inspect.isbuiltin(obj)
34*55a74a43SLisandro Dalcin        or type(obj).__name__ in (
35*55a74a43SLisandro Dalcin            'classmethod',
36*55a74a43SLisandro Dalcin            'classmethod_descriptor',
37*55a74a43SLisandro Dalcin        )
38*55a74a43SLisandro Dalcin    )
39*55a74a43SLisandro Dalcin
40*55a74a43SLisandro Dalcin
41*55a74a43SLisandro Dalcindef is_staticmethod(obj):
42*55a74a43SLisandro Dalcin    return (
43*55a74a43SLisandro Dalcin        type(obj).__name__ in (
44*55a74a43SLisandro Dalcin            'staticmethod',
45*55a74a43SLisandro Dalcin        )
46*55a74a43SLisandro Dalcin    )
47*55a74a43SLisandro Dalcin
48*55a74a43SLisandro Dalcin
49*55a74a43SLisandro Dalcindef is_constant(obj):
50*55a74a43SLisandro Dalcin    return isinstance(obj, (int, float, str))
51*55a74a43SLisandro Dalcin
52*55a74a43SLisandro Dalcin
53*55a74a43SLisandro Dalcindef is_datadescr(obj):
54*55a74a43SLisandro Dalcin    return inspect.isdatadescriptor(obj) and not hasattr(obj, 'fget')
55*55a74a43SLisandro Dalcin
56*55a74a43SLisandro Dalcin
57*55a74a43SLisandro Dalcindef is_property(obj):
58*55a74a43SLisandro Dalcin    return inspect.isdatadescriptor(obj) and hasattr(obj, 'fget')
59*55a74a43SLisandro Dalcin
60*55a74a43SLisandro Dalcin
61*55a74a43SLisandro Dalcindef is_class(obj):
62*55a74a43SLisandro Dalcin    return inspect.isclass(obj) or type(obj) is type(int)
63*55a74a43SLisandro Dalcin
64*55a74a43SLisandro Dalcin
65*55a74a43SLisandro Dalcinclass Lines(list):
66*55a74a43SLisandro Dalcin
67*55a74a43SLisandro Dalcin    INDENT = " " * 4
68*55a74a43SLisandro Dalcin    level = 0
69*55a74a43SLisandro Dalcin
70*55a74a43SLisandro Dalcin    @property
71*55a74a43SLisandro Dalcin    def add(self):
72*55a74a43SLisandro Dalcin        return self
73*55a74a43SLisandro Dalcin
74*55a74a43SLisandro Dalcin    @add.setter
75*55a74a43SLisandro Dalcin    def add(self, lines):
76*55a74a43SLisandro Dalcin        if lines is None:
77*55a74a43SLisandro Dalcin            return
78*55a74a43SLisandro Dalcin        if isinstance(lines, str):
79*55a74a43SLisandro Dalcin            lines = textwrap.dedent(lines).strip().split("\n")
80*55a74a43SLisandro Dalcin        indent = self.INDENT * self.level
81*55a74a43SLisandro Dalcin        for line in lines:
82*55a74a43SLisandro Dalcin            self.append(indent + line)
83*55a74a43SLisandro Dalcin
84*55a74a43SLisandro Dalcin
85*55a74a43SLisandro Dalcindef signature(obj):
86*55a74a43SLisandro Dalcin    doc = obj.__doc__
87*55a74a43SLisandro Dalcin    doc = doc or f"{obj.__name__}: Any"  # FIXME remove line
88*55a74a43SLisandro Dalcin    sig = doc.split('\n', 1)[0].split('.', 1)[-1]
89*55a74a43SLisandro Dalcin    return sig or None
90*55a74a43SLisandro Dalcin
91*55a74a43SLisandro Dalcindef visit_constant(constant):
92*55a74a43SLisandro Dalcin    name, value = constant
93*55a74a43SLisandro Dalcin    return f"{name}: Final[{type(value).__name__}] = ..."
94*55a74a43SLisandro Dalcin
95*55a74a43SLisandro Dalcin
96*55a74a43SLisandro Dalcindef visit_function(function):
97*55a74a43SLisandro Dalcin    sig = signature(function)
98*55a74a43SLisandro Dalcin    return f"def {sig}: ..."
99*55a74a43SLisandro Dalcin
100*55a74a43SLisandro Dalcin
101*55a74a43SLisandro Dalcindef visit_method(method):
102*55a74a43SLisandro Dalcin    sig = signature(method)
103*55a74a43SLisandro Dalcin    return f"def {sig}: ..."
104*55a74a43SLisandro Dalcin
105*55a74a43SLisandro Dalcin
106*55a74a43SLisandro Dalcindef visit_datadescr(datadescr):
107*55a74a43SLisandro Dalcin    sig = signature(datadescr)
108*55a74a43SLisandro Dalcin    return f"{sig}"
109*55a74a43SLisandro Dalcin
110*55a74a43SLisandro Dalcin
111*55a74a43SLisandro Dalcindef visit_property(prop, name=None):
112*55a74a43SLisandro Dalcin    sig = signature(prop.fget)
113*55a74a43SLisandro Dalcin    pname = name or prop.fget.__name__
114*55a74a43SLisandro Dalcin    ptype = sig.rsplit('->', 1)[-1].strip()
115*55a74a43SLisandro Dalcin    return f"{pname}: {ptype}"
116*55a74a43SLisandro Dalcin
117*55a74a43SLisandro Dalcin
118*55a74a43SLisandro Dalcindef visit_constructor(cls, name='__init__', args=None):
119*55a74a43SLisandro Dalcin    init = (name == '__init__')
120*55a74a43SLisandro Dalcin    argname = cls.__name__.lower()
121*55a74a43SLisandro Dalcin    argtype = cls.__name__
122*55a74a43SLisandro Dalcin    initarg = args or f"{argname}: Optional[{argtype}] = None"
123*55a74a43SLisandro Dalcin    selfarg = 'self' if init else 'cls'
124*55a74a43SLisandro Dalcin    rettype = 'None' if init else argtype
125*55a74a43SLisandro Dalcin    arglist = f"{selfarg}, {initarg}"
126*55a74a43SLisandro Dalcin    sig = f"{name}({arglist}) -> {rettype}"
127*55a74a43SLisandro Dalcin    return f"def {sig}: ..."
128*55a74a43SLisandro Dalcin
129*55a74a43SLisandro Dalcindef visit_class(cls, outer=None, done=None):
130*55a74a43SLisandro Dalcin    skip = {
131*55a74a43SLisandro Dalcin        '__doc__',
132*55a74a43SLisandro Dalcin        '__dict__',
133*55a74a43SLisandro Dalcin        '__module__',
134*55a74a43SLisandro Dalcin        '__weakref__',
135*55a74a43SLisandro Dalcin        '__pyx_vtable__',
136*55a74a43SLisandro Dalcin        '__enum2str',  # FIXME refactor implemetation
137*55a74a43SLisandro Dalcin        '_traceback_', # FIXME maybe refactor?
138*55a74a43SLisandro Dalcin        '__lt__',
139*55a74a43SLisandro Dalcin        '__le__',
140*55a74a43SLisandro Dalcin        '__ge__',
141*55a74a43SLisandro Dalcin        '__gt__',
142*55a74a43SLisandro Dalcin    }
143*55a74a43SLisandro Dalcin    special = {
144*55a74a43SLisandro Dalcin        '__len__':   "__len__(self) -> int",
145*55a74a43SLisandro Dalcin        '__bool__':  "__bool__(self) -> bool",
146*55a74a43SLisandro Dalcin        '__hash__':  "__hash__(self) -> int",
147*55a74a43SLisandro Dalcin        '__int__':   "__int__(self) -> int",
148*55a74a43SLisandro Dalcin        '__index__': "__int__(self) -> int",
149*55a74a43SLisandro Dalcin        '__str__':   "__str__(self) -> str",
150*55a74a43SLisandro Dalcin        '__repr__':  "__repr__(self) -> str",
151*55a74a43SLisandro Dalcin        '__eq__':    "__eq__(self, other: object) -> bool",
152*55a74a43SLisandro Dalcin        '__ne__':    "__ne__(self, other: object) -> bool",
153*55a74a43SLisandro Dalcin    }
154*55a74a43SLisandro Dalcin    constructor = (
155*55a74a43SLisandro Dalcin        '__new__',
156*55a74a43SLisandro Dalcin        '__init__',
157*55a74a43SLisandro Dalcin    )
158*55a74a43SLisandro Dalcin
159*55a74a43SLisandro Dalcin    qualname = cls.__name__
160*55a74a43SLisandro Dalcin    cls_name = cls.__name__
161*55a74a43SLisandro Dalcin    if outer is not None and cls_name.startswith(outer):
162*55a74a43SLisandro Dalcin        cls_name = cls_name[len(outer):]
163*55a74a43SLisandro Dalcin        qualname = f"{outer}.{cls_name}"
164*55a74a43SLisandro Dalcin
165*55a74a43SLisandro Dalcin    override = OVERRIDE.get(qualname, {})
166*55a74a43SLisandro Dalcin    done = set() if done is None else done
167*55a74a43SLisandro Dalcin    lines = Lines()
168*55a74a43SLisandro Dalcin
169*55a74a43SLisandro Dalcin    try:
170*55a74a43SLisandro Dalcin        class sub(cls):
171*55a74a43SLisandro Dalcin            pass
172*55a74a43SLisandro Dalcin        final = False
173*55a74a43SLisandro Dalcin    except TypeError:
174*55a74a43SLisandro Dalcin        final = True
175*55a74a43SLisandro Dalcin    if final:
176*55a74a43SLisandro Dalcin        lines.add = "@final"
177*55a74a43SLisandro Dalcin    base = cls.__base__
178*55a74a43SLisandro Dalcin    if base is object:
179*55a74a43SLisandro Dalcin        lines.add = f"class {cls_name}:"
180*55a74a43SLisandro Dalcin    else:
181*55a74a43SLisandro Dalcin        lines.add = f"class {cls_name}({base.__name__}):"
182*55a74a43SLisandro Dalcin    lines.level += 1
183*55a74a43SLisandro Dalcin    start = len(lines)
184*55a74a43SLisandro Dalcin
185*55a74a43SLisandro Dalcin    for name in constructor:
186*55a74a43SLisandro Dalcin        if name in cls.__dict__:
187*55a74a43SLisandro Dalcin            done.add(name)
188*55a74a43SLisandro Dalcin
189*55a74a43SLisandro Dalcin    if '__hash__' in cls.__dict__:
190*55a74a43SLisandro Dalcin        if cls.__hash__ is None:
191*55a74a43SLisandro Dalcin            done.add('__hash__')
192*55a74a43SLisandro Dalcin
193*55a74a43SLisandro Dalcin    dct = cls.__dict__
194*55a74a43SLisandro Dalcin    keys = list(dct.keys())
195*55a74a43SLisandro Dalcin
196*55a74a43SLisandro Dalcin    def dunder(name):
197*55a74a43SLisandro Dalcin        return name.startswith('__') and name.endswith('__')
198*55a74a43SLisandro Dalcin
199*55a74a43SLisandro Dalcin    def members(seq):
200*55a74a43SLisandro Dalcin        for name in seq:
201*55a74a43SLisandro Dalcin            if name in skip:
202*55a74a43SLisandro Dalcin                continue
203*55a74a43SLisandro Dalcin            if name in done:
204*55a74a43SLisandro Dalcin                continue
205*55a74a43SLisandro Dalcin            if dunder(name):
206*55a74a43SLisandro Dalcin                if name not in special and name not in override:
207*55a74a43SLisandro Dalcin                    done.add(name)
208*55a74a43SLisandro Dalcin                    continue
209*55a74a43SLisandro Dalcin            yield name
210*55a74a43SLisandro Dalcin
211*55a74a43SLisandro Dalcin    for name in members(keys):
212*55a74a43SLisandro Dalcin        attr = getattr(cls, name)
213*55a74a43SLisandro Dalcin        if is_class(attr):
214*55a74a43SLisandro Dalcin            done.add(name)
215*55a74a43SLisandro Dalcin            lines.add = visit_class(attr, outer=cls_name)
216*55a74a43SLisandro Dalcin            continue
217*55a74a43SLisandro Dalcin
218*55a74a43SLisandro Dalcin    for name in members(keys):
219*55a74a43SLisandro Dalcin
220*55a74a43SLisandro Dalcin        if name in override:
221*55a74a43SLisandro Dalcin            done.add(name)
222*55a74a43SLisandro Dalcin            lines.add = override[name]
223*55a74a43SLisandro Dalcin            continue
224*55a74a43SLisandro Dalcin
225*55a74a43SLisandro Dalcin        if name in special:
226*55a74a43SLisandro Dalcin            done.add(name)
227*55a74a43SLisandro Dalcin            sig = special[name]
228*55a74a43SLisandro Dalcin            lines.add = f"def {sig}: ..."
229*55a74a43SLisandro Dalcin            continue
230*55a74a43SLisandro Dalcin
231*55a74a43SLisandro Dalcin        attr = getattr(cls, name)
232*55a74a43SLisandro Dalcin
233*55a74a43SLisandro Dalcin        if is_method(attr):
234*55a74a43SLisandro Dalcin            done.add(name)
235*55a74a43SLisandro Dalcin            if name == attr.__name__:
236*55a74a43SLisandro Dalcin                obj = dct[name]
237*55a74a43SLisandro Dalcin                if is_classmethod(obj):
238*55a74a43SLisandro Dalcin                    lines.add = "@classmethod"
239*55a74a43SLisandro Dalcin                elif is_staticmethod(obj):
240*55a74a43SLisandro Dalcin                    lines.add = "@staticmethod"
241*55a74a43SLisandro Dalcin                lines.add = visit_method(attr)
242*55a74a43SLisandro Dalcin            elif True:
243*55a74a43SLisandro Dalcin                lines.add = f"{name} = {attr.__name__}"
244*55a74a43SLisandro Dalcin            continue
245*55a74a43SLisandro Dalcin
246*55a74a43SLisandro Dalcin        if is_datadescr(attr):
247*55a74a43SLisandro Dalcin            done.add(name)
248*55a74a43SLisandro Dalcin            lines.add = visit_datadescr(attr)
249*55a74a43SLisandro Dalcin            continue
250*55a74a43SLisandro Dalcin
251*55a74a43SLisandro Dalcin        if is_property(attr):
252*55a74a43SLisandro Dalcin            done.add(name)
253*55a74a43SLisandro Dalcin            lines.add = visit_property(attr, name)
254*55a74a43SLisandro Dalcin            continue
255*55a74a43SLisandro Dalcin
256*55a74a43SLisandro Dalcin        if is_constant(attr):
257*55a74a43SLisandro Dalcin            done.add(name)
258*55a74a43SLisandro Dalcin            lines.add = visit_constant((name, attr))
259*55a74a43SLisandro Dalcin            continue
260*55a74a43SLisandro Dalcin
261*55a74a43SLisandro Dalcin    leftovers = [name for name in keys if
262*55a74a43SLisandro Dalcin                 name not in done and name not in skip]
263*55a74a43SLisandro Dalcin    if leftovers:
264*55a74a43SLisandro Dalcin        raise RuntimeError(f"leftovers: {leftovers}")
265*55a74a43SLisandro Dalcin
266*55a74a43SLisandro Dalcin    if len(lines) == start:
267*55a74a43SLisandro Dalcin        lines.add = "pass"
268*55a74a43SLisandro Dalcin    lines.level -= 1
269*55a74a43SLisandro Dalcin    return lines
270*55a74a43SLisandro Dalcin
271*55a74a43SLisandro Dalcin
272*55a74a43SLisandro Dalcindef visit_module(module, done=None):
273*55a74a43SLisandro Dalcin    skip = {
274*55a74a43SLisandro Dalcin        '__doc__',
275*55a74a43SLisandro Dalcin        '__name__',
276*55a74a43SLisandro Dalcin        '__loader__',
277*55a74a43SLisandro Dalcin        '__spec__',
278*55a74a43SLisandro Dalcin        '__file__',
279*55a74a43SLisandro Dalcin        '__package__',
280*55a74a43SLisandro Dalcin        '__builtins__',
281*55a74a43SLisandro Dalcin        '__pyx_unpickle_Enum',  # FIXME review
282*55a74a43SLisandro Dalcin    }
283*55a74a43SLisandro Dalcin
284*55a74a43SLisandro Dalcin    done = set() if done is None else done
285*55a74a43SLisandro Dalcin    lines = Lines()
286*55a74a43SLisandro Dalcin
287*55a74a43SLisandro Dalcin    keys = list(module.__dict__.keys())
288*55a74a43SLisandro Dalcin    keys.sort(key=lambda name: name.startswith("_"))
289*55a74a43SLisandro Dalcin
290*55a74a43SLisandro Dalcin    constants = [
291*55a74a43SLisandro Dalcin        (name, getattr(module, name)) for name in keys
292*55a74a43SLisandro Dalcin        if all((
293*55a74a43SLisandro Dalcin            name not in done and name not in skip,
294*55a74a43SLisandro Dalcin            isinstance(getattr(module, name), int),
295*55a74a43SLisandro Dalcin        ))
296*55a74a43SLisandro Dalcin    ]
297*55a74a43SLisandro Dalcin    for name, value in constants:
298*55a74a43SLisandro Dalcin        done.add(name)
299*55a74a43SLisandro Dalcin        if name in OVERRIDE:
300*55a74a43SLisandro Dalcin            lines.add = OVERRIDE[name]
301*55a74a43SLisandro Dalcin        else:
302*55a74a43SLisandro Dalcin            lines.add = visit_constant((name, value))
303*55a74a43SLisandro Dalcin    if constants:
304*55a74a43SLisandro Dalcin        lines.add = ""
305*55a74a43SLisandro Dalcin
306*55a74a43SLisandro Dalcin    for name in keys:
307*55a74a43SLisandro Dalcin        if name in done or name in skip:
308*55a74a43SLisandro Dalcin            continue
309*55a74a43SLisandro Dalcin        value = getattr(module, name)
310*55a74a43SLisandro Dalcin
311*55a74a43SLisandro Dalcin        if is_class(value):
312*55a74a43SLisandro Dalcin            done.add(name)
313*55a74a43SLisandro Dalcin            if value.__module__ != module.__name__:
314*55a74a43SLisandro Dalcin                continue
315*55a74a43SLisandro Dalcin            lines.add = visit_class(value)
316*55a74a43SLisandro Dalcin            lines.add = ""
317*55a74a43SLisandro Dalcin            instances = [
318*55a74a43SLisandro Dalcin                (k, getattr(module, k)) for k in keys
319*55a74a43SLisandro Dalcin                if all((
320*55a74a43SLisandro Dalcin                    k not in done and k not in skip,
321*55a74a43SLisandro Dalcin                    type(getattr(module, k)) is value,
322*55a74a43SLisandro Dalcin                ))
323*55a74a43SLisandro Dalcin            ]
324*55a74a43SLisandro Dalcin            for attrname, attrvalue in instances:
325*55a74a43SLisandro Dalcin                done.add(attrname)
326*55a74a43SLisandro Dalcin                lines.add = visit_constant((attrname, attrvalue))
327*55a74a43SLisandro Dalcin            if instances:
328*55a74a43SLisandro Dalcin                lines.add = ""
329*55a74a43SLisandro Dalcin            continue
330*55a74a43SLisandro Dalcin
331*55a74a43SLisandro Dalcin        if is_function(value):
332*55a74a43SLisandro Dalcin            done.add(name)
333*55a74a43SLisandro Dalcin            if name == value.__name__:
334*55a74a43SLisandro Dalcin                lines.add = visit_function(value)
335*55a74a43SLisandro Dalcin            else:
336*55a74a43SLisandro Dalcin                lines.add = f"{name} = {value.__name__}"
337*55a74a43SLisandro Dalcin            continue
338*55a74a43SLisandro Dalcin
339*55a74a43SLisandro Dalcin    lines.add = ""
340*55a74a43SLisandro Dalcin    for name in keys:
341*55a74a43SLisandro Dalcin        if name in done or name in skip:
342*55a74a43SLisandro Dalcin            continue
343*55a74a43SLisandro Dalcin        value = getattr(module, name)
344*55a74a43SLisandro Dalcin        done.add(name)
345*55a74a43SLisandro Dalcin        if name in OVERRIDE:
346*55a74a43SLisandro Dalcin            lines.add = OVERRIDE[name]
347*55a74a43SLisandro Dalcin        else:
348*55a74a43SLisandro Dalcin            lines.add = visit_constant((name, value))
349*55a74a43SLisandro Dalcin
350*55a74a43SLisandro Dalcin    leftovers = [name for name in keys if
351*55a74a43SLisandro Dalcin                 name not in done and name not in skip]
352*55a74a43SLisandro Dalcin    if leftovers:
353*55a74a43SLisandro Dalcin        raise RuntimeError(f"leftovers: {leftovers}")
354*55a74a43SLisandro Dalcin    return lines
355*55a74a43SLisandro Dalcin
356*55a74a43SLisandro Dalcin
357*55a74a43SLisandro DalcinIMPORTS = """
358*55a74a43SLisandro Dalcinfrom __future__ import annotations
359*55a74a43SLisandro Dalcinimport sys
360*55a74a43SLisandro Dalcinfrom threading import Lock
361*55a74a43SLisandro Dalcinfrom typing import (
362*55a74a43SLisandro Dalcin    Any,
363*55a74a43SLisandro Dalcin    Union,
364*55a74a43SLisandro Dalcin    Optional,
365*55a74a43SLisandro Dalcin    NoReturn,
366*55a74a43SLisandro Dalcin    overload,
367*55a74a43SLisandro Dalcin)
368*55a74a43SLisandro Dalcinif sys.version_info >= (3, 8):
369*55a74a43SLisandro Dalcin    from typing import (
370*55a74a43SLisandro Dalcin        final,
371*55a74a43SLisandro Dalcin        Final,
372*55a74a43SLisandro Dalcin        Literal,
373*55a74a43SLisandro Dalcin    )
374*55a74a43SLisandro Dalcinelse:
375*55a74a43SLisandro Dalcin    from typing_extensions import (
376*55a74a43SLisandro Dalcin        final,
377*55a74a43SLisandro Dalcin        Final,
378*55a74a43SLisandro Dalcin        Literal,
379*55a74a43SLisandro Dalcin    )
380*55a74a43SLisandro Dalcinif sys.version_info >= (3, 9):
381*55a74a43SLisandro Dalcin    from collections.abc import (
382*55a74a43SLisandro Dalcin        Callable,
383*55a74a43SLisandro Dalcin        Hashable,
384*55a74a43SLisandro Dalcin        Iterable,
385*55a74a43SLisandro Dalcin        Iterator,
386*55a74a43SLisandro Dalcin        Sequence,
387*55a74a43SLisandro Dalcin        Mapping,
388*55a74a43SLisandro Dalcin    )
389*55a74a43SLisandro Dalcinelse:
390*55a74a43SLisandro Dalcin    from typing import (
391*55a74a43SLisandro Dalcin        Callable,
392*55a74a43SLisandro Dalcin        Hashable,
393*55a74a43SLisandro Dalcin        Iterable,
394*55a74a43SLisandro Dalcin        Iterator,
395*55a74a43SLisandro Dalcin        Sequence,
396*55a74a43SLisandro Dalcin        Mapping,
397*55a74a43SLisandro Dalcin    )
398*55a74a43SLisandro Dalcinif sys.version_info >= (3, 11):
399*55a74a43SLisandro Dalcin    from typing import Self
400*55a74a43SLisandro Dalcinelse:
401*55a74a43SLisandro Dalcin    from typing_extensions import Self
402*55a74a43SLisandro Dalcinfrom os import PathLike
403*55a74a43SLisandro Dalcin
404*55a74a43SLisandro Dalcinimport numpy
405*55a74a43SLisandro Dalcin
406*55a74a43SLisandro DalcinIntType: numpy.dtype = ...
407*55a74a43SLisandro DalcinRealType: numpy.dtype = ...
408*55a74a43SLisandro DalcinComplexType: numpy.dtype = ...
409*55a74a43SLisandro DalcinScalarType: numpy.dtype = ...
410*55a74a43SLisandro Dalcin"""
411*55a74a43SLisandro Dalcin
412*55a74a43SLisandro DalcinOVERRIDE = {
413*55a74a43SLisandro Dalcin    'Error': {
414*55a74a43SLisandro Dalcin    },
415*55a74a43SLisandro Dalcin    '__pyx_capi__': "__pyx_capi__: Final[Dict[str, Any]] = ...",
416*55a74a43SLisandro Dalcin    '__type_registry__': "__type_registry__: Final[Dict[int, type[Object]]] = ...",
417*55a74a43SLisandro Dalcin}
418*55a74a43SLisandro Dalcin
419*55a74a43SLisandro DalcinTYPING = """
420*55a74a43SLisandro Dalcin"""
421*55a74a43SLisandro Dalcin
422*55a74a43SLisandro Dalcin
423*55a74a43SLisandro Dalcindef visit_petsc4py_PETSc(done=None):
424*55a74a43SLisandro Dalcin    from petsc4py import PETSc as module
425*55a74a43SLisandro Dalcin    lines = Lines()
426*55a74a43SLisandro Dalcin    lines.add = IMPORTS
427*55a74a43SLisandro Dalcin    lines.add = ""
428*55a74a43SLisandro Dalcin    lines.add = visit_module(module)
429*55a74a43SLisandro Dalcin    lines.add = TYPING
430*55a74a43SLisandro Dalcin    return lines
431*55a74a43SLisandro Dalcin
432*55a74a43SLisandro Dalcin
433*55a74a43SLisandro Dalcindef generate(filename):
434*55a74a43SLisandro Dalcin    dirname = os.path.dirname(filename)
435*55a74a43SLisandro Dalcin    os.makedirs(dirname, exist_ok=True)
436*55a74a43SLisandro Dalcin    with open(filename, 'w') as f:
437*55a74a43SLisandro Dalcin        for line in visit_petsc4py_PETSc():
438*55a74a43SLisandro Dalcin            print(line, file=f)
439*55a74a43SLisandro Dalcin
440*55a74a43SLisandro Dalcin
441*55a74a43SLisandro DalcinOUTDIR = os.path.join('src', 'petsc4py')
442*55a74a43SLisandro Dalcin
443*55a74a43SLisandro Dalcinif __name__ == '__main__':
444*55a74a43SLisandro Dalcin    generate(os.path.join(OUTDIR, 'PETSc.pyi'))
445