internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: networkx/networkx

Issue:
`PlanarEmbedding.copy()` raising `NotImplementedError` after PR #6798
`PlanarEmbedding` inherits the method `copy()` from `nx.Graph`. However, the current implementation uses the method `add_edges_from()` which was made forbidden by PR #6798.

### Current Behavior

```python
embedding = nx.PlanarEmbedding({1: {2: {"cw": 2, "ccw": 2}},
                                2: {1: {"cw": 1, "ccw": 1}}})
emb2 = embedding.copy()
```
```
NotImplementedError: Use `add_half_edge` method to add edges to a PlanarEmbedding.
```

### Environment

Python version: 3.11
NetworkX version: commit fd3cadc (main)

### Additional context

PR #6798 was written by me to solve a bug, but the blocking of inherited edge-adding methods was requested by @dschult.

I think this block is quite likely to break code in unforeseen places. The safer approach would be to extend these methods in PlanarEmbedding and display a deprecation warning for a while (I can't work on that at the moment).

The specific problem with `copy()` can be resolved by the PR below.


Discussion:

Resolving patch:
diff --git a/networkx/algorithms/planarity.py b/networkx/algorithms/planarity.py
--- a/networkx/algorithms/planarity.py
+++ b/networkx/algorithms/planarity.py
@@ -1385,3 +1385,16 @@ def is_directed(self):
         contained.
         """
         return False
+
+    def copy(self, as_view=False):
+        if as_view is True:
+            return nx.graphviews.generic_graph_view(self)
+        G = self.__class__()
+        G.graph.update(self.graph)
+        G.add_nodes_from((n, d.copy()) for n, d in self._node.items())
+        super(self.__class__, G).add_edges_from(
+            (u, v, datadict.copy())
+            for u, nbrs in self._adj.items()
+            for v, datadict in nbrs.items()
+        )
+        return G


Test patch:
Repository: networkx/networkx

Issue:
Typo in Tensor Product Documentation
### Current Behavior
Currently, in the documentation, the definition of the node set of the product says, it is the **tensor** product of the node sets. This is incorrect, as the tensor product is not applicable to sets and does not correspond to the sci. definition. 

### Expected Behavior
The **Cartesian** product of the node set provides the correct (and implemented) mathematical operation.  



Discussion:

Resolving patch:
diff --git a/networkx/algorithms/operators/product.py b/networkx/algorithms/operators/product.py
--- a/networkx/algorithms/operators/product.py
+++ b/networkx/algorithms/operators/product.py
@@ -128,7 +128,7 @@ def tensor_product(G, H):
     r"""Returns the tensor product of G and H.
 
     The tensor product $P$ of the graphs $G$ and $H$ has a node set that
-    is the tensor product of the node sets, $V(P)=V(G) \times V(H)$.
+    is the Cartesian product of the node sets, $V(P)=V(G) \times V(H)$.
     $P$ has an edge $((u,v), (x,y))$ if and only if $(u,x)$ is an edge in $G$
     and $(v,y)$ is an edge in $H$.
 


Test patch:
Repository: networkx/networkx

Issue:
Return type of `general_k_edge_subgraphs` is incorrect in docstring
In networkx 3.2.1, `general_k_edge_subgraphs` return type in docstring says this:
```
    k_edge_subgraphs : a generator of nx.Graphs that are k-edge-subgraphs
        Each k-edge-subgraph is a maximal set of nodes that defines a subgraph
        of G that is k-edge-connected.
```
However, it actually _yields_ (not returns) _graphs_, not sets of nodes.


Discussion:

Resolving patch:
diff --git a/networkx/algorithms/connectivity/edge_kcomponents.py b/networkx/algorithms/connectivity/edge_kcomponents.py
--- a/networkx/algorithms/connectivity/edge_kcomponents.py
+++ b/networkx/algorithms/connectivity/edge_kcomponents.py
@@ -505,17 +505,24 @@ def _high_degree_components(G, k):
 
 @nx._dispatchable
 def general_k_edge_subgraphs(G, k):
-    """General algorithm to find all maximal k-edge-connected subgraphs in G.
+    """General algorithm to find all maximal k-edge-connected subgraphs in `G`.
 
-    Returns
-    -------
-    k_edge_subgraphs : a generator of nx.Graphs that are k-edge-subgraphs
-        Each k-edge-subgraph is a maximal set of nodes that defines a subgraph
-        of G that is k-edge-connected.
+    Parameters
+    ----------
+    G : nx.Graph
+       Graph in which all maximal k-edge-connected subgraphs will be found.
+
+    k : int
+
+    Yields
+    ------
+    k_edge_subgraphs : Graph instances that are k-edge-subgraphs
+        Each k-edge-subgraph contains a maximal set of nodes that defines a
+        subgraph of `G` that is k-edge-connected.
 
     Notes
     -----
-    Implementation of the basic algorithm from _[1].  The basic idea is to find
+    Implementation of the basic algorithm from [1]_.  The basic idea is to find
     a global minimum cut of the graph. If the cut value is at least k, then the
     graph is a k-edge-connected subgraph and can be added to the results.
     Otherwise, the cut is used to split the graph in two and the procedure is
@@ -524,7 +531,7 @@ def general_k_edge_subgraphs(G, k):
     a single node or a subgraph of G that is k-edge-connected.
 
     This implementation contains optimizations for reducing the number of calls
-    to max-flow, but there are other optimizations in _[1] that could be
+    to max-flow, but there are other optimizations in [1]_ that could be
     implemented.
 
     References
@@ -547,7 +554,7 @@ def general_k_edge_subgraphs(G, k):
     ...     (14, 101, 24),
     ... ]
     >>> G = nx.Graph(it.chain(*[pairwise(path) for path in paths]))
