diff --git a/generator/generate.py b/generator/generate.py index 5844f24..2c49a39 100755 --- a/generator/generate.py +++ b/generator/generate.py @@ -667,10 +667,13 @@ def check(self): self.dump() sys.stderr.write(self.docs + "\n") - def dump(self, indent_lvl=0): + def dump(self, indent_lvl=0, out=()): for _ in range(indent_lvl): sys.stderr.write(_INDENT_) - sys.stderr.write("%s (%s): %s\n" % (self.name, self.type, self.source)) + + t = "Out" if self.name in out else "" + sys.stderr.write("%s (%s): %s %s\n" % (self.name, self.type, self.source, t)) + for p in self.pars: p.dump(indent_lvl + 1, self.out) @@ -697,6 +700,8 @@ def docs_in_sphinx_format(self, first=0) -> str: r = [] v = [] block = None + block_is_params = False + last_param_name = None lines = self.base_sphinx_format(self.docs) @@ -709,6 +714,7 @@ def docs_in_sphinx_format(self, first=0) -> str: if block is None: indent = "" block = heads + block_is_params = False # Check whether there is a blonk line right before the @code line. # If not, add one (needed for sphinx to properly display the list). @@ -723,22 +729,35 @@ def docs_in_sphinx_format(self, first=0) -> str: i += 1 block.append("") + block = None + block_is_params = False elif ":param" in line: + last_param_name = line.split()[1] + if _OUT_ in line: line = line.replace(_PNTR_, "") - out.append(line.split()[1]) + out.append(last_param_name) + params.append(param_re.sub(r":param \g:", line)) + block = params + block_is_params = True elif ":return:" in line: r.append(line) + block = r + block_is_params = False elif ":version:" in line: v.append(line) + block = v + block_is_params = False elif ":bug:" in line: b.append(line) + block = b + block_is_params = False elif "@code" in line: # we are dealing with a code block # Check whether there is a blonk line right before the @code line. # If not, add one (needed for sphinx to properly display the code block). @@ -778,20 +797,30 @@ def docs_in_sphinx_format(self, first=0) -> str: heads.append(line.replace("@endcode", "").strip()) block = None + block_is_params = False elif ".. note::" in line: if i - 1 >= 0 and lines[i - 1]: heads.append("") + heads.append(line) + block = heads + block_is_params = False elif ".. warning::" in line: heads.append(line) + block = heads + block_is_params = False elif block is not None: + if block_is_params and _OUT_ in line: + out.append(last_param_name) + if line: block.append(_INDENT_ + line) else: block.append(line) block = None + block_is_params = False else: heads.append(line) @@ -2209,6 +2238,12 @@ def generate_funcs(self): for f in self.parser.funcs: name = f.name + # NOTE: `docs_in_sphinx_format` must be called before the `flags` method + # of `Par` instances, because it fills the `out` member (and other members) + # of the `Func`. If called after, `out` will be empty, resulting in missing + # out parameters in the bindings. + docs = self.add_sphinx_cross_refs(f.docs_in_sphinx_format()) + # make decorators for parameters that are function pointers pfs = {} for p in f.pars: @@ -2268,8 +2303,6 @@ def generate_funcs(self): types = ", ".join(types) - docs = self.add_sphinx_cross_refs(f.docs_in_sphinx_format()) - self.output(f"def {name}({args}):") self.generate_docstring(docs) self.output( @@ -2319,14 +2352,19 @@ def generate_func_pointer_decorator( """ indent = _INDENT_ * indent_lvl name = replacement_name if replacement_name else self.class4(pf.name) + + # NOTE: `docs_in_sphinx_format` must be called before the `flags` method + # of `Par` instances, because it fills the `out` member (and other members) + # of the `Func`. If called after, `out` will be empty, resulting in missing + # out parameters in the bindings. + docs = self.add_sphinx_cross_refs(pf.docs_in_sphinx_format()) + # return value and arg classes types = ", ".join( [self.class4(pf.type)] + [self.class4(p.type, p.flags(pf.out)[0]) for p in pf.pars] ) - docs = self.add_sphinx_cross_refs(pf.docs_in_sphinx_format()) - self.output(f"{indent}{name} = ctypes.CFUNCTYPE({types})") if docs: self.output(f"{indent}{name}.__doc__ = '''{docs}'''")