Skip to content

Commit

Permalink
Try ruff (#346)
Browse files Browse the repository at this point in the history
Fix most ruff errors: fix line length problems, prefer function definition over assigning to lambdas, unused variables and related issues, and add some new tests.
  • Loading branch information
leotrs authored May 10, 2023
1 parent 26ba651 commit 7a1e85e
Show file tree
Hide file tree
Showing 34 changed files with 475 additions and 374 deletions.
10 changes: 9 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,15 @@

version = __version__

authors = "Nicholas Landry, Leo Torres, Maxime Lucas, Iacopo Iacopini, Giovanni Petri, Alice Patania, and Alice Schwarze"
authors = (
"Nicholas Landry, "
"Leo Torres, "
"Maxime Lucas, "
"Iacopo Iacopini, "
"Giovanni Petri, "
"Alice Patania, "
"and Alice Schwarze"
)

author_email = "[email protected]"

Expand Down
1 change: 0 additions & 1 deletion tests/algorithms/test_clustering.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import numpy as np
import pytest

import xgi
Expand Down
4 changes: 2 additions & 2 deletions tests/algorithms/test_connected.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
def test_is_connected(edgelist1, edgelist3):
H1 = xgi.Hypergraph(edgelist1)
H2 = xgi.Hypergraph(edgelist3)
assert xgi.is_connected(H1) == False
assert xgi.is_connected(H2) == True
assert xgi.is_connected(H1) is False
assert xgi.is_connected(H2) is True


def test_connected_components(edgelist1, edgelist2, edgelist4):
Expand Down
28 changes: 15 additions & 13 deletions tests/classes/test_function.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def test_max_edge_order(edgelist1, edgelist4, edgelist5):
H3 = xgi.Hypergraph(edgelist4)
H4 = xgi.Hypergraph(edgelist5)

assert xgi.max_edge_order(H0) == None
assert xgi.max_edge_order(H0) is None
assert xgi.max_edge_order(H1) == 0
assert xgi.max_edge_order(H2) == 2
assert xgi.max_edge_order(H3) == 3
Expand All @@ -31,11 +31,11 @@ def test_max_edge_order(edgelist1, edgelist4, edgelist5):
def test_is_possible_order(edgelist1):
H1 = xgi.Hypergraph(edgelist1)

assert xgi.is_possible_order(H1, -1) == False
assert xgi.is_possible_order(H1, 0) == True
assert xgi.is_possible_order(H1, 1) == True
assert xgi.is_possible_order(H1, 2) == True
assert xgi.is_possible_order(H1, 3) == False
assert xgi.is_possible_order(H1, -1) is False
assert xgi.is_possible_order(H1, 0) is True
assert xgi.is_possible_order(H1, 1) is True
assert xgi.is_possible_order(H1, 2) is True
assert xgi.is_possible_order(H1, 3) is False


def test_is_uniform(edgelist1, edgelist6, edgelist7):
Expand All @@ -44,10 +44,10 @@ def test_is_uniform(edgelist1, edgelist6, edgelist7):
H2 = xgi.Hypergraph(edgelist7)
H3 = xgi.empty_hypergraph()

assert xgi.is_uniform(H0) == False
assert xgi.is_uniform(H0) is False
assert xgi.is_uniform(H1) == 2
assert xgi.is_uniform(H2) == 2
assert xgi.is_uniform(H3) == False
assert xgi.is_uniform(H3) is False


def test_edge_neighborhood(edgelist3):
Expand Down Expand Up @@ -157,7 +157,7 @@ def test_create_empty_copy(edgelist1):
assert E2["name"] == "test"
assert E2["timestamp"] == "Nov. 20"
with pytest.raises(XGIError):
author = E2["author"]
_ = E2["author"]
for n in E2.nodes:
assert E2.nodes[n]["name"] == attr_dict[n]["name"]

Expand Down Expand Up @@ -508,7 +508,9 @@ def test_density(edgelist1):
with pytest.raises(ValueError):
xgi.density(H, max_order=8) # max_order cannot be larger than number of nodes

dens_ignore_sing = lambda m: xgi.density(H, max_order=m, ignore_singletons=True)
def dens_ignore_sing(m):
return xgi.density(H, max_order=m, ignore_singletons=True)

assert abs(dens_ignore_sing(0) - 0.0) < tol
assert abs(dens_ignore_sing(1) - 0.03571428571428571) < tol
assert abs(dens_ignore_sing(2) - 0.03571428571428571) < tol
Expand Down Expand Up @@ -678,9 +680,9 @@ def test_incidence_density(edgelist1):
H, max_order=8
) # max_order cannot be larger than number of nodes

