pybind11-stubgen
pybind11-stubgen copied to clipboard
Sorting is causing parent-child relationships to be defined out of order
When I run pybind11-stubgen, I see ouput:
class SimpleSetupArrayOutput(SimpleSetupEntity):
def getDataType(self) -> DATA_TYPE:
...
class SimpleSetupEntity:
def getName(self) -> str:
...
This is out of order because the SimpleSetupArrayOutput is a subclass of SimpleSetupEntity and this causes linting errors. Is there a way to turn off sorting? Or is it possible to sort and then reorder as necessary?
I have this problem as well. The generated classes look like:
class BusyError(Error):
pass
class Error(Exception):
pass
I have the same issue with mixing classes that I define in the right order - but stubgen outputs them alphabetically, which breaks then exactly as the two examples above: https://github.com/ECP-WarpX/impactx/blob/2c97164cc687cacc6ba058482a93c1e1f0bf7ca9/src/python/elements.cpp#L143-L277
@sizmailov Can we disable sorting somehow? I am running tools like ruff on my generated files anyway :)
As a quick hack, I tried to remove the sorted() for classes in printer.py but it looks like the class sorting stays the same right now. It looks like the classes are stored in a List, thus I do not yet understand where the sorting comes in.
I modified the inheritance test in #238 as a demo but am not sure how to fix the issue yet :)
Ok, if I append reverse=True to this line, then it changes the sorting:
https://github.com/sizmailov/pybind11-stubgen/blob/cf58aa6c7f0655c2f830b6964aa48baff868b891/pybind11_stubgen/printer.py#L228
If I just remove the sorted() altogether then it is still sorting the classes alphabetically, so there must be an earlier sort of some kind happening for module.classes.
I think the issue might be that parse.py uses inspect.getmembers to get the members of a module and that one is sorted alphabetically.
After some Google & LLM queries, we could use the ast module instead to query and preserve order.
@ax3l cited these lines in printer.py:
https://github.com/sizmailov/pybind11-stubgen/blob/cf58aa6c7f0655c2f830b6964aa48baff868b891/pybind11_stubgen/printer.py#L228
To fix this (at least for my case), I performed a topological sort of the classes. I sort the class names because the Class type is not hashable.
import graphlib
import itertools
sorted_names = list(
graphlib.TopologicalSorter(
{c.name: set(itertools.chain.from_iterable(c.bases)) for c in module.classes}
).static_order()
)
# Use `filter` to drop `None` values returned when a base is outside the collection.
sorted_classes = filter(lambda c: c, map({c.name: c for c in module.classes}.get, sorted_names))
for class_ in sorted_classes:
result.extend(self.print_class(class_))
(Inheritance relationships should form a DAG, so I think this topological sort should generally succeed.)