-    >>> sorted(map(len, k_edge_subgraphs(G, k=3)))
+    >>> sorted(len(k_sg) for k_sg in k_edge_subgraphs(G, k=3))
     [1, 1, 1, 4, 4]
     """
     if k < 1:


Test patch:
Repository: networkx/networkx

Issue:
Docstring of `nonisomorphic_trees` should use `Yields`, not `Returns`
In NetworkX 3.2.1, `nonisomorphic_trees` yields graphs or adjacency matrices, so the docstring should use a `Yields` section, but it uses `Returns`.


Discussion:

Resolving patch:
diff --git a/networkx/generators/nonisomorphic_trees.py b/networkx/generators/nonisomorphic_trees.py
--- a/networkx/generators/nonisomorphic_trees.py
+++ b/networkx/generators/nonisomorphic_trees.py
@@ -19,22 +19,20 @@ def nonisomorphic_trees(order, create="graph"):
     Parameters
     ----------
     order : int
-      order of the desired tree(s)
-
-    create : graph or matrix (default="Graph)
-      If graph is selected a list of trees will be returned,
-      if matrix is selected a list of adjacency matrix will
-      be returned
-
-    Returns
-    -------
-    G : List of NetworkX Graphs
-
-    M : List of Adjacency matrices
-
-    References
-    ----------
-
+       order of the desired tree(s)
+
+    create : one of {"graph", "matrix"} (default="graph")
+       If ``"graph"`` is selected a list of ``Graph`` instances will be returned,
+       if matrix is selected a list of adjacency matrices will be returned.
+
+    Yields
+    ------
+    list
+       A list of nonisomorphic trees, in one of two formats depending on the
+       value of the `create` parameter:
+       - ``create="graph"``: yields a list of `networkx.Graph` instances
+       - ``create="matrix"``: yields a list of list-of-lists representing
+         adjacency matrices
     """
 
     if order < 2:


Test patch:
Repository: networkx/networkx

Issue:
Visualization: arrowstyle warning is very noisy
Follow-up to #7010