dens_ignore_sing = lambda m: xgi.incidence_density(
H, max_order=m, ignore_singletons=True
)
def dens_ignore_sing(m):
return xgi.incidence_density(H, max_order=m, ignore_singletons=True)

assert abs(dens_ignore_sing(0) - 0.0) < tol
assert abs(dens_ignore_sing(1) - 0.25) < tol
assert abs(dens_ignore_sing(2) - 1 / 3) < tol
Expand Down
4 changes: 2 additions & 2 deletions tests/classes/test_simplicialcomplex.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ def test_constructor(edgelist5, dict5, incidence5, dataframe5):
S_sc = xgi.SimplicialComplex(S_list)

with pytest.raises(XGIError):
S_dict = xgi.SimplicialComplex(dict5)
_ = xgi.SimplicialComplex(dict5)
with pytest.raises(XGIError):
S_mat = xgi.SimplicialComplex(incidence5)
_ = xgi.SimplicialComplex(incidence5)

assert set(S_list.nodes) == set(S_df.nodes) == set(S_sc.nodes)
assert set(S_list.edges) == set(S_df.edges) == set(S_sc.edges)
Expand Down
19 changes: 13 additions & 6 deletions tests/drawing/test_layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,30 @@ def test_random_layout():
assert len(pos) == S.num_nodes


def test_pairwise_spring_layout():
def test_pairwise_spring_layout_hypergraph():
H = xgi.random_hypergraph(10, [0.2], seed=1)

# seed
pos1 = xgi.pairwise_spring_layout(H, seed=1)
pos2 = xgi.pairwise_spring_layout(H, seed=2)
pos3 = xgi.pairwise_spring_layout(H, seed=2)
assert pos1.keys() == pos2.keys()
assert pos2.keys() == pos3.keys()
assert pos1.keys() == pos2.keys() == pos3.keys()
assert not np.allclose(list(pos1.values()), list(pos2.values()))
assert np.allclose(list(pos2.values()), list(pos3.values()))

assert len(pos1) == H.num_nodes

# simplicial complex


def test_pairwise_spring_layout_simplicial_complex():
S = xgi.random_flag_complex_d2(10, 0.2, seed=1)
pos = xgi.pairwise_spring_layout(S, seed=1)

pos1 = xgi.pairwise_spring_layout(S, seed=1)
pos2 = xgi.pairwise_spring_layout(S, seed=2)
pos3 = xgi.pairwise_spring_layout(S, seed=2)
assert pos1.keys() == pos2.keys() == pos3.keys()
assert not np.allclose(list(pos1.values()), list(pos2.values()))
assert np.allclose(list(pos2.values()), list(pos3.values()))
assert len(pos1) == S.num_nodes


def test_barycenter_spring_layout(hypergraph1):
Expand Down
2 changes: 1 addition & 1 deletion tests/generators/test_classic.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def test_empty_hypergraph():
assert (H.num_nodes, H.num_edges) == (0, 0)


def test_empty_hypergraph():
def test_empty_simplicial_complex():
SC = xgi.empty_simplicial_complex()
assert (SC.num_nodes, SC.num_edges) == (0, 0)

Expand Down
4 changes: 1 addition & 3 deletions tests/generators/test_nonuniform.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@ def test_chung_lu_hypergraph():
assert H2._edge == H3._edge

with pytest.warns(Warning):
k1 = {1: 1, 2: 2}
k2 = {1: 2, 1: 2}
H = xgi.chung_lu_hypergraph(k1, k2)
_ = xgi.chung_lu_hypergraph({1: 1, 2: 2}, {1: 2, 2: 2})


def test_dcsbm_hypergraph():
Expand Down
10 changes: 2 additions & 8 deletions tests/stats/test_nodestats.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,9 @@ def test_call_filterby(edgelist1, edgelist8):
assert filtered.asdict() == {1: 3.5}


