Repository: networkx/networkx

Issue:
simple_cycles attempts to import multiple libraries on every call
<!-- If you have a general question about NetworkX, please use the discussions tab to create a new discussion -->

<!--- Provide a general summary of the issue in the Title above -->

### Current Behavior

Calling [nx.simple_cycles](https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.cycles.simple_cycles.html) produces multiple ImportWarnings when pandas/numpy/scipy is not installed:
```
/usr/local/lib/python3.11/site-packages/networkx/convert.py:136: ImportWarning: pandas not found, skipping conversion test.
  warnings.warn("pandas not found, skipping conversion test.", ImportWarning)
/usr/local/lib/python3.11/site-packages/networkx/convert.py:150: ImportWarning: numpy not found, skipping conversion test.
  warnings.warn("numpy not found, skipping conversion test.", ImportWarning)
/usr/local/lib/python3.11/site-packages/networkx/convert.py:164: ImportWarning: scipy not found, skipping conversion test.
  warnings.warn("scipy not found, skipping conversion test.", ImportWarning)
```

This happens every time `simple_cycles` is called. The warnings come the method `convert.to_networkx_graph`, which appears in DiGraph's constructor when called from [here](https://github.com/networkx/networkx/blob/main/networkx/algorithms/cycles.py#L220)

Problems with this:
- **Warnings polluted**: If logs are configured to show warnings, they get very polluted with these warnings. On pytest, for example, warnings are enabled, so they pollute the logs.
- **Import attempts on every call**: Every time `simple_cycles` is called, multiple `import` instructions are called, which is slow. Does it make sense to try importing these libs on every `to_networkx_graph` call? Or can that be done just once? See a sample code below with a profile:

The following code reproduces the issue: Calling `simple_cycles` 1000 times with warnings enabled:
`graph.py`:
```
import warnings
import networkx as nx

warnings.simplefilter('always', Warning)

for _ in range(1000):
    edges = [
        ("A", "B"),
        ("B", "C"),
        ("C", "D"),
        ("D", "B"),
    ]
    graph = nx.DiGraph(edges)   # << warnings appear once here
    cycles = list(nx.simple_cycles(graph))   # <<< and another time here
    print(cycles)
```

`python -m cProfile -s cumulative graph.py`
```
         2890844 function calls (2879132 primitive calls) in 1.228 seconds

   Ordered by: cumulative time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        2    0.005    0.002    1.229    0.615 graph.py:1(<module>)
    358/1    0.002    0.000    1.228    1.228 {built-in method builtins.exec}
     3000    0.007    0.000    0.958    0.000 digraph.py:316(__init__)
     2000    0.015    0.000    0.949    0.000 convert.py:34(to_networkx_graph)
6374/6001    0.017    0.000    0.871    0.000 <frozen importlib._bootstrap>:1165(_find_and_load)
6373/6001    0.009    0.000    0.806    0.000 <frozen importlib._bootstrap>:1120(_find_and_load_unlocked)
     6369    0.027    0.000    0.706    0.000 <frozen importlib._bootstrap>:1054(_find_spec)
     6367    0.004    0.000    0.638    0.000 <frozen importlib._bootstrap_external>:1496(find_spec)
     6367    0.046    0.000    0.634    0.000 <frozen importlib._bootstrap_external>:1464(_get_spec)
     2000    0.005    0.000    0.626    0.000 cycles.py:104(simple_cycles)
```
From 1000 calls to `simple_cycles` there are 6000 import attempts and it took ~90% of the total execution time.


I would also like to mention that this may not be exclusive to `simple_cycle` method, since the warnings/imports happen on any usage of `nx.DiGraph(incoming_graph_data)` where incoming_graph_data is a list or iterator, but I understand this is expected because it has to guess. However, I wouldn't expect this guessing to happen internally on simple_cycle calls, because unlike with the construction of my nx.DiGraph, I have no way of controlling it.
```
    edges = [
        ("A", "B"),
        ("B", "C"),
        ("C", "D"),
        ("D", "B"),
    ]
    nx.DiGraph((u, v) for u, v in edges)
```

<!--- Tell us what happens instead of the expected behavior -->

### Expected Behavior

Warnings and imports should happen at most one time, both for logging purposes and execution time.


### Steps to Reproduce

<!--- Provide a minimal example that reproduces the bug -->
See graph.py above

### Environment

<!--- Please provide details about your local environment -->

Python version: 3.11.9
NetworkX version: 3.3

### Additional context

<!--- Add any other context about the problem here, screenshots, etc. -->



Discussion:
A quick bit of context - this is not related to the recent nx v3.3 release. This behavior (i.e. ImportWarnings on soft dependencies when the warnings filter is turned all the way up) has always been around. That's not to say it shouldn't be changed insofar as possible, just that it's not related to the recent release!
Do we need the warnings in `to_networkx_graph`?

I think the warnings were intended to help a user who didn't realize that they had forgotten to install e.g. pandas in their environment. That they input a pandas DataFrame but didn't have pandas installed.  But it seems like that case is not possible. If `pandas` is not installed, how could the user get a pandas object to input? 

Is there a way for users to input an object intended for the pandas conversion code and not have pandas installed?

If not, is there any danger in replacing the warnings with `pass`?
We should also update the docstring for [nx.simple_cycles](https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.cycles.simple_cycles.html). It currently states:
```
    Parameters
    ----------
    G : NetworkX DiGraph
       A directed graph
```
but `G` doesn't have to be a NetworkX DiGraph.

Resolving patch:
diff --git a/networkx/convert.py b/networkx/convert.py
--- a/networkx/convert.py
+++ b/networkx/convert.py
@@ -133,7 +133,7 @@ def to_networkx_graph(data, create_using=None, multigraph_input=False):
                     msg = "Input is not a correct Pandas DataFrame edge-list."
                     raise nx.NetworkXError(msg) from err
     except ImportError:
-        warnings.warn("pandas not found, skipping conversion test.", ImportWarning)
+        pass
 
     # numpy array
     try:
@@ -147,7 +147,7 @@ def to_networkx_graph(data, create_using=None, multigraph_input=False):
                     f"Failed to interpret array as an adjacency matrix."
                 ) from err
     except ImportError:
-        warnings.warn("numpy not found, skipping conversion test.", ImportWarning)
+        pass
 
     # scipy sparse array - any format
     try:
@@ -161,7 +161,7 @@ def to_networkx_graph(data, create_using=None, multigraph_input=False):
                     "Input is not a correct scipy sparse array type."
                 ) from err
     except ImportError:
-        warnings.warn("scipy not found, skipping conversion test.", ImportWarning)
+        pass
 
     # Note: most general check - should remain last in order of execution
     # Includes containers (e.g. list, set, dict, etc.), generators, and


Test patch: