Repository: networkx/networkx

Issue:
Deprecate `Ordered` graph classes
Since the next NetworkX release will drop support for Python 3.6, dictionaries should be ordered by default in all supported Python implementations moving forward (though it's worth double-checking that this is true for PyPy). Thus the `Ordered` graph classes will be redundant moving forward and can be deprecated for 2.6 in preparation for removal in 3.0.

This [SO post](https://stackoverflow.com/questions/39980323/are-dictionaries-ordered-in-python-3-6) compiles a lot of useful links re: the status of guaranteed insertion order for various Python versions. The conclusion is that insertion-order preservation is guaranteed for dictionaries from Python 3.7 onward.

Discussion:
rossbar: N.B. this will need #4628 (or similar) to fix the CI. 

Patch:
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst
index 177ab1625..9ddc21cf6 100644
--- a/CONTRIBUTING.rst
+++ b/CONTRIBUTING.rst
@@ -45,7 +45,7 @@ Development Workflow
          # Activate it
          source networkx-dev/bin/activate
          # Install main development and runtime dependencies of networkx
-         pip install -r <(cat requirements/{default,developer,doc,optional,test}.txt)
+         pip install -r <(cat requirements/{default,developer,test}.txt)
          #
          # (Optional) Install pygraphviz, pydot, and gdal packages
          # These packages require that you have your system properly configured
@@ -66,7 +66,7 @@ Development Workflow
          # Activate it
          conda activate networkx-dev
          # Install main development and runtime dependencies of networkx
-         conda install -c conda-forge `for i in requirements/{default,developer,doc,optional,test}.txt; do echo -n " --file $i "; done`
+         conda install -c conda-forge `for i in requirements/{default,developer,test}.txt; do echo -n " --file $i "; done`
          #
          # (Optional) Install pygraphviz, pydot, and gdal packages
          # These packages require that you have your system properly configured
diff --git a/doc/credits.rst b/doc/credits.rst
index c0488855c..425b334fb 100644
--- a/doc/credits.rst
+++ b/doc/credits.rst
@@ -142,6 +142,7 @@ to add your name to the bottom of the list.
 - Danny Niquette
 - James Trimble, Github: `jamestrimble <https://github.com/jamestrimble>`_
 - Matthias Bruhns, Github `<https://github.com/mbruhns>`_ 
+- Philip Boalch
 
 A supplementary (but still incomplete) list of contributors is given by the
 list of names that have commits in ``networkx``'s
diff --git a/doc/developer/deprecations.rst b/doc/developer/deprecations.rst
index 812f4aced..1ceb637bf 100644
--- a/doc/developer/deprecations.rst
+++ b/doc/developer/deprecations.rst
@@ -75,3 +75,5 @@ Version 3.0
 * Remove ``readwrite/json_graph/jit.py`` and related tests.
 * In ``utils/misc.py`` remove ``generate_unique_node`` and related tests.
 * In ``algorithms/link_analysis/hits_alg.py`` remove ``hub_matrix`` and ``authority_matrix``
+* In ``networkx.classes`` remove the ``ordered`` module and the four ``Ordered``
+  classes defined therein.
diff --git a/doc/reference/algorithms/community.rst b/doc/reference/algorithms/community.rst
index b89b0e2cd..5df5b89c3 100644
--- a/doc/reference/algorithms/community.rst
+++ b/doc/reference/algorithms/community.rst
@@ -29,7 +29,7 @@ Modularity-based communities
    :toctree: generated/
 
    greedy_modularity_communities
-   _naive_greedy_modularity_communities
+   naive_greedy_modularity_communities
 
 Tree partitioning
 -----------------
diff --git a/doc/release/release_dev.rst b/doc/release/release_dev.rst
index ccef52dfd..7ed72a03c 100644
--- a/doc/release/release_dev.rst
+++ b/doc/release/release_dev.rst
@@ -60,6 +60,10 @@ API Changes
   instead of a UUID generate string. So the function returns `tree`.
 - [`#4545 <https://github.com/networkx/networkx/pull/4545>`_]
   The variable `NIL` ="NIL" has been removed from `networkx.generators.trees`
+- [`#3620 <https://github.com/networkx/networkx/pull/3620>`_]
+  The function `naive_greedy_modularity_communities` now returns a
+  list of communities (like `greedy_modularity_communities`) instead
+  of a generator of communities.
 
 Deprecations
 ------------
@@ -96,6 +100,10 @@ Deprecations
   Deprecate ``empty_generator``.
 - [`#4617 <https://github.com/networkx/networkx/pull/4617>`_]
   Deprecate ``hub_matrix`` and ``authority_matrix``
+- [`#4629 <https://github.com/networkx/networkx/pull/4629>`_]
+  Deprecate the ``Ordered`` graph classes.
+
+
 
 Contributors to this release
 ----------------------------
diff --git a/examples/graphviz_layout/plot_atlas.py b/examples/graphviz_layout/plot_atlas.py
index ec08fb798..68a113c16 100644
--- a/examples/graphviz_layout/plot_atlas.py
+++ b/examples/graphviz_layout/plot_atlas.py
@@ -3,9 +3,13 @@
 Atlas
 =====
 
-Atlas of all graphs of 6 nodes or less.
+Atlas of all connected graphs with up to 6 nodes.
 
-This example needs Graphviz and PyGraphviz.
+This example uses Graphviz via PyGraphviz.
+
+The image should show 142 graphs.
+We don't plot the empty graph nor the single node graph.
+(142 is the sum of values 2 to n=6 in sequence oeis.org/A001349).
 """
 
 import random
@@ -14,40 +18,21 @@ import matplotlib.pyplot as plt
 import networkx as nx
 
 
+GraphMatcher = nx.isomorphism.vf2userfunc.GraphMatcher
+
+
 def atlas6():
-    """Return the atlas of all connected graphs of 6 nodes or less.
-    Attempt to check for isomorphisms and remove.
-    """
+    """Return the atlas of all connected graphs with at most 6 nodes"""
 
-    Atlas = nx.graph_atlas_g()[0:208]  # 208
-    # remove isolated nodes, only connected graphs are left
+    Atlas = nx.graph_atlas_g()[3:209]  # 0, 1, 2 => no edges. 208 is last 6 node graph
     U = nx.Graph()  # graph for union of all graphs in atlas
     for G in Atlas:
-        zerodegree = [n for n in G if G.degree(n) == 0]
-        for n in zerodegree:
-            G.remove_node(n)
-        U = nx.disjoint_union(U, G)
-
-    # iterator of graphs of all connected components
-    C = (U.subgraph(c) for c in nx.connected_components(U))
-
-    UU = nx.Graph()
-    # do quick isomorphic-like check, not a true isomorphism checker
-    nlist = []  # list of nonisomorphic graphs
-    for G in C:
-        # check against all nonisomorphic graphs so far
-        if not iso(G, nlist):
-            nlist.append(G)
-            UU = nx.disjoint_union(UU, G)  # union the nonisomorphic graphs
-    return UU
-
-
-def iso(G1, glist):
-    """Quick and dirty nonisomorphism checker used to check isomorphisms."""
-    for G2 in glist:
-        if nx.isomorphism.isomorph.graph_could_be_isomorphic(G1, G2):
-            return True
-    return False
+        # check if connected
+        if nx.number_connected_components(G) == 1:
+            # check if isomorphic to a previous graph
+            if not GraphMatcher(U, G).subgraph_is_isomorphic():
+                U = nx.disjoint_union(U, G)
+    return U
 
 
 G = atlas6()
diff --git a/networkx/algorithms/community/modularity_max.py b/networkx/algorithms/community/modularity_max.py
index 88225368e..cac64eb55 100644
--- a/networkx/algorithms/community/modularity_max.py
+++ b/networkx/algorithms/community/modularity_max.py
@@ -15,22 +15,30 @@ __all__ = [
 ]
 
 
-def greedy_modularity_communities(G, weight=None):
-    """Find communities in graph using Clauset-Newman-Moore greedy modularity
-    maximization. This method currently supports the Graph class and does not
+def greedy_modularity_communities(G, weight=None, resolution=1):
+    """Find communities in G using greedy modularity maximization.
+
+    This function uses Clauset-Newman-Moore greedy modularity maximization [2]_.
+    This method currently supports the Graph class and does not
     consider edge weights.
 
     Greedy modularity maximization begins with each node in its own community
     and joins the pair of communities that most increases modularity until no
     such pair exists.
 
+    This function maximizes the generalized modularity, where `resolution`
+    is the resolution parameter, often expressed as $\gamma$.
+    See :func:`~networkx.algorithms.community.quality.modularity`.
+
     Parameters
     ----------
     G : NetworkX graph
 
     Returns
     -------
-    Yields sets of nodes, one for each community.
+    list
+        A list of sets of nodes, one for each community.
+        Sorted by length with largest communities first.
 
     Examples
     --------
@@ -40,13 +48,19 @@ def greedy_modularity_communities(G, weight=None):
     >>> sorted(c[0])
     [8, 14, 15, 18, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33]
 
+    See Also
+    --------
+    modularity
+
     References
     ----------
-    .. [1] M. E. J Newman 'Networks: An Introduction', page 224
+    .. [1] M. E. J Newman "Networks: An Introduction", page 224
        Oxford University Press 2011.
     .. [2] Clauset, A., Newman, M. E., & Moore, C.
        "Finding community structure in very large networks."
        Physical Review E 70(6), 2004.
+    .. [3] Reichardt and Bornholdt "Statistical Mechanics of Community
+       Detection" Phys. Rev. E74, 2006.
     """
 
     # Count nodes and edges
@@ -68,7 +82,7 @@ def greedy_modularity_communities(G, weight=None):
 
     # Initial modularity
     partition = [[label_for_node[x] for x in c] for c in communities.values()]
-    q_cnm = modularity(G, partition)
+    q_cnm = modularity(G, partition, resolution=resolution)
 
     # Initialize data structures
     # CNM Eq 8-9 (Eq 8 was missing a factor of 2 (from A_ij + A_ji)
@@ -79,7 +93,7 @@ def greedy_modularity_communities(G, weight=None):
     a = [k[i] * q0 for i in range(N)]
     dq_dict = {
         i: {
-            j: 2 * q0 - 2 * k[i] * k[j] * q0 * q0
+            j: 2 * q0 - 2 * resolution * k[i] * k[j] * q0 * q0
             for j in [node_for_label[u] for u in G.neighbors(label_for_node[i])]
             if j != i
         }
@@ -138,10 +152,10 @@ def greedy_modularity_communities(G, weight=None):
             if k in both_set:
                 dq_jk = dq_dict[j][k] + dq_dict[i][k]
             elif k in j_set:
-                dq_jk = dq_dict[j][k] - 2.0 * a[i] * a[k]
+                dq_jk = dq_dict[j][k] - 2.0 * resolution * a[i] * a[k]
             else:
                 # k in i_set
-                dq_jk = dq_dict[i][k] - 2.0 * a[j] * a[k]
+                dq_jk = dq_dict[i][k] - 2.0 * resolution * a[j] * a[k]
             # Update rows j and k
             for row, col in [(j, k), (k, j)]:
                 # Save old value for finding heap index
@@ -209,10 +223,42 @@ def greedy_modularity_communities(G, weight=None):
     return sorted(communities, key=len, reverse=True)
 
 
-def naive_greedy_modularity_communities(G):
-    """Find communities in graph using the greedy modularity maximization.
+def naive_greedy_modularity_communities(G, resolution=1):
+    """Find communities in G using greedy modularity maximization.
+
     This implementation is O(n^4), much slower than alternatives, but it is
     provided as an easy-to-understand reference implementation.
+
+    Greedy modularity maximization begins with each node in its own community
+    and joins the pair of communities that most increases modularity until no
+    such pair exists.
+
+    This function maximizes the generalized modularity, where `resolution`
+    is the resolution parameter, often expressed as $\gamma$.
+    See :func:`~networkx.algorithms.community.quality.modularity`.
+
+    Parameters
+    ----------
+    G : NetworkX graph
+
+    Returns
+    -------
+    list
+        A list of sets of nodes, one for each community.
+        Sorted by length with largest communities first.
+
+    Examples
+    --------
+    >>> from networkx.algorithms.community import greedy_modularity_communities
+    >>> G = nx.karate_club_graph()
+    >>> c = list(greedy_modularity_communities(G))
+    >>> sorted(c[0])
+    [8, 14, 15, 18, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33]
+
+    See Also
+    --------
+    greedy_modularity_communities
+    modularity
     """
     # First create one community for each node
     communities = list([frozenset([u]) for u in G.nodes()])
@@ -220,7 +266,7 @@ def naive_greedy_modularity_communities(G):
     merges = []
     # Greedily merge communities until no improvement is possible
     old_modularity = None
-    new_modularity = modularity(G, communities)
+    new_modularity = modularity(G, communities, resolution=resolution)
     while old_modularity is None or new_modularity > old_modularity:
         # Save modularity for comparison
         old_modularity = new_modularity
@@ -229,13 +275,15 @@ def naive_greedy_modularity_communities(G):
         to_merge = None
         for i, u in enumerate(communities):
             for j, v in enumerate(communities):
-                # Skip i=j and empty communities
+                # Skip i==j and empty communities
                 if j <= i or len(u) == 0 or len(v) == 0:
                     continue
                 # Merge communities u and v
                 trial_communities[j] = u | v
                 trial_communities[i] = frozenset([])
-                trial_modularity = modularity(G, trial_communities)
+                trial_modularity = modularity(
+                    G, trial_communities, resolution=resolution
+                )
                 if trial_modularity >= new_modularity:
                     # Check if strictly better or tie
                     if trial_modularity > new_modularity:
@@ -257,8 +305,7 @@ def naive_greedy_modularity_communities(G):
             communities[j] = u | v
             communities[i] = frozenset([])
     # Remove empty communities and sort
-    communities = [c for c in communities if len(c) > 0]
-    yield from sorted(communities, key=lambda x: len(x), reverse=True)
+    return sorted((c for c in communities if len(c) > 0), key=len, reverse=True)
 
 
 # old name
diff --git a/networkx/algorithms/community/quality.py b/networkx/algorithms/community/quality.py
index 8db1c9600..470db9ee8 100644
--- a/networkx/algorithms/community/quality.py
+++ b/networkx/algorithms/community/quality.py
@@ -244,31 +244,38 @@ def coverage(G, partition):
     return intra_edges / total_edges
 
 
-def modularity(G, communities, weight="weight"):
+def modularity(G, communities, weight="weight", resolution=1):
     r"""Returns the modularity of the given partition of the graph.
 
     Modularity is defined in [1]_ as
 
     .. math::
-
-        Q = \frac{1}{2m} \sum_{ij} \left( A_{ij} - \frac{k_ik_j}{2m}\right)
+        Q = \frac{1}{2m} \sum_{ij} \left( A_{ij} - \gamma\frac{k_ik_j}{2m}\right)
             \delta(c_i,c_j)
 
-    where $m$ is the number of edges, $A$ is the adjacency matrix of
-    `G`, $k_i$ is the degree of $i$ and $\delta(c_i, c_j)$
-    is 1 if $i$ and $j$ are in the same community and 0 otherwise.
+    where $m$ is the number of edges, $A$ is the adjacency matrix of `G`,
+    $k_i$ is the degree of $i$, $\gamma$ is the resolution parameter,
+    and $\delta(c_i, c_j)$ is 1 if $i$ and $j$ are in the same community else 0.
 
     According to [2]_ (and verified by some algebra) this can be reduced to
 
     .. math::
        Q = \sum_{c=1}^{n}
-       \left[ \frac{L_c}{m} - \left( \frac{k_c}{2m} \right) ^2 \right]
+       \left[ \frac{L_c}{m} - \gamma\left( \frac{k_c}{2m} \right) ^2 \right]
 
     where the sum iterates over all communities $c$, $m$ is the number of edges,
     $L_c$ is the number of intra-community links for community $c$,
-    $k_c$ is the sum of degrees of the nodes in community $c$.
+    $k_c$ is the sum of degrees of the nodes in community $c$,
+    and $\gamma$ is the resolution parameter.
+
+    The resolution parameter sets an arbitrary tradeoff between intra-group
+    edges and inter-group edges. More complex grouping patterns can be
+    discovered by analyzing the same network with multiple values of gamma
+    and then combining the results [3]_. That said, it is very common to
+    simply use gamma=1. More on the choice of gamma is in [4]_.
 
     The second formula is the one actually used in calculation of the modularity.
+    For directed graphs the second formula replaces $k_c$ with $k^{in}_c k^{out}_c$.
 
     Parameters
     ----------
@@ -282,6 +289,10 @@ def modularity(G, communities, weight="weight"):
             as a weight. If None or an edge does not have that attribute,
             then that edge has weight 1.
 
+    resolution : float (default=1)
+        If resolution is less than 1, modularity favors larger communities.
+        Greater than 1 favors smaller communities.
+
     Returns
     -------
     Q : float
@@ -303,11 +314,17 @@ def modularity(G, communities, weight="weight"):
 
     References
     ----------
-    .. [1] M. E. J. Newman *Networks: An Introduction*, page 224.
+    .. [1] M. E. J. Newman "Networks: An Introduction", page 224.
        Oxford University Press, 2011.
     .. [2] Clauset, Aaron, Mark EJ Newman, and Cristopher Moore.
        "Finding community structure in very large networks."
-       Physical review E 70.6 (2004). <https://arxiv.org/abs/cond-mat/0408187>
+       Phys. Rev. E 70.6 (2004). <https://arxiv.org/abs/cond-mat/0408187>
+    .. [3] Reichardt and Bornholdt "Statistical Mechanics of Community Detection"
+       Phys. Rev. E 74, 016110, 2006. https://doi.org/10.1103/PhysRevE.74.016110
+    .. [4] M. E. J. Newman, "Equivalence between modularity optimization and
+       maximum likelihood methods for community detection"
+       Phys. Rev. E 94, 052315, 2016. https://doi.org/10.1103/PhysRevE.94.052315
+
     """
     if not isinstance(communities, list):
         communities = list(communities)
@@ -333,7 +350,7 @@ def modularity(G, communities, weight="weight"):
         out_degree_sum = sum(out_degree[u] for u in comm)
         in_degree_sum = sum(in_degree[u] for u in comm) if directed else out_degree_sum
 
-        return L_c / m - out_degree_sum * in_degree_sum * norm
+        return L_c / m - resolution * out_degree_sum * in_degree_sum * norm
 
     return sum(map(community_contribution, communities))
 
diff --git a/networkx/algorithms/cycles.py b/networkx/algorithms/cycles.py
index 2605a0f4e..483804be0 100644
--- a/networkx/algorithms/cycles.py
+++ b/networkx/algorithms/cycles.py
@@ -392,11 +392,10 @@ def find_cycle(G, source=None, orientation=None):
     is also known as a polytree).
 
     >>> G = nx.DiGraph([(0, 1), (0, 2), (1, 2)])
-    >>> try:
-    ...     nx.find_cycle(G, orientation="original")
-    ... except:
-    ...     pass
-    ...
+    >>> nx.find_cycle(G, orientation="original")
+    Traceback (most recent call last):
+        ...
+    networkx.exception.NetworkXNoCycle: No cycle found.
     >>> list(nx.find_cycle(G, orientation="ignore"))
     [(0, 1, 'forward'), (1, 2, 'forward'), (0, 2, 'reverse')]
 
diff --git a/networkx/algorithms/matching.py b/networkx/algorithms/matching.py
index c6e5fd1cb..4bcd92366 100644
--- a/networkx/algorithms/matching.py
+++ b/networkx/algorithms/matching.py
@@ -92,6 +92,13 @@ def is_matching(G, matching):
     """
     if isinstance(matching, dict):
         matching = matching_dict_to_set(matching)
+
+    for edge in matching:
+        if len(edge) != 2:
+            return False
+        if not G.has_edge(*edge):
+            return False
+
     # TODO This is parallelizable.
     return all(len(set(e1) & set(e2)) == 0 for e1, e2 in combinations(matching, 2))
 
diff --git a/networkx/classes/multidigraph.py b/networkx/classes/multidigraph.py
index 2fe7a460b..13f23cb28 100644
--- a/networkx/classes/multidigraph.py
+++ b/networkx/classes/multidigraph.py
@@ -367,9 +367,6 @@ class MultiDiGraph(MultiGraph, DiGraph):
             Nodes must be hashable (and not None) Python objects.
         key : hashable identifier, optional (default=lowest unused integer)
             Used to distinguish multiedges between a pair of nodes.
-        attr_dict : dictionary, optional (default= no attributes)
-            Dictionary of edge attributes.  Key/value pairs will
-            update existing data associated with the edge.
         attr : keyword arguments, optional
             Edge data (or labels or objects) can be assigned using
             keyword arguments.
diff --git a/networkx/classes/ordered.py b/networkx/classes/ordered.py
index 74bd59654..67021e5aa 100644
--- a/networkx/classes/ordered.py
+++ b/networkx/classes/ordered.py
@@ -1,4 +1,10 @@
 """
+
+.. deprecated:: 2.6
+
+   The ordered variants of graph classes in this module are deprecated and
+   will be removed in version 3.0.
+
 Consistently ordered variants of the default base classes.
 Note that if you are using Python 3.6+, you shouldn't need these classes
 because the dicts in Python 3.6+ are ordered.
@@ -28,6 +34,7 @@ subgraphs and replace with code similar to:
 
 """
 from collections import OrderedDict
+import warnings
 
 from .graph import Graph
 from .multigraph import MultiGraph
@@ -42,25 +49,70 @@ __all__.extend(
 
 
 class OrderedGraph(Graph):
-    """Consistently ordered variant of :class:`~networkx.Graph`."""
+    """Consistently ordered variant of :class:`~networkx.Graph`.
+
+    .. deprecated:: 2.6
+
+       OrderedGraph is deprecated and will be removed in version 3.0.
+       Use `Graph` instead, which guarantees order is preserved for
+       Python >= 3.7
+    """
 
     node_dict_factory = OrderedDict
     adjlist_outer_dict_factory = OrderedDict
     adjlist_inner_dict_factory = OrderedDict
     edge_attr_dict_factory = OrderedDict
 
+    def __init__(self, incoming_graph_data=None, **attr):
+        warnings.warn(
+            (
+                "OrderedGraph is deprecated and will be removed in version 3.0.\n"
+                "Use `Graph` instead, which guarantees order is preserved for\n"
+                "Python >= 3.7\n"
+            ),
+            DeprecationWarning,
+            stacklevel=2,
+        )
+        super(OrderedGraph, self).__init__(incoming_graph_data, **attr)
+
 
 class OrderedDiGraph(DiGraph):
-    """Consistently ordered variant of :class:`~networkx.DiGraph`."""
+    """Consistently ordered variant of :class:`~networkx.DiGraph`.
+
+    .. deprecated:: 2.6
+
+       OrderedDiGraph is deprecated and will be removed in version 3.0.
+       Use `DiGraph` instead, which guarantees order is preserved for
+       Python >= 3.7
+    """
 
     node_dict_factory = OrderedDict
     adjlist_outer_dict_factory = OrderedDict
     adjlist_inner_dict_factory = OrderedDict
     edge_attr_dict_factory = OrderedDict
 
+    def __init__(self, incoming_graph_data=None, **attr):
+        warnings.warn(
+            (
+                "OrderedDiGraph is deprecated and will be removed in version 3.0.\n"
+                "Use `DiGraph` instead, which guarantees order is preserved for\n"
+                "Python >= 3.7\n"
+            ),
+            DeprecationWarning,
+            stacklevel=2,
+        )
+        super(OrderedDiGraph, self).__init__(incoming_graph_data, **attr)
+
 
 class OrderedMultiGraph(MultiGraph):
-    """Consistently ordered variant of :class:`~networkx.MultiGraph`."""
+    """Consistently ordered variant of :class:`~networkx.MultiGraph`.
+
+    .. deprecated:: 2.6
+
+       OrderedMultiGraph is deprecated and will be removed in version 3.0.
+       Use `MultiGraph` instead, which guarantees order is preserved for
+       Python >= 3.7
+    """
 
     node_dict_factory = OrderedDict
     adjlist_outer_dict_factory = OrderedDict
@@ -68,12 +120,43 @@ class OrderedMultiGraph(MultiGraph):
     edge_key_dict_factory = OrderedDict
     edge_attr_dict_factory = OrderedDict
 
+    def __init__(self, incoming_graph_data=None, **attr):
+        warnings.warn(
+            (
+                "OrderedMultiGraph is deprecated and will be removed in version 3.0.\n"
+                "Use `MultiGraph` instead, which guarantees order is preserved for\n"
+                "Python >= 3.7\n"
+            ),
+            DeprecationWarning,
+            stacklevel=2,
+        )
+        super(OrderedMultiGraph, self).__init__(incoming_graph_data, **attr)
+
 
 class OrderedMultiDiGraph(MultiDiGraph):
-    """Consistently ordered variant of :class:`~networkx.MultiDiGraph`."""
+    """Consistently ordered variant of :class:`~networkx.MultiDiGraph`.
+
+    .. deprecated:: 2.6
+
+       OrderedMultiDiGraph is deprecated and will be removed in version 3.0.
+       Use `MultiDiGraph` instead, which guarantees order is preserved for
+       Python >= 3.7
+    """
 
     node_dict_factory = OrderedDict
     adjlist_outer_dict_factory = OrderedDict
     adjlist_inner_dict_factory = OrderedDict
     edge_key_dict_factory = OrderedDict
     edge_attr_dict_factory = OrderedDict
+
+    def __init__(self, incoming_graph_data=None, **attr):
+        warnings.warn(
+            (
+                "OrderedMultiDiGraph is deprecated and will be removed in version 3.0.\n"
+                "Use `MultiDiGraph` instead, which guarantees order is preserved for\n"
+                "Python >= 3.7\n"
+            ),
+            DeprecationWarning,
+            stacklevel=2,
+        )
+        super(OrderedMultiDiGraph, self).__init__(incoming_graph_data, **attr)


Test patch:
diff --git a/networkx/algorithms/community/tests/test_modularity_max.py b/networkx/algorithms/community/tests/test_modularity_max.py
index ba80ef949..c6fe3fa24 100644
--- a/networkx/algorithms/community/tests/test_modularity_max.py
+++ b/networkx/algorithms/community/tests/test_modularity_max.py
@@ -1,39 +1,43 @@
+import pytest
+
 import networkx as nx
 from networkx.algorithms.community import (
     greedy_modularity_communities,
+    modularity,
     naive_greedy_modularity_communities,
 )
 
 
-class TestCNM:
-    def setup(self):
-        self.G = nx.karate_club_graph()
+@pytest.mark.parametrize(
+    "func", (greedy_modularity_communities, naive_greedy_modularity_communities)
+)
+def test_modularity_communities(func):
+    G = nx.karate_club_graph()
+
+    john_a = frozenset(
+        [8, 14, 15, 18, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33]
+    )
+    mr_hi = frozenset([0, 4, 5, 6, 10, 11, 16, 19])
+    overlap = frozenset([1, 2, 3, 7, 9, 12, 13, 17, 21])
+    expected = {john_a, overlap, mr_hi}
 
-    def _check_communities(self, expected):
-        communities = set(greedy_modularity_communities(self.G))
-        assert communities == expected
+    assert set(func(G)) == expected
 
-    def test_karate_club(self):
-        john_a = frozenset(
-            [8, 14, 15, 18, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33]
-        )
-        mr_hi = frozenset([0, 4, 5, 6, 10, 11, 16, 19])
-        overlap = frozenset([1, 2, 3, 7, 9, 12, 13, 17, 21])
-        self._check_communities({john_a, overlap, mr_hi})
 
+def test_resolution_parameter_impact():
+    G = nx.barbell_graph(5, 3)
 
-class TestNaive:
-    def setup(self):
-        self.G = nx.karate_club_graph()
+    gamma = 1
+    expected = [frozenset(range(5)), frozenset(range(8, 13)), frozenset(range(5, 8))]
+    assert greedy_modularity_communities(G, resolution=gamma) == expected
+    assert naive_greedy_modularity_communities(G, resolution=gamma) == expected
 
-    def _check_communities(self, expected):
-        communities = set(naive_greedy_modularity_communities(self.G))
-        assert communities == expected
+    gamma = 2.5
+    expected = [{0, 1, 2, 3}, {9, 10, 11, 12}, {5, 6, 7}, {4}, {8}]
+    assert greedy_modularity_communities(G, resolution=gamma) == expected
+    assert naive_greedy_modularity_communities(G, resolution=gamma) == expected
 
-    def test_karate_club(self):
-        john_a = frozenset(
-            [8, 14, 15, 18, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33]
-        )
-        mr_hi = frozenset([0, 4, 5, 6, 10, 11, 16, 19])
-        overlap = frozenset([1, 2, 3, 7, 9, 12, 13, 17, 21])
-        self._check_communities({john_a, overlap, mr_hi})
+    gamma = 0.3
+    expected = [frozenset(range(8)), frozenset(range(8, 13))]
+    assert greedy_modularity_communities(G, resolution=gamma) == expected
+    assert naive_greedy_modularity_communities(G, resolution=gamma) == expected
diff --git a/networkx/algorithms/community/tests/test_quality.py b/networkx/algorithms/community/tests/test_quality.py
index a28f99e43..79d60e7ff 100644
--- a/networkx/algorithms/community/tests/test_quality.py
+++ b/networkx/algorithms/community/tests/test_quality.py
@@ -2,6 +2,7 @@
 module.
 
 """
+import pytest
 
 import networkx as nx
 from networkx import barbell_graph
@@ -73,6 +74,64 @@ def test_modularity():
     assert almost_equal(2 / 9, modularity(G, C))
 
 
+def test_modularity_resolution():
+    G = nx.barbell_graph(3, 0)
+    C = [{0, 1, 4}, {2, 3, 5}]
+    assert modularity(G, C) == pytest.approx(3 / 7 - 100 / 14 ** 2)
+    gamma = 2
+    result = modularity(G, C, resolution=gamma)
+    assert result == pytest.approx(3 / 7 - gamma * 100 / 14 ** 2)
+    gamma = 0.2
+    result = modularity(G, C, resolution=gamma)
+    assert result == pytest.approx(3 / 7 - gamma * 100 / 14 ** 2)
+
+    C = [{0, 1, 2}, {3, 4, 5}]
+    assert modularity(G, C) == pytest.approx(6 / 7 - 98 / 14 ** 2)
+    gamma = 2
+    result = modularity(G, C, resolution=gamma)
+    assert result == pytest.approx(6 / 7 - gamma * 98 / 14 ** 2)
+    gamma = 0.2
+    result = modularity(G, C, resolution=gamma)
+    assert result == pytest.approx(6 / 7 - gamma * 98 / 14 ** 2)
+
+    G = nx.barbell_graph(5, 3)
+    C = [frozenset(range(5)), frozenset(range(8, 13)), frozenset(range(5, 8))]
+    gamma = 1
+    result = modularity(G, C, resolution=gamma)
+    # This C is maximal for gamma=1:  modularity = 0.518229
+    assert result == pytest.approx((22 / 24) - gamma * (918 / (48 ** 2)))
+    gamma = 2
+    result = modularity(G, C, resolution=gamma)
+    assert result == pytest.approx((22 / 24) - gamma * (918 / (48 ** 2)))
+    gamma = 0.2
+    result = modularity(G, C, resolution=gamma)
+    assert result == pytest.approx((22 / 24) - gamma * (918 / (48 ** 2)))
+
+    C = [{0, 1, 2, 3}, {9, 10, 11, 12}, {5, 6, 7}, {4}, {8}]
+    gamma = 1
+    result = modularity(G, C, resolution=gamma)
+    assert result == pytest.approx((14 / 24) - gamma * (598 / (48 ** 2)))
+    gamma = 2.5
+    result = modularity(G, C, resolution=gamma)
+    # This C is maximal for gamma=2.5:  modularity = -0.06553819
+    assert result == pytest.approx((14 / 24) - gamma * (598 / (48 ** 2)))
+    gamma = 0.2
+    result = modularity(G, C, resolution=gamma)
+    assert result == pytest.approx((14 / 24) - gamma * (598 / (48 ** 2)))
+
+    C = [frozenset(range(8)), frozenset(range(8, 13))]
+    gamma = 1
+    result = modularity(G, C, resolution=gamma)
+    assert result == pytest.approx((23 / 24) - gamma * (1170 / (48 ** 2)))
+    gamma = 2
+    result = modularity(G, C, resolution=gamma)
+    assert result == pytest.approx((23 / 24) - gamma * (1170 / (48 ** 2)))
+    gamma = 0.3
+    result = modularity(G, C, resolution=gamma)
+    # This C is maximal for gamma=0.3:  modularity = 0.805990
+    assert result == pytest.approx((23 / 24) - gamma * (1170 / (48 ** 2)))
+
+
 def test_inter_community_edges_with_digraphs():
     G = nx.complete_graph(2, create_using=nx.DiGraph())
     partition = [{0}, {1}]
diff --git a/networkx/algorithms/tests/test_matching.py b/networkx/algorithms/tests/test_matching.py
index 5886ed64c..df9b8abab 100644
--- a/networkx/algorithms/tests/test_matching.py
+++ b/networkx/algorithms/tests/test_matching.py
@@ -408,6 +408,14 @@ class TestIsMatching:
         G = nx.path_graph(4)
         assert not nx.is_matching(G, {(0, 1), (1, 2), (2, 3)})
 
+    def test_invalid_edge(self):
+        G = nx.path_graph(4)
+        assert not nx.is_matching(G, {(0, 3), (1, 2)})
+        assert not nx.is_matching(G, {(0, 4)})
+        G = nx.path_graph(4, create_using=nx.DiGraph)
+        assert nx.is_matching(G, {(0, 1)})
+        assert not nx.is_matching(G, {(1, 0)})
+
 
 class TestIsMaximalMatching:
     """Unit tests for the
diff --git a/networkx/conftest.py b/networkx/conftest.py
index d3b93087e..53bf5dc9f 100644
--- a/networkx/conftest.py
+++ b/networkx/conftest.py
@@ -27,6 +27,9 @@ def pytest_collection_modifyitems(config, items):
 # TODO: The warnings below need to be dealt with, but for now we silence them.
 @pytest.fixture(autouse=True)
 def set_warnings():
+    warnings.filterwarnings(
+        "ignore", category=DeprecationWarning, message=r"Ordered.* is deprecated"
+    )
     warnings.filterwarnings(
         "ignore",
         category=DeprecationWarning,