def test_filterby_attr(hyperwithattrs, attr1, attr2, attr3, attr4, attr5):
def test_filterby_attr(hyperwithattrs):
H = hyperwithattrs
attrs = {
1: attr1,
2: attr2,
3: attr3,
4: attr4,
5: attr5,
}

filtered = H.nodes.filterby_attr("age", 20, "eq")
assert set(filtered) == {4}

Expand Down
11 changes: 6 additions & 5 deletions xgi/algorithms/centrality.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,8 @@ def h_eigenvector_centrality(H, max_iter=100, tol=1e-6):

new_H = convert_labels_to_integers(H, "old-label")

f = lambda v, m: np.power(v, 1.0 / m)
g = lambda v, x: np.prod(v[list(x)])
f = lambda v, m: np.power(v, 1.0 / m) # noqa: E731
g = lambda v, x: np.prod(v[list(x)]) # noqa: E731

x = np.random.uniform(size=(new_H.num_nodes))
x = x / norm(x, 1)
Expand Down Expand Up @@ -263,10 +263,11 @@ def line_vector_centrality(H):
References
----------
Vector centrality in hypergraphs,
K. Kovalenko, M. Romance, E. Vasilyeva, D. Aleja, R. Criado, D. Musatov,
A.M. Raigorodskii, J. Flores, I. Samoylenko, K. Alfaro-Bittner, M. Perc, S. Boccaletti,
"Vector centrality in hypergraphs", K. Kovalenko, M. Romance, E. Vasilyeva,
D. Aleja, R. Criado, D. Musatov, A.M. Raigorodskii, J. Flores, I. Samoylenko,
K. Alfaro-Bittner, M. Perc, S. Boccaletti,
https://doi.org/10.1016/j.chaos.2022.112397
"""
from ..algorithms import is_connected

Expand Down
7 changes: 4 additions & 3 deletions xgi/algorithms/clustering.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,8 @@ def local_clustering_coefficient(H):
References
----------
"Properties of metabolic graphs: biological organization or representation artifacts?"
by Wanding Zhou and Luay Nakhleh.
"Properties of metabolic graphs: biological organization or representation
artifacts?" by Wanding Zhou and Luay Nakhleh.
https://doi.org/10.1186/1471-2105-12-132
"Hypergraphs for predicting essential genes using multiprotein complex data"
Expand All @@ -118,6 +118,7 @@ def local_clustering_coefficient(H):
>>> cc = xgi.local_clustering_coefficient(H)
>>> cc
{0: 1.0, 1: 1.0, 2: 1.0}
"""
result = {}

