From 97ec628247915cb4b453674bee797a4ba598c47a Mon Sep 17 00:00:00 2001 From: Chris Trevino Date: Fri, 10 May 2024 12:58:18 -0700 Subject: [PATCH 1/5] replace black, isort, pylint with ruff --- graspologic/cluster/autogmm.py | 9 +- graspologic/cluster/divisive_cluster.py | 9 +- graspologic/cluster/kclust.py | 4 +- graspologic/embed/ase.py | 2 +- graspologic/embed/base.py | 4 +- graspologic/embed/lse.py | 2 +- graspologic/embed/mase.py | 20 +- graspologic/embed/omni.py | 4 +- graspologic/embed/svd.py | 2 +- graspologic/layouts/nooverlap/_grid.py | 2 +- graspologic/layouts/nooverlap/nooverlap.py | 2 +- graspologic/match/solver.py | 7 +- graspologic/models/sbm_estimators.py | 4 +- graspologic/nominate/VNviaSGM.py | 4 +- graspologic/pipeline/embed/_elbow.py | 2 +- .../pipeline/embed/omnibus_embedding.py | 10 +- graspologic/pipeline/graph_builder.py | 2 +- graspologic/plot/plot.py | 22 +- graspologic/subgraph/sg.py | 10 +- graspologic/utils/utils.py | 12 +- poetry.lock | 113 +++------- pyproject.toml | 94 ++++++-- tests/embed/test_omni.py | 18 +- tests/partition/test_leiden.py | 22 +- tests/preprocessing/graph_cuts.py | 12 +- tests/test_mds.py | 14 +- tests/test_models.py | 28 ++- tests/test_plot.py | 16 +- tests/test_plot_matrix.py | 72 +++---- tests/test_ptr.py | 194 +++++++++-------- tests/test_sims.py | 123 +++++------ tests/test_spectral_embed.py | 14 +- tests/test_svd.py | 20 +- tests/test_utils.py | 202 +++++++++--------- 34 files changed, 512 insertions(+), 563 deletions(-) diff --git a/graspologic/cluster/autogmm.py b/graspologic/cluster/autogmm.py index 85b66fe5e..3f2a3879b 100644 --- a/graspologic/cluster/autogmm.py +++ b/graspologic/cluster/autogmm.py @@ -574,7 +574,7 @@ def fit(self, X: np.ndarray, y: Optional[np.ndarray] = None) -> "AutoGMMCluster" agg = AgglomerativeClustering( n_clusters=self.min_components, metric=affinity, - **p_ag_without_affinity + **p_ag_without_affinity, ) agg.fit(X_subset) hierarchical_labels = _hierarchical_labels( @@ -762,9 +762,10 @@ def _hierarchical_labels( inds = np.where(np.isin(hierarchical_labels[:, n], children[n, :]))[0] hierarchical_labels[inds, -1] = n_samples + n if n < merge_end: - hierarchical_labels = np.hstack( - (hierarchical_labels, hierarchical_labels[:, -1].reshape((-1, 1))) - ) + hierarchical_labels = np.hstack(( + hierarchical_labels, + hierarchical_labels[:, -1].reshape((-1, 1)), + )) hierarchical_labels = hierarchical_labels[:, merge_start:] for i in range(hierarchical_labels.shape[1]): diff --git a/graspologic/cluster/divisive_cluster.py b/graspologic/cluster/divisive_cluster.py index 5d036497e..e4492d9b0 100644 --- a/graspologic/cluster/divisive_cluster.py +++ b/graspologic/cluster/divisive_cluster.py @@ -214,7 +214,7 @@ def _cluster_and_decide(self, X: np.ndarray) -> np.ndarray: cluster = AutoGMMCluster( min_components=min_components, max_components=self.max_components, - **self.cluster_kws + **self.cluster_kws, ) cluster.fit(X) model = cluster.model_ @@ -275,9 +275,10 @@ def _fit(self, X: np.ndarray) -> np.ndarray: ): child_labels = dc._fit(new_X) while labels.shape[1] <= child_labels.shape[1]: - labels = np.column_stack( - (labels, np.zeros((len(X), 1), dtype=int)) - ) + labels = np.column_stack(( + labels, + np.zeros((len(X), 1), dtype=int), + )) labels[inds, 1 : child_labels.shape[1] + 1] = child_labels else: # make a "GaussianMixture" model for clusters diff --git a/graspologic/cluster/kclust.py b/graspologic/cluster/kclust.py index 734aceee3..df58380aa 100644 --- a/graspologic/cluster/kclust.py +++ b/graspologic/cluster/kclust.py @@ -88,9 +88,7 @@ def fit(self, X: np.ndarray, y: Optional[np.ndarray] = None) -> "KMeansCluster": # Deal with number of clusters if self.max_clusters > X.shape[0]: msg = "n_components must be >= n_samples, but got \ - n_components = {}, n_samples = {}".format( - self.max_clusters, X.shape[0] - ) + n_components = {}, n_samples = {}".format(self.max_clusters, X.shape[0]) raise ValueError(msg) else: max_clusters = self.max_clusters diff --git a/graspologic/embed/ase.py b/graspologic/embed/ase.py index 14b250368..52ab969e8 100644 --- a/graspologic/embed/ase.py +++ b/graspologic/embed/ase.py @@ -142,7 +142,7 @@ def fit( graph: GraphRepresentation, y: Optional[Any] = None, *args: Any, - **kwargs: Any + **kwargs: Any, ) -> "AdjacencySpectralEmbed": """ Fit ASE model to input graph diff --git a/graspologic/embed/base.py b/graspologic/embed/base.py index 428a94573..26195c742 100644 --- a/graspologic/embed/base.py +++ b/graspologic/embed/base.py @@ -144,7 +144,7 @@ def fit( graph: GraphRepresentation, y: Optional[Any] = None, *args: Any, - **kwargs: Any + **kwargs: Any, ) -> "BaseSpectralEmbed": """ A method for embedding. @@ -221,7 +221,7 @@ def fit_transform( graph: GraphRepresentation, y: Optional[Any] = None, *args: Any, - **kwargs: Any + **kwargs: Any, ) -> Union[np.ndarray, Tuple[np.ndarray, np.ndarray]]: """ Fit the model with graphs and apply the transformation. diff --git a/graspologic/embed/lse.py b/graspologic/embed/lse.py index a9102d3f9..6a5f1f207 100644 --- a/graspologic/embed/lse.py +++ b/graspologic/embed/lse.py @@ -148,7 +148,7 @@ def fit( graph: GraphRepresentation, y: Optional[Any] = None, *args: Any, - **kwargs: Any + **kwargs: Any, ) -> "LaplacianSpectralEmbed": """ Fit LSE model to input graph diff --git a/graspologic/embed/mase.py b/graspologic/embed/mase.py index 04a9dea86..b2bb5904a 100644 --- a/graspologic/embed/mase.py +++ b/graspologic/embed/mase.py @@ -172,18 +172,14 @@ def _reduce_dim(self, graphs): # type: ignore Vs = np.hstack([V.T[:, :best_dimension] for V in Vs]) else: # Equivalent to ASE - Us = np.hstack( - [ - U[:, :best_dimension] @ np.diag(np.sqrt(D[:best_dimension])) - for U, D in zip(Us, Ds) - ] - ) - Vs = np.hstack( - [ - V.T[:, :best_dimension] @ np.diag(np.sqrt(D[:best_dimension])) - for V, D in zip(Vs, Ds) - ] - ) + Us = np.hstack([ + U[:, :best_dimension] @ np.diag(np.sqrt(D[:best_dimension])) + for U, D in zip(Us, Ds) + ]) + Vs = np.hstack([ + V.T[:, :best_dimension] @ np.diag(np.sqrt(D[:best_dimension])) + for V, D in zip(Vs, Ds) + ]) # Second SVD for vertices # The notation is slightly different than the paper diff --git a/graspologic/embed/omni.py b/graspologic/embed/omni.py index 82b09f446..3da50da96 100644 --- a/graspologic/embed/omni.py +++ b/graspologic/embed/omni.py @@ -56,7 +56,7 @@ def _get_omnibus_matrix_sparse(matrices: List[csr_array]) -> csr_array: def _get_laplacian_matrices( - graphs: Union[np.ndarray, List[GraphRepresentation]] + graphs: Union[np.ndarray, List[GraphRepresentation]], ) -> Union[np.ndarray, List[np.ndarray]]: """ Helper function to convert graph adjacency matrices to graph Laplacian @@ -82,7 +82,7 @@ def _get_laplacian_matrices( def _get_omni_matrix( - graphs: Union[AdjacencyMatrix, List[AdjacencyMatrix]] + graphs: Union[AdjacencyMatrix, List[AdjacencyMatrix]], ) -> np.ndarray: """ Helper function for creating the omnibus matrix. diff --git a/graspologic/embed/svd.py b/graspologic/embed/svd.py index d02d6ec11..47dbaec97 100644 --- a/graspologic/embed/svd.py +++ b/graspologic/embed/svd.py @@ -44,7 +44,7 @@ def _compute_likelihood(arr: np.ndarray) -> np.ndarray: mu2 = -np.inf # compute pooled variance - variance = ((np.sum((s1 - mu1) ** 2) + np.sum((s2 - mu2) ** 2))) / ( + variance = (np.sum((s1 - mu1) ** 2) + np.sum((s2 - mu2) ** 2)) / ( n_elements - 1 - (idx < n_elements) ) std = np.sqrt(variance) diff --git a/graspologic/layouts/nooverlap/_grid.py b/graspologic/layouts/nooverlap/_grid.py index eb4f98b90..9cef0b2b7 100644 --- a/graspologic/layouts/nooverlap/_grid.py +++ b/graspologic/layouts/nooverlap/_grid.py @@ -180,7 +180,7 @@ def get_all_grid_cells(self) -> List[List[int]]: def print_stats(self) -> None: print( - f"cell size: {self.cell_size}, area: {self.cell_size*self.cell_size}, " + f"cell size: {self.cell_size}, area: {self.cell_size * self.cell_size}, " f"rows: {self._get_y_cells()}, cols: {self._get_x_cells()}" ) diff --git a/graspologic/layouts/nooverlap/nooverlap.py b/graspologic/layouts/nooverlap/nooverlap.py index 128c9b953..1c091ed09 100644 --- a/graspologic/layouts/nooverlap/nooverlap.py +++ b/graspologic/layouts/nooverlap/nooverlap.py @@ -23,7 +23,7 @@ def remove_overlaps(node_positions: List[NodePosition]) -> List[NodePosition]: qt = _QuadTree(local_nodes, 50) qt.layout_dense_first(first_color=None) stop = time.time() - logger.info(f"removed overlap in {stop-start} seconds") + logger.info(f"removed overlap in {stop - start} seconds") new_positions = [ NodePosition( diff --git a/graspologic/match/solver.py b/graspologic/match/solver.py index 856d8c0f9..d720713ea 100644 --- a/graspologic/match/solver.py +++ b/graspologic/match/solver.py @@ -430,9 +430,10 @@ def finalize(self, P: np.ndarray, rng: np.random.Generator) -> None: permutation = np.array([], dtype=int) # deal with seed-nonseed sorting from the initialization - permutation = np.concatenate( - (np.arange(self.n_seeds), permutation + self.n_seeds) - ) + permutation = np.concatenate(( + np.arange(self.n_seeds), + permutation + self.n_seeds, + )) final_permutation = np.empty(self.n, dtype=int) final_permutation[self.perm_A] = self.perm_B[permutation] diff --git a/graspologic/models/sbm_estimators.py b/graspologic/models/sbm_estimators.py index 1787662d5..51b640a95 100644 --- a/graspologic/models/sbm_estimators.py +++ b/graspologic/models/sbm_estimators.py @@ -166,7 +166,7 @@ def _estimate_assignments(self, graph: GraphRepresentation) -> None: gc = GaussianCluster( min_components=self.min_comm, max_components=self.max_comm, - **self.cluster_kws + **self.cluster_kws, ) vertex_assignments = gc.fit_predict(latent) # type: ignore self.vertex_assignments_ = vertex_assignments @@ -374,7 +374,7 @@ def _estimate_assignments(self, graph: GraphRepresentation) -> None: gc = GaussianCluster( min_components=self.min_comm, max_components=self.max_comm, - **self.cluster_kws + **self.cluster_kws, ) self.vertex_assignments_ = gc.fit_predict(latent) # type: ignore diff --git a/graspologic/nominate/VNviaSGM.py b/graspologic/nominate/VNviaSGM.py index 99aedc90f..9ec2194ee 100644 --- a/graspologic/nominate/VNviaSGM.py +++ b/graspologic/nominate/VNviaSGM.py @@ -259,9 +259,7 @@ def fit( if len(close_seeds) <= 0: warnings.warn( 'Voi {} was not a member of the induced subgraph A[{}], \ - Try increasing "order_voi_subgraph"'.format( - voi, seedsA - ) + Try increasing "order_voi_subgraph"'.format(voi, seedsA) ) self.n_seeds_ = None self.nomination_list_ = None diff --git a/graspologic/pipeline/embed/_elbow.py b/graspologic/pipeline/embed/_elbow.py index f6267bd12..8a08e450f 100644 --- a/graspologic/pipeline/embed/_elbow.py +++ b/graspologic/pipeline/embed/_elbow.py @@ -38,7 +38,7 @@ def _compute_likelihood(arr: np.ndarray) -> np.ndarray: mu2 = -np.inf # compute pooled variance - variance = ((np.sum((s1 - mu1) ** 2) + np.sum((s2 - mu2) ** 2))) / ( + variance = (np.sum((s1 - mu1) ** 2) + np.sum((s2 - mu2) ** 2)) / ( n_elements - 1 - (idx < n_elements) ) std = np.sqrt(variance) diff --git a/graspologic/pipeline/embed/omnibus_embedding.py b/graspologic/pipeline/embed/omnibus_embedding.py index cdd7a988a..fc989ad6a 100644 --- a/graspologic/pipeline/embed/omnibus_embedding.py +++ b/graspologic/pipeline/embed/omnibus_embedding.py @@ -220,12 +220,10 @@ def omnibus_embedding_pairwise( elbow_cut, graph.is_directed(), model.singular_values_, current_embedding ) - graph_embeddings.append( - ( - Embeddings(union_node_ids, previous_embedding_cut), - Embeddings(union_node_ids, current_embedding_cut), - ) - ) + graph_embeddings.append(( + Embeddings(union_node_ids, previous_embedding_cut), + Embeddings(union_node_ids, current_embedding_cut), + )) return graph_embeddings diff --git a/graspologic/pipeline/graph_builder.py b/graspologic/pipeline/graph_builder.py index f952b781d..a147da829 100644 --- a/graspologic/pipeline/graph_builder.py +++ b/graspologic/pipeline/graph_builder.py @@ -43,7 +43,7 @@ def add_edge( target: Any, weight: Union[int, float] = 1.0, sum_weight: bool = True, - **attributes: Any + **attributes: Any, ) -> None: """ Adds a weighted edge between the provided source and target. The source diff --git a/graspologic/plot/plot.py b/graspologic/plot/plot.py index efa80e061..6e54202b7 100644 --- a/graspologic/plot/plot.py +++ b/graspologic/plot/plot.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation and contributors. +# Copyright (c) Microsoft Corporation and contributors. # Licensed under the MIT License. import warnings @@ -72,9 +72,7 @@ def _check_common_inputs( raise TypeError(msg) elif context not in ["paper", "notebook", "talk", "poster"]: msg = "context must be one of (paper, notebook, talk, poster), \ - not {}.".format( - context - ) + not {}.".format(context) raise ValueError(msg) # Handle font_scale @@ -876,16 +874,14 @@ def pairplot_with_gmm( gmm.covariances_[np.newaxis, :, :], n_components, axis=0 ) elif gmm.covariance_type == "diag": - covariances = np.array( - [np.diag(gmm.covariances_[i]) for i in range(n_components)] - ) + covariances = np.array([ + np.diag(gmm.covariances_[i]) for i in range(n_components) + ]) elif gmm.covariance_type == "spherical": - covariances = np.array( - [ - np.diag(np.repeat(gmm.covariances_[i], X.shape[1])) - for i in range(n_components) - ] - ) + covariances = np.array([ + np.diag(np.repeat(gmm.covariances_[i], X.shape[1])) + for i in range(n_components) + ]) # setting up the data DataFrame if labels is None: diff --git a/graspologic/subgraph/sg.py b/graspologic/subgraph/sg.py index 13b1d14d0..21c7dd973 100644 --- a/graspologic/subgraph/sg.py +++ b/graspologic/subgraph/sg.py @@ -113,12 +113,10 @@ def fit( self.__construct_contingency() verts = np.shape(self.graphs)[0] - sigmat = np.array( - [ - [fisher_exact(self.contmat_[i, j, :, :])[1] for j in range(verts)] - for i in range(verts) - ] - ) + sigmat = np.array([ + [fisher_exact(self.contmat_[i, j, :, :])[1] for j in range(verts)] + for i in range(verts) + ]) if isinstance(constraints, (int)): # incoherent nedges = constraints diff --git a/graspologic/utils/utils.py b/graspologic/utils/utils.py index 1e17efc85..f31bbf11e 100644 --- a/graspologic/utils/utils.py +++ b/graspologic/utils/utils.py @@ -26,7 +26,7 @@ @beartype def average_matrices( - matrices: Union[np.ndarray, Union[List[np.ndarray], List[csr_array]]] + matrices: Union[np.ndarray, Union[List[np.ndarray], List[csr_array]]], ) -> Union[np.ndarray, csr_array]: """ Helper method to encapsulate calculating the average of matrices represented either as a @@ -104,9 +104,7 @@ def import_graph( ) else: msg = "Input must be networkx.Graph, np.array, or scipy.sparse.csr_array,\ - not {}.".format( - type(graph) - ) + not {}.".format(type(graph)) raise TypeError(msg) return out @@ -1160,9 +1158,9 @@ def remap_node_ids( graph_remapped.add_edge(node_id_dict[source], node_id_dict[target]) - graph_remapped[node_id_dict[source]][node_id_dict[target]][ - weight_attribute - ] = weight + graph_remapped[node_id_dict[source]][node_id_dict[target]][weight_attribute] = ( + weight + ) return graph_remapped, node_id_dict diff --git a/poetry.lock b/poetry.lock index 246593c53..30478a5f5 100644 --- a/poetry.lock +++ b/poetry.lock @@ -134,52 +134,6 @@ charset-normalizer = ["charset-normalizer"] html5lib = ["html5lib"] lxml = ["lxml"] -[[package]] -name = "black" -version = "24.4.2" -description = "The uncompromising code formatter." -optional = false -python-versions = ">=3.8" -files = [ - {file = "black-24.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dd1b5a14e417189db4c7b64a6540f31730713d173f0b63e55fabd52d61d8fdce"}, - {file = "black-24.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e537d281831ad0e71007dcdcbe50a71470b978c453fa41ce77186bbe0ed6021"}, - {file = "black-24.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaea3008c281f1038edb473c1aa8ed8143a5535ff18f978a318f10302b254063"}, - {file = "black-24.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:7768a0dbf16a39aa5e9a3ded568bb545c8c2727396d063bbaf847df05b08cd96"}, - {file = "black-24.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:257d724c2c9b1660f353b36c802ccece186a30accc7742c176d29c146df6e474"}, - {file = "black-24.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bdde6f877a18f24844e381d45e9947a49e97933573ac9d4345399be37621e26c"}, - {file = "black-24.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e151054aa00bad1f4e1f04919542885f89f5f7d086b8a59e5000e6c616896ffb"}, - {file = "black-24.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:7e122b1c4fb252fd85df3ca93578732b4749d9be076593076ef4d07a0233c3e1"}, - {file = "black-24.4.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:accf49e151c8ed2c0cdc528691838afd217c50412534e876a19270fea1e28e2d"}, - {file = "black-24.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:88c57dc656038f1ab9f92b3eb5335ee9b021412feaa46330d5eba4e51fe49b04"}, - {file = "black-24.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be8bef99eb46d5021bf053114442914baeb3649a89dc5f3a555c88737e5e98fc"}, - {file = "black-24.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:415e686e87dbbe6f4cd5ef0fbf764af7b89f9057b97c908742b6008cc554b9c0"}, - {file = "black-24.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bf10f7310db693bb62692609b397e8d67257c55f949abde4c67f9cc574492cc7"}, - {file = "black-24.4.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:98e123f1d5cfd42f886624d84464f7756f60ff6eab89ae845210631714f6db94"}, - {file = "black-24.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48a85f2cb5e6799a9ef05347b476cce6c182d6c71ee36925a6c194d074336ef8"}, - {file = "black-24.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:b1530ae42e9d6d5b670a34db49a94115a64596bc77710b1d05e9801e62ca0a7c"}, - {file = "black-24.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:37aae07b029fa0174d39daf02748b379399b909652a806e5708199bd93899da1"}, - {file = "black-24.4.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:da33a1a5e49c4122ccdfd56cd021ff1ebc4a1ec4e2d01594fef9b6f267a9e741"}, - {file = "black-24.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef703f83fc32e131e9bcc0a5094cfe85599e7109f896fe8bc96cc402f3eb4b6e"}, - {file = "black-24.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:b9176b9832e84308818a99a561e90aa479e73c523b3f77afd07913380ae2eab7"}, - {file = "black-24.4.2-py3-none-any.whl", hash = "sha256:d36ed1124bb81b32f8614555b34cc4259c3fbc7eec17870e8ff8ded335b58d8c"}, - {file = "black-24.4.2.tar.gz", hash = "sha256:c872b53057f000085da66a19c55d68f6f8ddcac2642392ad3a355878406fbd4d"}, -] - -[package.dependencies] -click = ">=8.0.0" -mypy-extensions = ">=0.4.3" -packaging = ">=22.0" -pathspec = ">=0.9.0" -platformdirs = ">=2" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} - -[package.extras] -colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] -jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -uvloop = ["uvloop (>=0.15.2)"] - [[package]] name = "bleach" version = "6.1.0" @@ -372,20 +326,6 @@ files = [ {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, ] -[[package]] -name = "click" -version = "8.1.7" -description = "Composable command line interface toolkit" -optional = false -python-versions = ">=3.7" -files = [ - {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, - {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} - [[package]] name = "colorama" version = "0.4.6" @@ -956,20 +896,6 @@ files = [ {file = "ipython_genutils-0.2.0.tar.gz", hash = "sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8"}, ] -[[package]] -name = "isort" -version = "5.13.2" -description = "A Python utility / library to sort Python imports." -optional = false -python-versions = ">=3.8.0" -files = [ - {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"}, - {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"}, -] - -[package.extras] -colors = ["colorama (>=0.4.6)"] - [[package]] name = "jedi" version = "0.19.1" @@ -1801,17 +1727,6 @@ files = [ {file = "pastel-0.2.1.tar.gz", hash = "sha256:e6581ac04e973cac858828c6202c1e1e81fee1dc7de7683f3e1ffe0bfd8a573d"}, ] -[[package]] -name = "pathspec" -version = "0.12.1" -description = "Utility library for gitignore style pattern matching of file paths." -optional = false -python-versions = ">=3.8" -files = [ - {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, - {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, -] - [[package]] name = "patsy" version = "0.5.6" @@ -2479,6 +2394,32 @@ files = [ {file = "rpds_py-0.18.1.tar.gz", hash = "sha256:dc48b479d540770c811fbd1eb9ba2bb66951863e448efec2e2c102625328e92f"}, ] +[[package]] +name = "ruff" +version = "0.4.4" +description = "An extremely fast Python linter and code formatter, written in Rust." +optional = false +python-versions = ">=3.7" +files = [ + {file = "ruff-0.4.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:29d44ef5bb6a08e235c8249294fa8d431adc1426bfda99ed493119e6f9ea1bf6"}, + {file = "ruff-0.4.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c4efe62b5bbb24178c950732ddd40712b878a9b96b1d02b0ff0b08a090cbd891"}, + {file = "ruff-0.4.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c8e2f1e8fc12d07ab521a9005d68a969e167b589cbcaee354cb61e9d9de9c15"}, + {file = "ruff-0.4.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:60ed88b636a463214905c002fa3eaab19795679ed55529f91e488db3fe8976ab"}, + {file = "ruff-0.4.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b90fc5e170fc71c712cc4d9ab0e24ea505c6a9e4ebf346787a67e691dfb72e85"}, + {file = "ruff-0.4.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:8e7e6ebc10ef16dcdc77fd5557ee60647512b400e4a60bdc4849468f076f6eef"}, + {file = "ruff-0.4.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b9ddb2c494fb79fc208cd15ffe08f32b7682519e067413dbaf5f4b01a6087bcd"}, + {file = "ruff-0.4.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c51c928a14f9f0a871082603e25a1588059b7e08a920f2f9fa7157b5bf08cfe9"}, + {file = "ruff-0.4.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5eb0a4bfd6400b7d07c09a7725e1a98c3b838be557fee229ac0f84d9aa49c36"}, + {file = "ruff-0.4.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:b1867ee9bf3acc21778dcb293db504692eda5f7a11a6e6cc40890182a9f9e595"}, + {file = "ruff-0.4.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:1aecced1269481ef2894cc495647392a34b0bf3e28ff53ed95a385b13aa45768"}, + {file = "ruff-0.4.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:9da73eb616b3241a307b837f32756dc20a0b07e2bcb694fec73699c93d04a69e"}, + {file = "ruff-0.4.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:958b4ea5589706a81065e2a776237de2ecc3e763342e5cc8e02a4a4d8a5e6f95"}, + {file = "ruff-0.4.4-py3-none-win32.whl", hash = "sha256:cb53473849f011bca6e754f2cdf47cafc9c4f4ff4570003a0dad0b9b6890e876"}, + {file = "ruff-0.4.4-py3-none-win_amd64.whl", hash = "sha256:424e5b72597482543b684c11def82669cc6b395aa8cc69acc1858b5ef3e5daae"}, + {file = "ruff-0.4.4-py3-none-win_arm64.whl", hash = "sha256:39df0537b47d3b597293edbb95baf54ff5b49589eb7ff41926d8243caa995ea6"}, + {file = "ruff-0.4.4.tar.gz", hash = "sha256:f87ea42d5cdebdc6a69761a9d0bc83ae9b3b30d0ad78952005ba6568d6c022af"}, +] + [[package]] name = "scikit-learn" version = "1.4.2" @@ -3186,4 +3127,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.9,<3.13" -content-hash = "2e5e2d44a0a5e64211290dd13009332fc77473294471109c3dbe7ec9adc36167" +content-hash = "7c579069db711648f1c9a899f635585517b28f38c4020ce09b5607131832800a" diff --git a/pyproject.toml b/pyproject.toml index fe66a8ecb..e96f03d56 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -52,7 +52,6 @@ umap-learn = "^0.5.6" [tool.poetry.group.dev.dependencies] ipykernel = "^5.1.0" ipython = "^7.4.0,!=8.7.0" # https://github.com/spatialaudio/nbsphinx/issues/687#issuecomment-1339271312 -isort = "^5.9.3" mypy = "^1.10.0" nbsphinx = "^0.8.7" numpydoc = "^1.1.0" @@ -65,7 +64,7 @@ sphinx-rtd-theme = "^2.0.0" testfixtures = "^6.18.3" pipdeptree = "^2.20.0" poethepoet = "^0.26.1" -black = "^24.4.2" +ruff = "^0.4.4" [build-system] requires = ["poetry-core>=1.0.0", "poetry-dynamic-versioning>=1.0.0,<2.0.0"] @@ -78,16 +77,14 @@ vcs = "git" bump = true [tool.poe.tasks] -_black = "black ./graspologic ./tests" -_isort = "isort ./graspologic ./tests" -_black_check = "black --check --diff ./graspologic ./tests" -_isort_check = "isort --check-only ./graspologic ./tests" +_sort_imports = "ruff check --select I --fix . --preview" +_format_code = "ruff format . --preview" +static_checks = 'ruff check . --preview' clean = "rm -rf docs/_build" type_check = "mypy ./graspologic" # Formatting -format = ["_black", "_isort"] -format_check = ["_black_check", "_isort_check"] +format = ['_sort_imports', '_format_code'] # Docs Tasks docs = "sphinx-build -W -a docs/ docs/_build/html" @@ -99,9 +96,82 @@ test_only = "pytest -s -k" coverage = "python -m pytest --co --cov=graspologic graspologic tests" fast_test = "pytest tests --ignore=tests/test_latentdistributiontest.py --ignore=tests/test_latentpositiontest.py" -lint = ["format_check", "type_check"] +lint = ["static_checks", "type_check"] validate = ["lint", "coverage", "docs", "tests"] -[tool.isort] -profile = "black" -multi_line_output = 3 + +[tool.ruff.lint] +select = [ + # "E4", + # "E7", + # "E9", + # "W291", + # "YTT", + # "T10", + # "ICN", + # "INP", + # "Q", + # "RSE", + # "SLOT", + # "INT", + # "FLY", + # "LOG", + # "C90", + # "T20", + # "D", + # "RET", + # "PD", + # "N", + # "PIE", + # "SIM", + # "S", + # "G", + # "ERA", + # "ASYNC", + # "TID", + # "UP", + # "SLF", + # "BLE", + # "C4", + # "I", + # "F", + # "A", + # "ARG", + # "PTH", + # "RUF", + # "B", + # "TCH", + # "DTZ", + # "PYI", + #"PT", + # "EM", + # "TRY", + # "PERF", + # "CPY", + + # "FBT", # use named arguments for boolean flags + # "TD", # todos + # "FIX", # fixme + # "FURB" # preview rules + # ANN # Type annotations, re-enable when we get bandwidth +] +ignore = [ + # Deprecated Rules + "ANN101", + "ANN102", + # Conflicts with interface argument checking + "ARG002", + "ANN204", + # TODO: Inspect these pandas rules for validity + "PD002", # prevents inplace=True + # TODO RE-Enable when we get bandwidth + "PERF203", # Needs restructuring of errors, we should bail-out on first error + "C901", # needs refactoring to remove cyclomatic complexity +] + +[tool.ruff.lint.per-file-ignores] +"tests/*" = ["S", "D", "ANN", "T201", "ASYNC", "ARG", "PTH", "TRY"] +"*.ipynb" = ["T201"] + +[tool.ruff.lint.pydocstyle] +convention = "numpy" \ No newline at end of file diff --git a/tests/embed/test_omni.py b/tests/embed/test_omni.py index ded1afab4..544bac1cf 100644 --- a/tests/embed/test_omni.py +++ b/tests/embed/test_omni.py @@ -56,16 +56,14 @@ def test_omni_matrix_ones_zeros(self): np.testing.assert_array_equal(output, expected_output) def test_omni_matrix_random(self): - expected_output = np.array( - [ - [0.0, 1.0, 1.0, 0.0, 0.5, 0.5], - [1.0, 0.0, 1.0, 0.5, 0.0, 1.0], - [1.0, 1.0, 0.0, 0.5, 1.0, 0.0], - [0.0, 0.5, 0.5, 0.0, 0.0, 0.0], - [0.5, 0.0, 1.0, 0.0, 0.0, 1.0], - [0.5, 1.0, 0.0, 0.0, 1.0, 0.0], - ] - ) + expected_output = np.array([ + [0.0, 1.0, 1.0, 0.0, 0.5, 0.5], + [1.0, 0.0, 1.0, 0.5, 0.0, 1.0], + [1.0, 1.0, 0.0, 0.5, 1.0, 0.0], + [0.0, 0.5, 0.5, 0.0, 0.0, 0.0], + [0.5, 0.0, 1.0, 0.0, 0.0, 1.0], + [0.5, 1.0, 0.0, 0.0, 1.0, 0.0], + ]) np.random.seed(4) dat_list = ( diff --git a/tests/partition/test_leiden.py b/tests/partition/test_leiden.py index 4e2247b16..d7d547a45 100644 --- a/tests/partition/test_leiden.py +++ b/tests/partition/test_leiden.py @@ -35,18 +35,16 @@ def test_from_native(self): # test from_native indirectly through calling graspologic.partition.hierarchical_leiden() def test_final_hierarchical_clustering(self): - hierarchical_clusters = HierarchicalClusters( - [ - HierarchicalCluster("1", 0, None, 0, False), - HierarchicalCluster("2", 0, None, 0, False), - HierarchicalCluster("3", 0, None, 0, False), - HierarchicalCluster("4", 1, None, 0, True), - HierarchicalCluster("5", 1, None, 0, True), - HierarchicalCluster("1", 2, 0, 1, True), - HierarchicalCluster("2", 2, 0, 1, True), - HierarchicalCluster("3", 3, 0, 1, True), - ] - ) + hierarchical_clusters = HierarchicalClusters([ + HierarchicalCluster("1", 0, None, 0, False), + HierarchicalCluster("2", 0, None, 0, False), + HierarchicalCluster("3", 0, None, 0, False), + HierarchicalCluster("4", 1, None, 0, True), + HierarchicalCluster("5", 1, None, 0, True), + HierarchicalCluster("1", 2, 0, 1, True), + HierarchicalCluster("2", 2, 0, 1, True), + HierarchicalCluster("3", 3, 0, 1, True), + ]) expected = { "1": 2, diff --git a/tests/preprocessing/graph_cuts.py b/tests/preprocessing/graph_cuts.py index 42fba1b5b..2759329f5 100644 --- a/tests/preprocessing/graph_cuts.py +++ b/tests/preprocessing/graph_cuts.py @@ -217,13 +217,11 @@ def test_histogram_from_graph(self): # check logger is logging things correctly since it is an important part of this function # by proxy this also checks that edges_by_weight is called - log_capture.check( - ( - "graspologic.preprocessing.graph_cuts", - "WARNING", - "Graph contains 1 edges with no weight. Histogram excludes these values.", - ) - ) + log_capture.check(( + "graspologic.preprocessing.graph_cuts", + "WARNING", + "Graph contains 1 edges with no weight. Histogram excludes these values.", + )) def test_make_cuts_larger_than_inclusive(self): graph = _get_toy_graph() diff --git a/tests/test_mds.py b/tests/test_mds.py index 5af219fb8..b77042f19 100644 --- a/tests/test_mds.py +++ b/tests/test_mds.py @@ -102,14 +102,12 @@ def use_fit(): assert_almost_equal(A, Ahat) def use_euclidean(): - A = np.array( - [ - [-7.62291243e-17, 6.12372436e-01, 4.95031815e-16], - [-4.97243701e-01, -2.04124145e-01, -2.93397401e-01], - [5.02711453e-01, -2.04124145e-01, -2.83926977e-01], - [-5.46775198e-03, -2.04124145e-01, 5.77324378e-01], - ] - ) + A = np.array([ + [-7.62291243e-17, 6.12372436e-01, 4.95031815e-16], + [-4.97243701e-01, -2.04124145e-01, -2.93397401e-01], + [5.02711453e-01, -2.04124145e-01, -2.83926977e-01], + [-5.46775198e-03, -2.04124145e-01, 5.77324378e-01], + ]) mds = ClassicalMDS(dissimilarity="euclidean") B = mds.fit_transform(A) diff --git a/tests/test_models.py b/tests/test_models.py index c1827fe28..c578cd6d3 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -212,14 +212,12 @@ def test_SBM_inputs(self): def test_SBM_fit_supervised(self): np.random.seed(888) - B = np.array( - [ - [0.9, 0.2, 0.05, 0.1], - [0.1, 0.7, 0.1, 0.1], - [0.2, 0.4, 0.8, 0.5], - [0.1, 0.2, 0.1, 0.7], - ] - ) + B = np.array([ + [0.9, 0.2, 0.05, 0.1], + [0.1, 0.7, 0.1, 0.1], + [0.2, 0.4, 0.8, 0.5], + [0.1, 0.2, 0.1, 0.7], + ]) n = np.array([500, 500, 250, 250]) g = sbm(n, B, directed=True, loops=False) sbe = SBMEstimator(directed=True, loops=False) @@ -288,14 +286,12 @@ class TestDCSBM(unittest.TestCase): @classmethod def setUpClass(cls) -> None: np.random.seed(8888) - B = np.array( - [ - [0.9, 0.05, 0.05, 0.05], - [0.05, 0.75, 0.05, 0.05], - [0.05, 0.05, 0.8, 0.5], - [0.05, 0.05, 0.05, 0.7], - ] - ) + B = np.array([ + [0.9, 0.05, 0.05, 0.05], + [0.05, 0.75, 0.05, 0.05], + [0.05, 0.05, 0.8, 0.5], + [0.05, 0.05, 0.05, 0.7], + ]) n = np.array([100, 100, 50, 50]) dc = np.random.beta(2, 5, size=n.sum()) labels = _n_to_labels(n) diff --git a/tests/test_plot.py b/tests/test_plot.py index ce4f49bbb..2673cef01 100644 --- a/tests/test_plot.py +++ b/tests/test_plot.py @@ -386,15 +386,13 @@ def test_networkplot_outputs_str(self): ) def test_sort_inds(self): - B = np.array( - [ - [0, 0.2, 0.1, 0.1, 0.1], - [0.2, 0.8, 0.1, 0.3, 0.1], - [0.15, 0.1, 0, 0.05, 0.1], - [0.1, 0.1, 0.2, 1, 0.1], - [0.1, 0.2, 0.1, 0.1, 0.8], - ] - ) + B = np.array([ + [0, 0.2, 0.1, 0.1, 0.1], + [0.2, 0.8, 0.1, 0.3, 0.1], + [0.15, 0.1, 0, 0.05, 0.1], + [0.1, 0.1, 0.2, 1, 0.1], + [0.1, 0.2, 0.1, 0.1, 0.8], + ]) g = sbm([10, 30, 50, 25, 25], B, directed=True) degrees = g.sum(axis=0) + g.sum(axis=1) diff --git a/tests/test_plot_matrix.py b/tests/test_plot_matrix.py index 679454f3c..b307b7c50 100644 --- a/tests/test_plot_matrix.py +++ b/tests/test_plot_matrix.py @@ -14,13 +14,11 @@ class TestPlotMatrix(unittest.TestCase): def test_adjplot_inputs(self): X = er_np(100, 0.5) - meta = pd.DataFrame( - { - "hemisphere": np.random.randint(2, size=100), - "region": np.random.randint(2, size=100), - "cell_size": np.random.randint(10, size=100), - } - ) + meta = pd.DataFrame({ + "hemisphere": np.random.randint(2, size=100), + "region": np.random.randint(2, size=100), + "cell_size": np.random.randint(10, size=100), + }) # test matrix with self.assertRaises(TypeError): @@ -30,13 +28,11 @@ def test_adjplot_inputs(self): # test meta with self.assertRaises(ValueError): - bad_meta = pd.DataFrame( - { - "hemisphere": np.random.randint(2, size=1), - "region": np.random.randint(2, size=1), - "cell_size": np.random.randint(10, size=1), - } - ) + bad_meta = pd.DataFrame({ + "hemisphere": np.random.randint(2, size=1), + "region": np.random.randint(2, size=1), + "cell_size": np.random.randint(10, size=1), + }) adjplot(X, meta=bad_meta) # test plot type @@ -66,13 +62,11 @@ def test_adjplot_output(self): simple function to see if plot is made without errors """ X = er_np(10, 0.5) - meta = pd.DataFrame( - { - "hemisphere": np.random.randint(2, size=10), - "region": np.random.randint(2, size=10), - "cell_size": np.random.randint(10, size=10), - } - ) + meta = pd.DataFrame({ + "hemisphere": np.random.randint(2, size=10), + "region": np.random.randint(2, size=10), + "cell_size": np.random.randint(10, size=10), + }) ax = adjplot(X, meta=meta) ax = adjplot(X, meta=meta, group="hemisphere") ax = adjplot(X, meta=meta, group="hemisphere", group_order="size") @@ -84,13 +78,11 @@ def test_adjplot_sparse(self): def test_matrix_inputs(self): X = er_np(100, 0.5) - meta = pd.DataFrame( - { - "hemisphere": np.random.randint(2, size=100), - "region": np.random.randint(2, size=100), - "cell_size": np.random.randint(10, size=100), - } - ) + meta = pd.DataFrame({ + "hemisphere": np.random.randint(2, size=100), + "region": np.random.randint(2, size=100), + "cell_size": np.random.randint(10, size=100), + }) # test matrix with self.assertRaises(TypeError): @@ -100,13 +92,11 @@ def test_matrix_inputs(self): # test meta with self.assertRaises(ValueError): - bad_meta = pd.DataFrame( - { - "hemisphere": np.random.randint(2, size=1), - "region": np.random.randint(2, size=1), - "cell_size": np.random.randint(10, size=1), - } - ) + bad_meta = pd.DataFrame({ + "hemisphere": np.random.randint(2, size=1), + "region": np.random.randint(2, size=1), + "cell_size": np.random.randint(10, size=1), + }) matrixplot(X, col_meta=bad_meta, row_meta=bad_meta) # test plot type @@ -168,13 +158,11 @@ def test_matrix_output(self): simple function to see if plot is made without errors """ X = er_np(10, 0.5) - meta = pd.DataFrame( - { - "hemisphere": np.random.randint(2, size=10), - "region": np.random.randint(2, size=10), - "cell_size": np.random.randint(10, size=10), - } - ) + meta = pd.DataFrame({ + "hemisphere": np.random.randint(2, size=10), + "region": np.random.randint(2, size=10), + "cell_size": np.random.randint(10, size=10), + }) ax = matrixplot(X, col_meta=meta, row_meta=meta) ax = matrixplot(X, col_meta=meta, row_meta=meta, row_group="hemisphere") ax = matrixplot( diff --git a/tests/test_ptr.py b/tests/test_ptr.py index 0b0d266b4..e1e99fb83 100644 --- a/tests/test_ptr.py +++ b/tests/test_ptr.py @@ -11,18 +11,30 @@ class TestPTR(unittest.TestCase): @classmethod def setUpClass(cls): - cls.loopless_undirected_input = np.array( - [[0, 1, 60, 60], [1, 0, 400, 0], [60, 400, 0, 80], [60, 0, 80, 0]] - ) - cls.looped_undirected_input = np.array( - [[0.5, 1, 60, 60], [1, 0, 400, 0], [60, 400, 20, 80], [60, 0, 80, 0]] - ) - cls.loopless_directed_input = np.array( - [[0, 1, 60, 60], [1, 0, 400, 0], [3, 600, 0, 80], [20, 0, 401, 0]] - ) - cls.looped_directed_input = np.array( - [[21, 1, 60, 60], [1, 0, 400, 0], [3, 600, 0, 80], [20, 0, 401, 30]] - ) + cls.loopless_undirected_input = np.array([ + [0, 1, 60, 60], + [1, 0, 400, 0], + [60, 400, 0, 80], + [60, 0, 80, 0], + ]) + cls.looped_undirected_input = np.array([ + [0.5, 1, 60, 60], + [1, 0, 400, 0], + [60, 400, 20, 80], + [60, 0, 80, 0], + ]) + cls.loopless_directed_input = np.array([ + [0, 1, 60, 60], + [1, 0, 400, 0], + [3, 600, 0, 80], + [20, 0, 401, 0], + ]) + cls.looped_directed_input = np.array([ + [21, 1, 60, 60], + [1, 0, 400, 0], + [3, 600, 0, 80], + [20, 0, 401, 30], + ]) def test_invalid_inputs(self): with self.assertRaises(ValueError): @@ -31,134 +43,120 @@ def test_invalid_inputs(self): pass_to_ranks("hi", "hi") def test_zeroboost_loopless_undirected(self): - ptr_expected = np.array( - [ - [0, 2.0 / 6, 3.5 / 6, 3.5 / 6], - [2.0 / 6, 0, 1, 0], - [3.5 / 6, 1, 0, 5.0 / 6], - [3.5 / 6, 0, 5.0 / 6, 0], - ] - ) + ptr_expected = np.array([ + [0, 2.0 / 6, 3.5 / 6, 3.5 / 6], + [2.0 / 6, 0, 1, 0], + [3.5 / 6, 1, 0, 5.0 / 6], + [3.5 / 6, 0, 5.0 / 6, 0], + ]) _run_test(self, "zero-boost", self.loopless_undirected_input, ptr_expected) def test_zeroboost_looped_undirected(self): - ptr_expected = np.array( - [ - [0.4, 0.5, 0.75, 0.75], - [0.5, 0, 1, 0], - [0.75, 1, 0.6, 0.9], - [0.75, 0, 0.9, 0], - ] - ) + ptr_expected = np.array([ + [0.4, 0.5, 0.75, 0.75], + [0.5, 0, 1, 0], + [0.75, 1, 0.6, 0.9], + [0.75, 0, 0.9, 0], + ]) _run_test(self, "zero-boost", self.looped_undirected_input, ptr_expected) def test_zeroboost_loopless_directed(self): - ptr_expected = np.array( - [[0, 3.5, 7.5, 7.5], [3.5, 0, 10, 0], [5, 12, 0, 9], [6, 0, 11, 0]] - ) + ptr_expected = np.array([ + [0, 3.5, 7.5, 7.5], + [3.5, 0, 10, 0], + [5, 12, 0, 9], + [6, 0, 11, 0], + ]) ptr_expected /= 12 _run_test(self, "zero-boost", self.loopless_directed_input, ptr_expected) def test_zeroboost_looped_directed(self): - ptr_expected = np.array( - [[9, 5.5, 11.5, 11.5], [5.5, 0, 14, 0], [7, 16, 0, 13], [8, 0, 15, 10]] - ) + ptr_expected = np.array([ + [9, 5.5, 11.5, 11.5], + [5.5, 0, 14, 0], + [7, 16, 0, 13], + [8, 0, 15, 10], + ]) ptr_expected /= 16 _run_test(self, "zero-boost", self.looped_directed_input, ptr_expected) def test_simpleall_loopless_undirected(self): - ptr_expected = 0.5 * np.array( - [ - [0, 0.1764706, 0.5294118, 0.5294118], - [0.1764706, 0, 1.1176471, 0], - [0.5294118, 1.1176471, 0, 0.8823529], - [0.5294118, 0, 0.8823529, 0], - ] - ) + ptr_expected = 0.5 * np.array([ + [0, 0.1764706, 0.5294118, 0.5294118], + [0.1764706, 0, 1.1176471, 0], + [0.5294118, 1.1176471, 0, 0.8823529], + [0.5294118, 0, 0.8823529, 0], + ]) _run_test(self, "simple-all", self.loopless_undirected_input, ptr_expected) def test_simpleall_looped_undirected(self): - ptr_expected = 0.5 * np.array( - [ - [0.1176471, 0.2941176, 0.7647059, 0.7647059], - [0.2941176, 0, 1.3529412, 0], - [0.7647059, 1.3529412, 0.4705882, 1.1176471], - [0.7647059, 0, 1.1176471, 0], - ] - ) + ptr_expected = 0.5 * np.array([ + [0.1176471, 0.2941176, 0.7647059, 0.7647059], + [0.2941176, 0, 1.3529412, 0], + [0.7647059, 1.3529412, 0.4705882, 1.1176471], + [0.7647059, 0, 1.1176471, 0], + ]) _run_test(self, "simple-all", self.looped_undirected_input, ptr_expected) def test_simpleall_loopless_directed(self): - ptr_expected = 0.5 * np.array( - [ - [0, 0.1764706, 0.6470588, 0.6470588], - [0.1764706, 0, 0.9411765, 0], - [0.3529412, 1.1764706, 0, 0.8235294], - [0.4705882, 0, 1.0588235, 0], - ] - ) + ptr_expected = 0.5 * np.array([ + [0, 0.1764706, 0.6470588, 0.6470588], + [0.1764706, 0, 0.9411765, 0], + [0.3529412, 1.1764706, 0, 0.8235294], + [0.4705882, 0, 1.0588235, 0], + ]) _run_test(self, "simple-all", self.loopless_directed_input, ptr_expected) def test_simpleall_looped_directed(self): - ptr_expected = 0.5 * np.array( - [ - [0.5882353, 0.1764706, 0.8823529, 0.8823529], - [0.1764706, 0, 1.1764706, 0], - [0.3529412, 1.4117647, 0, 1.0588235], - [0.4705882, 0, 1.2941176, 0.7058824], - ] - ) + ptr_expected = 0.5 * np.array([ + [0.5882353, 0.1764706, 0.8823529, 0.8823529], + [0.1764706, 0, 1.1764706, 0], + [0.3529412, 1.4117647, 0, 1.0588235], + [0.4705882, 0, 1.2941176, 0.7058824], + ]) _run_test(self, "simple-all", self.looped_directed_input, ptr_expected) def test_simplenonzero_loopless_undirected(self): - ptr_expected = 0.5 * np.array( - [ - [0, 0.2727273, 0.8181818, 0.8181818], - [0.2727273, 0, 1.7272727, 0], - [0.8181818, 1.7272727, 0, 1.3636364], - [0.8181818, 0, 1.3636364, 0], - ] - ) + ptr_expected = 0.5 * np.array([ + [0, 0.2727273, 0.8181818, 0.8181818], + [0.2727273, 0, 1.7272727, 0], + [0.8181818, 1.7272727, 0, 1.3636364], + [0.8181818, 0, 1.3636364, 0], + ]) _run_test(self, "simple-nonzero", self.loopless_undirected_input, ptr_expected) def test_simplenonzero_looped_undirected(self): - ptr_expected = 0.5 * np.array( - [ - [0.1538462, 0.3846154, 1, 1], - [0.3846154, 0, 1.7692308, 0], - [1, 1.7692308, 0.6153846, 1.4615385], - [1, 0, 1.4615385, 0], - ] - ) + ptr_expected = 0.5 * np.array([ + [0.1538462, 0.3846154, 1, 1], + [0.3846154, 0, 1.7692308, 0], + [1, 1.7692308, 0.6153846, 1.4615385], + [1, 0, 1.4615385, 0], + ]) _run_test(self, "simple-nonzero", self.looped_undirected_input, ptr_expected) def test_simplenonzero_loopless_directed(self): - ptr_expected = 0.5 * np.array( - [ - [0, 0.2727273, 1, 1], - [0.2727273, 0, 1.4545455, 0], - [0.5454545, 1.8181818, 0, 1.2727273], - [0.7272727, 0, 1.6363636, 0], - ] - ) + ptr_expected = 0.5 * np.array([ + [0, 0.2727273, 1, 1], + [0.2727273, 0, 1.4545455, 0], + [0.5454545, 1.8181818, 0, 1.2727273], + [0.7272727, 0, 1.6363636, 0], + ]) _run_test(self, "simple-nonzero", self.loopless_directed_input, ptr_expected) def test_simplenonzero_looped_directed(self): - ptr_expected = 0.5 * np.array( - [ - [0.7692308, 0.2307692, 1.1538462, 1.1538462], - [0.2307692, 0, 1.5384615, 0], - [0.4615385, 1.8461538, 0, 1.3846154], - [0.6153846, 0, 1.6923077, 0.9230769], - ] - ) + ptr_expected = 0.5 * np.array([ + [0.7692308, 0.2307692, 1.1538462, 1.1538462], + [0.2307692, 0, 1.5384615, 0], + [0.4615385, 1.8461538, 0, 1.3846154], + [0.6153846, 0, 1.6923077, 0.9230769], + ]) _run_test(self, "simple-nonzero", self.looped_directed_input, ptr_expected) diff --git a/tests/test_sims.py b/tests/test_sims.py index 82d725d42..bcb465a04 100644 --- a/tests/test_sims.py +++ b/tests/test_sims.py @@ -439,21 +439,18 @@ def exp_unif(self, x): def test_sbm_multiwt_directed_loopless(self): np.random.seed(12345) - Wt = np.vstack( - ( - [np.random.normal, np.random.poisson], - [np.random.exponential, np.random.uniform], - ) - ) - Wtargs = np.vstack( - ( - [{"loc": 2, "scale": 2}, {"lam": 5}], - [{"scale": 2}, {"low": 5, "high": 10}], - ) - ) - check = np.vstack( - ([self.exp_normal, self.exp_poisson], [self.exp_exp, self.exp_unif]) - ) + Wt = np.vstack(( + [np.random.normal, np.random.poisson], + [np.random.exponential, np.random.uniform], + )) + Wtargs = np.vstack(( + [{"loc": 2, "scale": 2}, {"lam": 5}], + [{"scale": 2}, {"low": 5, "high": 10}], + )) + check = np.vstack(( + [self.exp_normal, self.exp_poisson], + [self.exp_exp, self.exp_unif], + )) A = sbm(self.n, self.Psy, wt=Wt, directed=True, wtargs=Wtargs) for i in range(0, len(self.n)): for j in range(0, len(self.n)): @@ -480,18 +477,18 @@ def test_sbm_multiwt_directed_loopless(self): def test_sbm_multiwt_undirected_loopless(self): np.random.seed(12345) - Wt = np.vstack( - ( - [np.random.normal, np.random.poisson], - [np.random.poisson, np.random.uniform], - ) - ) - Wtargs = np.vstack( - ([{"loc": 2, "scale": 2}, {"lam": 5}], [{"lam": 5}, {"low": 5, "high": 10}]) - ) - check = np.vstack( - ([self.exp_normal, self.exp_poisson], [self.exp_poisson, self.exp_unif]) - ) + Wt = np.vstack(( + [np.random.normal, np.random.poisson], + [np.random.poisson, np.random.uniform], + )) + Wtargs = np.vstack(( + [{"loc": 2, "scale": 2}, {"lam": 5}], + [{"lam": 5}, {"low": 5, "high": 10}], + )) + check = np.vstack(( + [self.exp_normal, self.exp_poisson], + [self.exp_poisson, self.exp_unif], + )) A = sbm(self.n, self.Psy, wt=Wt, directed=False, wtargs=Wtargs) for i in range(0, len(self.n)): for j in range(0, len(self.n)): @@ -518,21 +515,18 @@ def test_sbm_multiwt_undirected_loopless(self): def test_sbm_multiwt_directed_loopy(self): np.random.seed(12345) - Wt = np.vstack( - ( - [np.random.normal, np.random.poisson], - [np.random.exponential, np.random.uniform], - ) - ) - Wtargs = np.vstack( - ( - [{"loc": 2, "scale": 2}, {"lam": 5}], - [{"scale": 2}, {"low": 5, "high": 10}], - ) - ) - check = np.vstack( - ([self.exp_normal, self.exp_poisson], [self.exp_exp, self.exp_unif]) - ) + Wt = np.vstack(( + [np.random.normal, np.random.poisson], + [np.random.exponential, np.random.uniform], + )) + Wtargs = np.vstack(( + [{"loc": 2, "scale": 2}, {"lam": 5}], + [{"scale": 2}, {"low": 5, "high": 10}], + )) + check = np.vstack(( + [self.exp_normal, self.exp_poisson], + [self.exp_exp, self.exp_unif], + )) A = sbm(self.n, self.Psy, wt=Wt, directed=True, loops=True, wtargs=Wtargs) for i in range(0, len(self.n)): for j in range(0, len(self.n)): @@ -557,18 +551,18 @@ def test_sbm_multiwt_directed_loopy(self): def test_sbm_multiwt_undirected_loopy(self): np.random.seed(12345) - Wt = np.vstack( - ( - [np.random.normal, np.random.poisson], - [np.random.poisson, np.random.uniform], - ) - ) - Wtargs = np.vstack( - ([{"loc": 2, "scale": 2}, {"lam": 5}], [{"lam": 5}, {"low": 5, "high": 10}]) - ) - check = np.vstack( - ([self.exp_normal, self.exp_poisson], [self.exp_poisson, self.exp_unif]) - ) + Wt = np.vstack(( + [np.random.normal, np.random.poisson], + [np.random.poisson, np.random.uniform], + )) + Wtargs = np.vstack(( + [{"loc": 2, "scale": 2}, {"lam": 5}], + [{"lam": 5}, {"low": 5, "high": 10}], + )) + check = np.vstack(( + [self.exp_normal, self.exp_poisson], + [self.exp_poisson, self.exp_unif], + )) A = sbm(self.n, self.Psy, wt=Wt, directed=False, loops=True, wtargs=Wtargs) for i in range(0, len(self.n)): for j in range(0, len(self.n)): @@ -595,14 +589,10 @@ def test_sbm_dc_dc_kws_directed_loopy_weights(self): np.random.seed(self.seed) funcs = [np.random.power, np.random.uniform] dc_kwss = [{"a": 3}, {"low": 5, "high": 10}] - dc = np.hstack( - ( - [ - [funcs[i](**dc_kwss[i]) for _ in range(self.n[i])] - for i in range(len(self.n)) - ] - ) - ) + dc = np.hstack(([ + [funcs[i](**dc_kwss[i]) for _ in range(self.n[i])] + for i in range(len(self.n)) + ])) for i in range(0, len(self.n)): dc[self.vcount[i] - self.n[i] : self.vcount[i]] /= sum( dc[self.vcount[i] - self.n[i] : self.vcount[i]] @@ -611,12 +601,9 @@ def test_sbm_dc_dc_kws_directed_loopy_weights(self): communities = np.hstack([[comm] * self.n[comm] for comm in range(len(self.n))]) for i, ki in zip(range(sum(self.n)), communities): degree = sum([A[i][j] for j in range(sum(self.n))]) - theta_hat = degree / sum( - [ - self.Psy[ki][kj] * self.n[ki] * self.n[kj] - for kj in range(len(self.n)) - ] - ) + theta_hat = degree / sum([ + self.Psy[ki][kj] * self.n[ki] * self.n[kj] for kj in range(len(self.n)) + ]) self.assertTrue(np.isclose(theta_hat, dc[i], atol=0.01)) # check dimensions self.assertTrue(A.shape == (np.sum(self.n), np.sum(self.n))) diff --git a/tests/test_spectral_embed.py b/tests/test_spectral_embed.py index 0934598df..5e4f3807c 100644 --- a/tests/test_spectral_embed.py +++ b/tests/test_spectral_embed.py @@ -181,14 +181,12 @@ def test_directed_correct_latent_positions(self): # separate into communities for i, latent in enumerate([latent_left, latent_right]): left = i == 0 - df = pd.DataFrame( - { - "Type": labels, - "Dimension 1": latent[:, 0], - "Dimension 2": latent[:, 1], - "Dimension 3": latent[:, 2], - } - ) + df = pd.DataFrame({ + "Type": labels, + "Dimension 1": latent[:, 0], + "Dimension 2": latent[:, 1], + "Dimension 3": latent[:, 2], + }) # make sure that oos vertices are closer to their true community averages than other community averages means = df.groupby("Type").mean() if left: diff --git a/tests/test_svd.py b/tests/test_svd.py index f47eb7350..ce40609c9 100644 --- a/tests/test_svd.py +++ b/tests/test_svd.py @@ -29,12 +29,10 @@ def test_bad_inputs(self): def test_outputs(self): np.random.seed(123) - X = np.vstack( - [ - np.repeat([[0.2, 0.2, 0.2]], 50, axis=0), - np.repeat([[0.5, 0.5, 0.5]], 50, axis=0), - ] - ) + X = np.vstack([ + np.repeat([[0.2, 0.2, 0.2]], 50, axis=0), + np.repeat([[0.5, 0.5, 0.5]], 50, axis=0), + ]) P = X @ X.T A = np.random.binomial(1, P).astype(float) @@ -68,12 +66,10 @@ def test_outputs(self): def test_eigsh(self): np.random.seed(123) - X = np.vstack( - [ - np.repeat([[0.2, 0.2, 0.2]], 50, axis=0), - np.repeat([[0.5, 0.5, 0.5]], 50, axis=0), - ] - ) + X = np.vstack([ + np.repeat([[0.2, 0.2, 0.2]], 50, axis=0), + np.repeat([[0.5, 0.5, 0.5]], 50, axis=0), + ]) P = X @ X.T A = np.random.binomial(1, P).astype(float) A = symmetrize(A, method="triu") diff --git a/tests/test_utils.py b/tests/test_utils.py index 4a6b51e40..3e2cbf4e2 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -209,15 +209,13 @@ def test_is_almost_symmetric(self): class TestLCC(unittest.TestCase): def test_lcc_networkx(self): - expected_lcc_matrix = np.array( - [ - [0, 1, 1, 0, 0], - [0, 0, 0, 0, 0], - [0, 0, 0, 1, 1], - [0, 1, 0, 0, 0], - [0, 0, 1, 0, 0], - ] - ) + expected_lcc_matrix = np.array([ + [0, 1, 1, 0, 0], + [0, 0, 0, 0, 0], + [0, 0, 0, 1, 1], + [0, 1, 0, 0, 0], + [0, 0, 1, 0, 0], + ]) expected_nodelist = np.array([1, 2, 3, 4, 6]) g = nx.DiGraph() [g.add_node(i) for i in range(1, 7)] @@ -237,15 +235,13 @@ def test_lcc_networkx(self): np.testing.assert_array_equal(lcc_matrix, expected_lcc_matrix) def test_lcc_networkx_undirected(self): - expected_lcc_matrix = np.array( - [ - [0, 1, 1, 0, 0], - [1, 0, 0, 1, 0], - [1, 0, 0, 1, 1], - [0, 1, 1, 0, 0], - [0, 0, 1, 0, 0], - ] - ) + expected_lcc_matrix = np.array([ + [0, 1, 1, 0, 0], + [1, 0, 0, 1, 0], + [1, 0, 0, 1, 1], + [0, 1, 1, 0, 0], + [0, 0, 1, 0, 0], + ]) expected_nodelist = np.array([1, 2, 3, 4, 6]) g = nx.Graph() [g.add_node(i) for i in range(1, 7)] @@ -264,15 +260,13 @@ def test_lcc_networkx_undirected(self): np.testing.assert_array_equal(lcc_matrix, expected_lcc_matrix) def test_lcc_numpy(self): - expected_lcc_matrix = np.array( - [ - [0, 1, 1, 0, 0], - [0, 0, 0, 0, 0], - [0, 0, 0, 1, 1], - [0, 1, 0, 0, 0], - [0, 0, 1, 0, 0], - ] - ) + expected_lcc_matrix = np.array([ + [0, 1, 1, 0, 0], + [0, 0, 0, 0, 0], + [0, 0, 0, 1, 1], + [0, 1, 0, 0, 0], + [0, 0, 1, 0, 0], + ]) expected_nodelist = np.array([0, 1, 2, 3, 5]) g = nx.DiGraph() [g.add_node(i) for i in range(1, 7)] @@ -291,27 +285,23 @@ def test_lcc_numpy(self): np.testing.assert_array_equal(lcc_matrix, expected_lcc_matrix) def test_lcc_scipy(self): - expected_lcc_matrix = np.array( - [ - [0, 1, 1, 0, 0], - [0, 0, 0, 0, 0], - [0, 0, 0, 1, 1], - [0, 1, 0, 0, 0], - [0, 0, 1, 0, 0], - ] - ) + expected_lcc_matrix = np.array([ + [0, 1, 1, 0, 0], + [0, 0, 0, 0, 0], + [0, 0, 0, 1, 1], + [0, 1, 0, 0, 0], + [0, 0, 1, 0, 0], + ]) expected_nodelist = np.array([0, 1, 2, 3, 5]) - adjacency = np.array( - [ - [0, 1, 1, 0, 0, 0, 0], # connected - [0, 0, 0, 0, 0, 0, 0], # connected - [0, 0, 0, 1, 0, 1, 0], # connected - [0, 1, 0, 0, 0, 0, 0], # connected - [0, 0, 0, 0, 0, 0, 0], # not connected - [0, 0, 1, 0, 0, 0, 0], # connected - [0, 0, 0, 0, 0, 0, 0], # not connected - ] - ) + adjacency = np.array([ + [0, 1, 1, 0, 0, 0, 0], # connected + [0, 0, 0, 0, 0, 0, 0], # connected + [0, 0, 0, 1, 0, 1, 0], # connected + [0, 1, 0, 0, 0, 0, 0], # connected + [0, 0, 0, 0, 0, 0, 0], # not connected + [0, 0, 1, 0, 0, 0, 0], # connected + [0, 0, 0, 0, 0, 0, 0], # not connected + ]) sparse_adjacency = csr_array(adjacency) lcc_matrix, nodelist = gus.largest_connected_component( @@ -333,12 +323,18 @@ def test_lcc_scipy_empty(self): assert lcc_adjacency.shape[0] == 1 def test_multigraph_lcc_numpystack(self): - expected_g_matrix = np.array( - [[0, 1, 0, 0], [0, 0, 1, 1], [0, 0, 0, 0], [0, 1, 0, 0]] - ) - expected_f_matrix = np.array( - [[0, 1, 0, 0], [1, 0, 1, 1], [0, 0, 0, 0], [0, 1, 0, 0]] - ) + expected_g_matrix = np.array([ + [0, 1, 0, 0], + [0, 0, 1, 1], + [0, 0, 0, 0], + [0, 1, 0, 0], + ]) + expected_f_matrix = np.array([ + [0, 1, 0, 0], + [1, 0, 1, 1], + [0, 0, 0, 0], + [0, 1, 0, 0], + ]) expected_mats = [expected_f_matrix, expected_g_matrix] expected_nodelist = np.array([0, 2, 3, 5]) g = nx.DiGraph() @@ -391,12 +387,18 @@ def test_multigraph_lcc_recurse_numpylist(self): np.testing.assert_array_equal(nodelist, expected_nodelist) def test_multigraph_lcc_numpylist(self): - expected_g_matrix = np.array( - [[0, 1, 0, 0], [0, 0, 1, 1], [0, 0, 0, 0], [0, 1, 0, 0]] - ) - expected_f_matrix = np.array( - [[0, 1, 0, 0], [1, 0, 1, 1], [0, 0, 0, 0], [0, 1, 0, 0]] - ) + expected_g_matrix = np.array([ + [0, 1, 0, 0], + [0, 0, 1, 1], + [0, 0, 0, 0], + [0, 1, 0, 0], + ]) + expected_f_matrix = np.array([ + [0, 1, 0, 0], + [1, 0, 1, 1], + [0, 0, 0, 0], + [0, 1, 0, 0], + ]) expected_mats = [expected_f_matrix, expected_g_matrix] expected_nodelist = np.array([0, 2, 3, 5]) g = nx.DiGraph() @@ -422,12 +424,18 @@ def test_multigraph_lcc_numpylist(self): np.testing.assert_array_equal(graph, expected_mats[i]) def test_multigraph_lcc_networkx(self): - expected_g_matrix = np.array( - [[0, 1, 0, 0], [0, 0, 1, 1], [0, 0, 0, 0], [0, 1, 0, 0]] - ) - expected_f_matrix = np.array( - [[0, 1, 0, 0], [1, 0, 1, 1], [0, 0, 0, 0], [0, 1, 0, 0]] - ) + expected_g_matrix = np.array([ + [0, 1, 0, 0], + [0, 0, 1, 1], + [0, 0, 0, 0], + [0, 1, 0, 0], + ]) + expected_f_matrix = np.array([ + [0, 1, 0, 0], + [1, 0, 1, 1], + [0, 0, 0, 0], + [0, 1, 0, 0], + ]) expected_mats = [expected_f_matrix, expected_g_matrix] expected_nodelist = np.array([1, 3, 4, 6]) g = nx.DiGraph() @@ -463,15 +471,13 @@ def test_multigraph_union(self): class TestDiagonalAugment(unittest.TestCase): def test_augment_diagonal_undirected(self): - A = np.array( - [ - [0, 1, 1, 0, 0], - [1, 0, 0, 2, 1], - [1, 0, 0, 1, 1], - [0, 2, 1, 0, 0], - [0, 1, 1, 0, 0], - ] - ) + A = np.array([ + [0, 1, 1, 0, 0], + [1, 0, 0, 2, 1], + [1, 0, 0, 1, 1], + [0, 2, 1, 0, 0], + [0, 1, 1, 0, 0], + ]) expected = A.copy().astype(float) expected[0, 0] = 2.0 / 4 expected[1, 1] = 4.0 / 4 @@ -482,15 +488,13 @@ def test_augment_diagonal_undirected(self): np.testing.assert_array_equal(A_aug, expected) def test_augment_diagonal_directed(self): - A = np.array( - [ - [0, 1, -1, 0, 0], - [0, 0, 0, 2, 1], - [1, 0, 0, 1, 1], - [0, 2, 0, 0, 0], - [0, 0, 1, 0, 0], - ] - ) + A = np.array([ + [0, 1, -1, 0, 0], + [0, 0, 0, 2, 1], + [1, 0, 0, 1, 1], + [0, 2, 0, 0, 0], + [0, 0, 1, 0, 0], + ]) expected = A.copy().astype(float) expected[0, 0] = 1.5 / 4 expected[1, 1] = 3 / 4 @@ -515,24 +519,20 @@ def test_binarize(): class TestRemoveVertices(unittest.TestCase): def setUp(self): - self.directed = np.array( - [ - [0, 2, 3, 4, 5], - [6, 0, 8, 9, 10], - [11, 12, 0, 14, 15], - [16, 17, 18, 0, 20], - [21, 22, 23, 24, 0], - ] - ) - self.undirected = np.array( - [ - [0, 6, 11, 16, 21], - [6, 0, 12, 17, 22], - [11, 12, 0, 18, 23], - [16, 17, 18, 0, 24], - [21, 22, 23, 24, 0], - ] - ) + self.directed = np.array([ + [0, 2, 3, 4, 5], + [6, 0, 8, 9, 10], + [11, 12, 0, 14, 15], + [16, 17, 18, 0, 20], + [21, 22, 23, 24, 0], + ]) + self.undirected = np.array([ + [0, 6, 11, 16, 21], + [6, 0, 12, 17, 22], + [11, 12, 0, 18, 23], + [16, 17, 18, 0, 24], + [21, 22, 23, 24, 0], + ]) def test_undirected(self): # with list index From 9a6fdfc92eeb2a0d1ef16ee2818e1c34740fa8e1 Mon Sep 17 00:00:00 2001 From: Chris Trevino Date: Fri, 10 May 2024 13:06:11 -0700 Subject: [PATCH 2/5] update workflow to use `static_checks` task --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index afec275cb..3a36bf162 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -83,7 +83,7 @@ jobs: - name: Install dependencies run: poetry install - name: Run Format Check - run: poetry run poe format_check + run: poetry run poe static_checks test-coverage: runs-on: ubuntu-latest strategy: From c9162c1dc8ac5fb94b02e4cec2d7aee9079eafa7 Mon Sep 17 00:00:00 2001 From: Chris Trevino Date: Fri, 10 May 2024 14:07:03 -0700 Subject: [PATCH 3/5] enable some rules --- docs/conf.py | 9 +++--- graspologic/embed/base.py | 4 +-- graspologic/inference/binomial.py | 2 +- .../inference/group_connection_test.py | 10 +++---- graspologic/inference/latent_position_test.py | 6 ++-- graspologic/match/wrappers.py | 2 +- graspologic/partition/leiden.py | 4 +-- graspologic/pipeline/embed/__init__.py | 4 +-- pyproject.toml | 29 ++++++++++--------- tests/cluster/__init__.py | 0 tests/layouts/test_auto.py | 6 ++-- tests/partition/__init__.py | 0 tests/pipeline/embed/__init__.py | 0 13 files changed, 39 insertions(+), 37 deletions(-) create mode 100644 tests/cluster/__init__.py create mode 100644 tests/partition/__init__.py create mode 100644 tests/pipeline/embed/__init__.py diff --git a/docs/conf.py b/docs/conf.py index 8abfd50db..9bc51e0e6 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -15,6 +15,11 @@ import os import sys +# Use RTD Theme +import sphinx_rtd_theme + +import graspologic + sys.path.append(os.path.abspath("./sphinx-ext/")) sys.path.insert(0, os.path.abspath("..")) @@ -28,7 +33,6 @@ dir_realpath = os.path.dirname(realpath) sys.path.append(dir_realpath) -import graspologic version = graspologic.__version__ # Append "dev" and the github run to the version when on the dev branch @@ -117,9 +121,6 @@ pygments_style = "sphinx" smartquotes = False -# Use RTD Theme -import sphinx_rtd_theme - html_theme = "sphinx_rtd_theme" html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] html_theme_options = { diff --git a/graspologic/embed/base.py b/graspologic/embed/base.py index 26195c742..8619e80da 100644 --- a/graspologic/embed/base.py +++ b/graspologic/embed/base.py @@ -312,8 +312,8 @@ def transform(self, X): # type: ignore # correct types? if directed and not isinstance(X, tuple): if X.shape[0] == X.shape[1]: # in case original matrix was passed - msg = """A square matrix A was passed to ``transform`` in the directed case. - If this was the original in-sample matrix, either use ``fit_transform`` + msg = """A square matrix A was passed to ``transform`` in the directed case. + If this was the original in-sample matrix, either use ``fit_transform`` or pass a tuple (A.T, A). If this was an out-of-sample matrix, directed graphs require a tuple (X_out, X_in).""" raise TypeError(msg) diff --git a/graspologic/inference/binomial.py b/graspologic/inference/binomial.py index 5e4f19d3b..77532dd34 100644 --- a/graspologic/inference/binomial.py +++ b/graspologic/inference/binomial.py @@ -79,6 +79,6 @@ def binom_2samp( value=null_ratio, ) else: - raise ValueError() + raise ValueError return BinomialResult(stat, pvalue) diff --git a/graspologic/inference/group_connection_test.py b/graspologic/inference/group_connection_test.py index e00b8cde8..8bde03e45 100644 --- a/graspologic/inference/group_connection_test.py +++ b/graspologic/inference/group_connection_test.py @@ -378,18 +378,18 @@ def group_connection_test( B1, n_observed1, n_possible1, group_counts1 = fit_sbm(A1, labels1) B2, n_observed2, n_possible2, group_counts2 = fit_sbm(A2, labels2) if not n_observed1.index.equals(n_observed2.index): - raise ValueError() + raise ValueError elif not n_observed1.columns.equals(n_observed2.columns): - raise ValueError() + raise ValueError elif not n_possible1.index.equals(n_possible2.index): - raise ValueError() + raise ValueError elif not n_observed1.columns.equals(n_observed2.columns): - raise ValueError() + raise ValueError index = n_observed1.index.copy() if n_observed1.shape[0] != n_observed2.shape[0]: - raise ValueError() + raise ValueError K = n_observed1.shape[0] diff --git a/graspologic/inference/latent_position_test.py b/graspologic/inference/latent_position_test.py index d1b2c8a53..dfc7a2d86 100644 --- a/graspologic/inference/latent_position_test.py +++ b/graspologic/inference/latent_position_test.py @@ -124,9 +124,9 @@ def latent_position_test( if type(embedding) is not str: raise TypeError("embedding must be str") if type(n_bootstraps) is not int: - raise TypeError() + raise TypeError if type(test_case) is not str: - raise TypeError() + raise TypeError if n_bootstraps < 1: raise ValueError( "{} is invalid number of bootstraps, must be greater than 1".format( @@ -148,7 +148,7 @@ def latent_position_test( A1 = import_graph(A1) A2 = import_graph(A2) if not is_symmetric(A1) or not is_symmetric(A2): - raise NotImplementedError() # TODO asymmetric case + raise NotImplementedError # TODO asymmetric case if A1.shape != A2.shape: raise ValueError("Input matrices do not have matching dimensions") num_components: int diff --git a/graspologic/match/wrappers.py b/graspologic/match/wrappers.py index 5245d5a26..c086ff30f 100644 --- a/graspologic/match/wrappers.py +++ b/graspologic/match/wrappers.py @@ -30,7 +30,7 @@ class MatchResult(NamedTuple): indices_B: np.ndarray """ Indices in ``B`` which were matched. Element ``indices_B[i]`` was matched - to element ``indices_A[i]``. ``indices_B`` can also be thought of as a + to element ``indices_A[i]``. ``indices_B`` can also be thought of as a permutation of the nodes of ``B`` with respect to ``A``. """ diff --git a/graspologic/partition/leiden.py b/graspologic/partition/leiden.py index 40141be1f..b66a46196 100644 --- a/graspologic/partition/leiden.py +++ b/graspologic/partition/leiden.py @@ -352,8 +352,8 @@ class HierarchicalCluster(NamedTuple): """Only used when level != 0, but will indicate the previous cluster id that this node was in""" level: int """ - Each time a community has a higher population than we would like, we create a subnetwork - of that community and process it again to break it into smaller chunks. Each time we + Each time a community has a higher population than we would like, we create a subnetwork + of that community and process it again to break it into smaller chunks. Each time we detect this, the level increases by 1 """ is_final_cluster: bool diff --git a/graspologic/pipeline/embed/__init__.py b/graspologic/pipeline/embed/__init__.py index c15104a65..4b6b00d2d 100644 --- a/graspologic/pipeline/embed/__init__.py +++ b/graspologic/pipeline/embed/__init__.py @@ -8,9 +8,9 @@ by nearest neighbor services and visualization routines. """ -__SVD_SOLVER_TYPES = ["randomized", "full", "truncated"] - from .adjacency_spectral_embedding import adjacency_spectral_embedding from .embeddings import Embeddings, EmbeddingsView from .laplacian_spectral_embedding import laplacian_spectral_embedding from .omnibus_embedding import omnibus_embedding_pairwise + +__SVD_SOLVER_TYPES = ["randomized", "full", "truncated"] diff --git a/pyproject.toml b/pyproject.toml index e96f03d56..f9445687e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -102,21 +102,21 @@ validate = ["lint", "coverage", "docs", "tests"] [tool.ruff.lint] select = [ - # "E4", + "E4", # "E7", - # "E9", - # "W291", - # "YTT", - # "T10", - # "ICN", - # "INP", - # "Q", - # "RSE", - # "SLOT", - # "INT", - # "FLY", - # "LOG", - # "C90", + "E9", + "W291", + "YTT", + "T10", + "ICN", + "INP", + "Q", + "RSE", + "SLOT", + "INT", + "FLY", + "LOG", + "C90", # "T20", # "D", # "RET", @@ -171,6 +171,7 @@ ignore = [ [tool.ruff.lint.per-file-ignores] "tests/*" = ["S", "D", "ANN", "T201", "ASYNC", "ARG", "PTH", "TRY"] +"docs/*" = ["INP001"] "*.ipynb" = ["T201"] [tool.ruff.lint.pydocstyle] diff --git a/tests/cluster/__init__.py b/tests/cluster/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/layouts/test_auto.py b/tests/layouts/test_auto.py index efff81772..c13e1201a 100644 --- a/tests/layouts/test_auto.py +++ b/tests/layouts/test_auto.py @@ -5,14 +5,14 @@ import unittest import networkx as nx -import numpy +import numpy as np from graspologic.layouts.auto import _get_bounds, layout_umap class TestAuto(unittest.TestCase): def test_get_bounds(self): - y = numpy.array([(1, 2), (4, 5), (-1, -2), (10, -20)]) + y = np.array([(1, 2), (4, 5), (-1, -2), (10, -20)]) minx, miny, maxx, maxy = _get_bounds(y) self.assertEqual(-1, minx) self.assertEqual(-20, miny) @@ -51,7 +51,7 @@ def test_layout_umap_directed_weighted(self): graph = nx.erdos_renyi_graph(10, 0.7, directed=True) for s, t in graph.edges(): - graph.edges[s, t]["weight"] = numpy.random.randint(1, 10) + graph.edges[s, t]["weight"] = np.random.randint(1, 10) _, node_positions = layout_umap(graph=graph) diff --git a/tests/partition/__init__.py b/tests/partition/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/pipeline/embed/__init__.py b/tests/pipeline/embed/__init__.py new file mode 100644 index 000000000..e69de29bb From 96565759ae97eee2ed7607ea37c397c233a91332 Mon Sep 17 00:00:00 2001 From: Chris Trevino Date: Fri, 10 May 2024 14:41:25 -0700 Subject: [PATCH 4/5] enable 'tch' rules --- graspologic/embed/mds.py | 7 ++++--- pyproject.toml | 10 ++++++---- tests/test_n2v.py | 5 ++++- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/graspologic/embed/mds.py b/graspologic/embed/mds.py index c7d17155f..7c42f87db 100644 --- a/graspologic/embed/mds.py +++ b/graspologic/embed/mds.py @@ -1,18 +1,19 @@ # Copyright (c) Microsoft Corporation and contributors. # Licensed under the MIT License. -from typing import Any, Optional, Union +from typing import TYPE_CHECKING, Any, Optional, Union import numpy as np from sklearn.base import BaseEstimator from sklearn.utils import check_array from typing_extensions import Literal -from graspologic.types import Tuple - from ..utils import is_symmetric from .svd import SvdAlgorithmType, select_svd +if TYPE_CHECKING: + from graspologic.types import Tuple + def _get_centering_matrix(n: int) -> np.ndarray: """ diff --git a/pyproject.toml b/pyproject.toml index f9445687e..4a3f985d7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -82,6 +82,8 @@ _format_code = "ruff format . --preview" static_checks = 'ruff check . --preview' clean = "rm -rf docs/_build" type_check = "mypy ./graspologic" +fix = "ruff --preview check --fix ." +fix_unsafe = "ruff check --preview --fix --unsafe-fixes ." # Formatting format = ['_sort_imports', '_format_code'] @@ -127,20 +129,20 @@ select = [ # "S", # "G", # "ERA", - # "ASYNC", + "ASYNC", # "TID", # "UP", # "SLF", # "BLE", # "C4", - # "I", + "I", # "F", # "A", # "ARG", # "PTH", # "RUF", # "B", - # "TCH", + "TCH", # "DTZ", # "PYI", #"PT", @@ -170,7 +172,7 @@ ignore = [ ] [tool.ruff.lint.per-file-ignores] -"tests/*" = ["S", "D", "ANN", "T201", "ASYNC", "ARG", "PTH", "TRY"] +"tests/*" = ["S", "D", "ANN", "T201", "ASYNC", "ARG", "PTH", "TRY", "SLF"] "docs/*" = ["INP001"] "*.ipynb" = ["T201"] diff --git a/tests/test_n2v.py b/tests/test_n2v.py index 334bcb9b7..a3a684b03 100644 --- a/tests/test_n2v.py +++ b/tests/test_n2v.py @@ -2,13 +2,16 @@ # Licensed under the MIT License. import unittest +from typing import TYPE_CHECKING import networkx as nx -import numpy as np import graspologic.embed.n2v as n2v from graspologic.embed.n2v import _Node2VecGraph +if TYPE_CHECKING: + import numpy as np + class Node2VecEmbedTest(unittest.TestCase): def test_node2vec_embedding_correct_shape_is_returned(self): From a898d8bacfe1869029719d3536e9a371b99fa39a Mon Sep 17 00:00:00 2001 From: Chris Trevino Date: Fri, 10 May 2024 14:47:25 -0700 Subject: [PATCH 5/5] revert pipeline/embed/__init__.py export order --- graspologic/pipeline/embed/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/graspologic/pipeline/embed/__init__.py b/graspologic/pipeline/embed/__init__.py index 4b6b00d2d..b9a76c4d5 100644 --- a/graspologic/pipeline/embed/__init__.py +++ b/graspologic/pipeline/embed/__init__.py @@ -1,6 +1,6 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT license. - +# ruff: noqa: E402 SVD_SOLVER_TYPES needs to be first """ The embed module of ``graspologic.pipeline.embed`` is intended to provide faster application development support. The functions provided in it reflect common call @@ -8,9 +8,9 @@ by nearest neighbor services and visualization routines. """ +__SVD_SOLVER_TYPES = ["randomized", "full", "truncated"] from .adjacency_spectral_embedding import adjacency_spectral_embedding from .embeddings import Embeddings, EmbeddingsView from .laplacian_spectral_embedding import laplacian_spectral_embedding from .omnibus_embedding import omnibus_embedding_pairwise -__SVD_SOLVER_TYPES = ["randomized", "full", "truncated"]