The logic determining when the `arrowstyle` UserWarning changed in #7010, with the unintended side-effect of it being raised far more often. For example, it is now raised during the doc build for all of the simple drawings of the classic generators.

The warning logic should be reviewed and modified so that the warning is only raised when appropriate.


Discussion:
This might be "just" a matter of setting a better stacklevel for the warnings. They didn't have a stacklevel before.
@dschult I think you're right - there was a stacklevel prior to #7010, but due to the nested function definitions, it was not correct :upside_down_face: . In other words, this warning *should've* been raised based on the previous logic, but wasn't because of stacklevel - though the raising itself was a bug!

The real cause of the problem is that [the check for raising the warning](https://github.com/networkx/networkx/blob/74ce63f222df0189c1c9ae425b5b7748111d17f9/networkx/drawing/nx_pylab.py#L883) checks that `arrowstyle is not None`, but the top-level drawing functions `draw_networkx` and `draw` (which call `draw_networkx_edges` under-the-hood) have `arrowstyle="-"` as the default.

I think the best way to fix this while maintaining the default behavior for all the drawing functions is to modify the `arrowstyle` warning check to `is not None or != "-"`. I'm going to give this a stab and see if it actually makes sense!

Resolving patch:
diff --git a/networkx/drawing/nx_pylab.py b/networkx/drawing/nx_pylab.py
--- a/networkx/drawing/nx_pylab.py
+++ b/networkx/drawing/nx_pylab.py
@@ -858,9 +858,6 @@ def draw_networkx_edges(
             raise TypeError("Argument `arrows` must be of type bool or None")
         use_linecollection = not arrows
 
-    if arrowstyle is None:
-        arrowstyle = "-|>" if G.is_directed() else "-"
-
     if isinstance(connectionstyle, str):
         connectionstyle = [connectionstyle]
     elif np.iterable(connectionstyle):
@@ -897,6 +894,10 @@ def draw_networkx_edges(
                 msg.format("connectionstyle"), category=UserWarning, stacklevel=2
             )
 
+    # NOTE: Arrowstyle modification must occur after the warnings section
+    if arrowstyle is None:
+        arrowstyle = "-|>" if G.is_directed() else "-"
+
     if ax is None:
         ax = plt.gca()
 


Test patch:
diff --git a/networkx/drawing/tests/test_pylab.py b/networkx/drawing/tests/test_pylab.py
--- a/networkx/drawing/tests/test_pylab.py
+++ b/networkx/drawing/tests/test_pylab.py
@@ -833,3 +833,15 @@ def test_user_warnings_for_unused_edge_drawing_kwargs(fap_only_kwarg):
         nx.draw_networkx_edges(G, pos, ax=ax, arrows=True, **fap_only_kwarg)
 
     plt.delaxes(ax)
+
+
+@pytest.mark.parametrize("draw_fn", (nx.draw, nx.draw_circular))
+def test_no_warning_on_default_draw_arrowstyle(draw_fn):
+    # See gh-7284
+    fig, ax = plt.subplots()
+    G = nx.cycle_graph(5)
+    with warnings.catch_warnings(record=True) as w:
+        draw_fn(G, ax=ax)
+    assert len(w) == 0
+
+    plt.delaxes(ax)
Repository: networkx/networkx

Issue:
Empty GraphML attribute is not shown with networkx
### Current Behavior

Currently, networkx does not show (GraphML) attributes that are empty.

Here is little example.
```xml
<?xml version='1.0' encoding='utf-8'?>
<graphml>
  <key id="d1" for="node" attr.name="foo" attr.type="string"/>
  <key id="d2" for="node" attr.name="bar" attr.type="string"/>
  <graph>
    <node id="0">
      <data key="d1">aaa</data>
      <data key="d2">bbb</data>
    </node>

    <node id="1">
      <data key="d1">ccc</data>
      <data key="d2"></data>
    </node>
  </graph>
</graphml>
```

If I load the file, node 0 shows both attributes while node 1 only shows the attribute `foo`.
```python
G = nx.read_graphml("example.graphml")
G.nodes().get('0')
# {'foo': 'aaa', 'bar': 'bbb'}
G.nodes().get('1')
# {'foo': 'ccc'}
```

### Expected Behavior

I would expect that node 1 shows attribute `bar` containing an empty string.

### Environment

<!--- Please provide details about your local environment -->

Python version: Python 3.11.6
NetworkX version: networkx==3.2.1

### Additional context

This bug appeared during an analysis of the Brave pagegraph, [see here](https://github.com/brave/brave-browser/issues/35970).



Discussion:

Resolving patch:
diff --git a/networkx/readwrite/graphml.py b/networkx/readwrite/graphml.py
--- a/networkx/readwrite/graphml.py
+++ b/networkx/readwrite/graphml.py
@@ -1010,9 +1010,10 @@ def decode_data_elements(self, graphml_keys, obj_xml):
                     edge_label = data_element.find(f"{pref}EdgeLabel")
                     if edge_label is not None:
                         break
-
                 if edge_label is not None:
                     data["label"] = edge_label.text
+            elif text is None:
+                data[data_name] = ""
         return data
 
     def find_graphml_keys(self, graph_element):


Test patch:
diff --git a/networkx/readwrite/tests/test_graphml.py b/networkx/readwrite/tests/test_graphml.py
--- a/networkx/readwrite/tests/test_graphml.py
+++ b/networkx/readwrite/tests/test_graphml.py
@@ -1505,3 +1505,27 @@ def test_exception_for_unsupported_datatype_graph_attr():
     fh = io.BytesIO()
     with pytest.raises(TypeError, match="GraphML does not support"):
         nx.write_graphml(G, fh)
+
+
+def test_empty_attribute():
+    """Tests that a GraphML string with an empty attribute can be parsed
+    correctly."""
+    s = """<?xml version='1.0' encoding='utf-8'?>
+    <graphml>
+      <key id="d1" for="node" attr.name="foo" attr.type="string"/>
+      <key id="d2" for="node" attr.name="bar" attr.type="string"/>
+      <graph>
+        <node id="0">
+          <data key="d1">aaa</data>
+          <data key="d2">bbb</data>
+        </node>
+        <node id="1">
+          <data key="d1">ccc</data>
+          <data key="d2"></data>
+        </node>
+      </graph>
+    </graphml>"""
+    fh = io.BytesIO(s.encode("UTF-8"))
+    G = nx.read_graphml(fh)
+    assert G.nodes["0"] == {"foo": "aaa", "bar": "bbb"}
+    assert G.nodes["1"] == {"foo": "ccc", "bar": ""}
Repository: networkx/networkx

Issue:
`single_target_shortest_path_length` on main returns dict, not iterator
There seem to be inconsistencies introduced in #6584 and #7161. For example, for `single_target_shortest_path_length`, the warning says that it will return dict (not iterator) starting in version 3.5, but it returns a dict _today_.


Discussion:
The warning message is:
```
single_target_shortest_path_length will return a dict instead of
an iterator in version 3.5
```
but the return statement is:
```python
return dict(_single_shortest_path_length(adj, nextlevel, cutoff))
```
For context: in the latest released version (3.2.1) it still returns a generator:

```python
In [1]: import networkx as nx

In [2]: nx.__version__
Out[2]: '3.2.1'

In [3]: G = nx.path_graph(10)

In [4]: nx.single_target_shortest_path_length(G, 0, 9)
Out[4]: <generator object _single_shortest_path_length at 0x771b69589d80>
```

so this inconsistency is only on the development branch and should be rectified before the next release!

Resolving patch:
diff --git a/networkx/algorithms/shortest_paths/unweighted.py b/networkx/algorithms/shortest_paths/unweighted.py
--- a/networkx/algorithms/shortest_paths/unweighted.py
+++ b/networkx/algorithms/shortest_paths/unweighted.py
@@ -117,7 +117,7 @@ def single_target_shortest_path_length(G, target, cutoff=None):
     Examples
     --------
     >>> G = nx.path_graph(5, create_using=nx.DiGraph())
-    >>> length = nx.single_target_shortest_path_length(G, 4)
+    >>> length = dict(nx.single_target_shortest_path_length(G, 4))
     >>> length[0]
     4
     >>> for node in range(5):
@@ -151,7 +151,7 @@ def single_target_shortest_path_length(G, target, cutoff=None):
     nextlevel = [target]
     # for version 3.3 we will return a dict like this:
     # return dict(_single_shortest_path_length(adj, nextlevel, cutoff))
-    return dict(_single_shortest_path_length(adj, nextlevel, cutoff))
+    return _single_shortest_path_length(adj, nextlevel, cutoff)
 
 
 @nx._dispatchable


Test patch:
diff --git a/networkx/algorithms/shortest_paths/tests/test_unweighted.py b/networkx/algorithms/shortest_paths/tests/test_unweighted.py
--- a/networkx/algorithms/shortest_paths/tests/test_unweighted.py
+++ b/networkx/algorithms/shortest_paths/tests/test_unweighted.py
@@ -92,9 +92,9 @@ def test_single_target_shortest_path(self):
     def test_single_target_shortest_path_length(self):
         pl = nx.single_target_shortest_path_length
         lengths = {0: 0, 1: 1, 2: 2, 3: 3, 4: 3, 5: 2, 6: 1}
-        assert pl(self.cycle, 0) == lengths
+        assert dict(pl(self.cycle, 0)) == lengths
         lengths = {0: 0, 1: 6, 2: 5, 3: 4, 4: 3, 5: 2, 6: 1}
-        assert pl(self.directed_cycle, 0) == lengths
+        assert dict(pl(self.directed_cycle, 0)) == lengths
         # test missing targets
         target = 8
         with pytest.raises(nx.NodeNotFound, match=f"Target {target} is not in G"):
Repository: networkx/networkx

Issue:
Missing documentation for output of ```optimal_edit_paths``` function
<!-- 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

The current description in the documentation for the ```optimal_edit_paths``` function is:

```
    edit_paths: list of tuples (node_edit_path, edge_edit_path)
         node_edit_path : list of tuples (u, v) edge_edit_path : list of tuples ((u1, v1), (u2, v2))
    cost : numeric
         Optimal edit path cost (graph edit distance).
```
while it states the type of output, there is no explanation on how to interpret the result.
On stackoverflow there is a [question](https://stackoverflow.com/questions/73696000/how-to-interpret-the-output-of-networkx-optimal-edit-paths) where users don't know how to interpret the output of such function.





Discussion:
I agree that this doc_string should be improved. 
The best description of graph edit paths I have found is buried in the doc_string of a function defined within a function -- and thus not available outside of the source code.  Perhaps it can kick-start a better description for the main doc_string.

<this is from the `get_edit_paths` function defined in `optimize_edit_paths`>
```
      Returns:
            sequence of (vertex_path, edge_path, cost)
                vertex_path: complete vertex edit path
                    list of tuples (u, v) of vertex mappings u<->v,
                    u=None or v=None for deletion/insertion
                edge_path: complete edge edit path
                    list of tuples (g, h) of edge mappings g<->h,
                    g=None or h=None for deletion/insertion
                cost: total cost of edit path
            NOTE: path costs are non-increasing
 ```

Resolving patch:
diff --git a/networkx/algorithms/similarity.py b/networkx/algorithms/similarity.py
--- a/networkx/algorithms/similarity.py
+++ b/networkx/algorithms/similarity.py
@@ -319,8 +319,12 @@ def optimal_edit_paths(
     Returns
     -------
     edit_paths : list of tuples (node_edit_path, edge_edit_path)
-        node_edit_path : list of tuples (u, v)
-        edge_edit_path : list of tuples ((u1, v1), (u2, v2))
+       - node_edit_path : list of tuples ``(u, v)`` indicating node transformations
+         between `G1` and `G2`. ``u`` is `None` for insertion, ``v`` is `None`
+         for deletion.
+       - edge_edit_path : list of tuples ``((u1, v1), (u2, v2))`` indicating edge
+         transformations between `G1` and `G2`. ``(None, (u2,v2))`` for insertion
+         and ``((u1,v1), None)`` for deletion.
 
     cost : numeric
         Optimal edit path cost (graph edit distance). When the cost


Test patch:
Repository: networkx/networkx

Issue:
FilterAdjacency: __len__ is recalculated unnecessarily

The class FilterAdjacency is only used in views and therefore only works on frozen sets of edges and nodes. Despite that its __len__ function is recalculated each time it is called instead of it being calculated and stored once upon its first call.

### Current Behavior

__len__ of FilterAdjacency is recalculated unnecessarily upon each call using up 80% of runtime for my application.

### Expected Behavior

__len__ of FilterAdjacency should calculated and stored once upon its first call. For all other calls the stored value is returned.

### Steps to Reproduce

Any use of nx.subgraph_view shows this behaviour. Very poor performance shows in my case for number of nodes > 100.000.

### Environment

Should be completely independent of env.

Python version: 3.11.8 
NetworkX version: 3.2.1



Discussion:

Resolving patch:
diff --git a/networkx/classes/coreviews.py b/networkx/classes/coreviews.py
--- a/networkx/classes/coreviews.py
+++ b/networkx/classes/coreviews.py
@@ -281,7 +281,13 @@ def __init__(self, d, NODE_OK):
         self.NODE_OK = NODE_OK
 
     def __len__(self):
-        return sum(1 for n in self)
+        # check whether NODE_OK stores the number of nodes as `length`
+        # or the nodes themselves as a set `nodes`. If not, count the nodes.
+        if hasattr(self.NODE_OK, "length"):
+            return self.NODE_OK.length
+        if hasattr(self.NODE_OK, "nodes"):
+            return len(self.NODE_OK.nodes & self._atlas.keys())
+        return sum(1 for n in self._atlas if self.NODE_OK(n))
 
     def __iter__(self):
         try:  # check that NODE_OK has attr 'nodes'
@@ -324,7 +330,13 @@ def __init__(self, d, NODE_OK, EDGE_OK):
         self.EDGE_OK = EDGE_OK
 
     def __len__(self):
-        return sum(1 for n in self)
+        # check whether NODE_OK stores the number of nodes as `length`
+        # or the nodes themselves as a set `nodes`. If not, count the nodes.
+        if hasattr(self.NODE_OK, "length"):
+            return self.NODE_OK.length
+        if hasattr(self.NODE_OK, "nodes"):
+            return len(self.NODE_OK.nodes & self._atlas.keys())
+        return sum(1 for n in self._atlas if self.NODE_OK(n))
 
     def __iter__(self):
         try:  # check that NODE_OK has attr 'nodes'
diff --git a/networkx/classes/filters.py b/networkx/classes/filters.py
--- a/networkx/classes/filters.py
+++ b/networkx/classes/filters.py
@@ -54,7 +54,14 @@ def hide_multiedges(edges):
 
 # write show_nodes as a class to make SubGraph pickleable
 class show_nodes:
-    """Filter class to show specific nodes."""
+    """Filter class to show specific nodes.
+
+    Attach the set of nodes as an attribute to speed up this commonly used filter
+
+    Note that another allowed attribute for filters is to store the number of nodes
+    on the filter as attribute `length` (used in `__len__`). It is a user
+    responsibility to ensure this attribute is accurate if present.
+    """
 
     def __init__(self, nodes):
         self.nodes = set(nodes)


Test patch: