networkx icon indicating copy to clipboard operation
networkx copied to clipboard

Making not_implemented_for decorator depend on dispatchable functions for non-nx graphs

Open amcandio opened this issue 7 months ago • 2 comments

This PR is a follow up from https://github.com/networkx/networkx/issues/8030. It makes nx.is_multigraph and nx.is_directed function dispatchable so its behavior can be modified by custom backends. In addition to this, it makes not_implemented_for decorator depend on nx.is_multigraph and nx.is_directed. The change allows backends graph class to not be forced to implement is_directed and is_multigraph methods, they just need to define its custom behavior based on the new dispatchable functions.

Previous approach remains the recommended way and not_implemented_for decorator will first attempt to use graph methods is_directed and is_multigraph. Fallback to top-level nx.is_directed and nx.is_multigraph only happens if the graph object functions are not present. This avoids calling the dispatchable NetworkX functions, which might not be implemented for some backends and could trigger unnecessary conversions to NetworkX graphs.

amcandio avatar May 10 '25 06:05 amcandio

@eriknw @dschult any change you can take a look at this small one? This should remove the limitation/restriction for backend graph types to implement is_directed and is_multigraph

amcandio avatar May 13 '25 13:05 amcandio

IIUC, this is basically "moving" the requirement for is_directed and is_multigraph from methods on the backend graph class to functions in the backend. From the perspective of the backend implementer I don't see how this changes much - no matter what, I have to have an is_directed and is_multigraph method/function in order to get past the not_implemented_for decorator, right?

In other words - if a backend implementer follows the current recommendation (that their backend graph object implements a is_directed and is_multigraph method) then everthing currently works, correct?

Sorry @rossbar I missed this comment! What I am trying to do here is to pass a class that is not defined in my code but in an external library. For example, my backend class is PyGraph from rustworkx.

I was able to fix it by monkey patching the external library to have this method but I'd prefer to not need that. Also, other classes might not admit patching in case the user wants to use built-in types for dispatching. For example, if you want nerworkx to work directly from dicts or strings.

amcandio avatar Jul 29 '25 16:07 amcandio