Expand Down Expand Up @@ -147,7 +148,7 @@ def local_clustering_coefficient(H):
# the neighbours of D1 and D2, respectively.
neighD1 = {i for d in D1 for i in H.nodes.neighbors(d)}
neighD2 = {i for d in D2 for i in H.nodes.neighbors(d)}
# compute the extra overlap [len() is used for cardinality of edges]
# compute extra overlap [len() is used for cardinality of edges]
eo = (
len(neighD1.intersection(D2))
+ len(neighD2.intersection(D1))
Expand Down
12 changes: 7 additions & 5 deletions xgi/classes/function.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,9 @@ def is_uniform(H):
def edge_neighborhood(H, n, include_self=False):
"""The edge neighborhood of the specified node.
The edge neighborhood of a node `n` in a hypergraph `H` is an edgelist of all the edges
containing `n` and its edges are all the edges in `H` that contain
`n`. Usually, the edge neighborhood does not include `n` itself. This can be controlled
The edge neighborhood of a node `n` in a hypergraph `H` is an edgelist of all the
edges containing `n` and its edges are all the edges in `H` that contain `n`.
Usually, the edge neighborhood does not include `n` itself. This can be controlled
with `include_self`.
Parameters
Expand Down Expand Up @@ -573,7 +573,8 @@ def set_edge_attributes(H, values, name=None):
warn(f"Edge {e} does not exist!")
except AttributeError:
raise XGIError(
"name property has not been set and a dict-of-dicts has not been provided."
"name property has not been set and a "
"dict-of-dicts has not been provided."
)


Expand Down Expand Up @@ -882,7 +883,8 @@ def subfaces(edges, order=None):
max_order = len(max(edges, key=len)) - 1
if order and order > max_order:
raise XGIError(
f"order must be less or equal to the maximum order among the edges: {max_order}."
"order must be less or equal to the maximum "
f"order among the edges: {max_order}."
)

faces = []
Expand Down
49 changes: 30 additions & 19 deletions xgi/classes/hypergraph.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,15 @@ def __str__(self):
"""
try:
return f"{type(self).__name__} named {self['name']} with {self.num_nodes} nodes and {self.num_edges} hyperedges"
return (
f"{type(self).__name__} named {self['name']} "
f"with {self.num_nodes} nodes and {self.num_edges} hyperedges"
)
except XGIError:
return f"Unnamed {type(self).__name__} with {self.num_nodes} nodes and {self.num_edges} hyperedges"
return (
f"Unnamed {type(self).__name__} with "
f"{self.num_nodes} nodes and {self.num_edges} hyperedges"
)

def __iter__(self):
"""Iterate over the nodes.
Expand Down Expand Up @@ -217,7 +223,8 @@ def __getattr__(self, attr):
if stat is None:
word = None
raise AttributeError(
f"{attr} is not a method of Hypergraph or a recognized NodeStat or EdgeStat"
f"{attr} is not a method of Hypergraph or a "
"recognized NodeStat or EdgeStat"
)

def func(node=None, *args, **kwargs):
Expand Down Expand Up @@ -528,29 +535,29 @@ def add_edge(self, members, id=None, **attr):
update_uid_counter(self, id)

def add_edges_from(self, ebunch_to_add, **attr):
"""Add multiple edges with optional attributes.
r"""Add multiple edges with optional attributes.
Parameters
----------
ebunch_to_add : Iterable
An iterable of edges. This may be an iterable of iterables (Format 1),
where each element contains the members of the edge specified as valid node IDs.
Alternatively, each element could also be a tuple in any of the following
formats:
where each element contains the members of the edge specified as valid node
IDs. Alternatively, each element could also be a tuple in any of the
following formats:
* Format 2: 2-tuple (members, edge_id), or
* Format 3: 2-tuple (members, attr), or
* Format 4: 3-tuple (members, edge_id, attr),
where `members` is an iterable of node IDs, `edge_id` is a hashable to use
as edge ID, and `attr` is a dict of attributes. Finally, `ebunch_to_add`
may be a dict of the form `{edge_id: edge_members}` (Format 5).
as edge ID, and `attr` is a dict of attributes. Finally, `ebunch_to_add` may
be a dict of the form `{edge_id: edge_members}` (Format 5).
Formats 2 and 3 are unambiguous because `attr` dicts are not hashable, while `id`s must be.
In Formats 2-4, each element of `ebunch_to_add` must have the same length,
i.e. you cannot mix different formats. The iterables containing edge
members cannot be strings.
Formats 2 and 3 are unambiguous because `attr` dicts are not hashable, while
`id`s must be. In Formats 2-4, each element of `ebunch_to_add` must have
the same length, i.e. you cannot mix different formats. The iterables
containing edge members cannot be strings.
attr : \*\*kwargs, optional
Additional attributes to be assigned to all edges. Attribues specified via
Expand Down Expand Up @@ -1172,7 +1179,8 @@ def merge_duplicate_edges(

if merge_rule == "union":
warn(
"You will not be able to color/draw by merged attributes with xgi.draw()!"
"You will not be able to color/draw by "
"merged attributes with xgi.draw()!"
)

def copy(self):
Expand Down Expand Up @@ -1235,15 +1243,18 @@ def cleanup(
Parameters
----------
isolates : bool, optional
Whether isolated nodes are allowed, by default False
Whether isolated nodes are allowed, by default False.
singletons : bool, optional
Whether singleton edges are allowed, by default False
Whether singleton edges are allowed, by default False.
multiedges : bool, optional
Whether multiedges are allowed, by default False
Whether multiedges are allowed, by default False.
relabel : bool, optional
Whether to convert all node and edge labels to sequential integers, by default True
Whether to convert all node and edge labels to sequential integers, by
default True.
in_place : bool, optional
Whether to modify the current hypergraph or output a new one, by default True
Whether to modify the current hypergraph or output a new one, by default
True.
"""
if in_place:
if not multiedges:
Expand Down
Loading

0 comments on commit 7a1e85e

Please sign in to comment.