okstra 0.114.0 → 0.115.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/kr/architecture.md +2 -2
- package/docs/kr/follow-ups/2026-07-10-final-report-option-3.md +51 -0
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/workers/report-writer-worker.md +1 -0
- package/runtime/prompts/lead/okstra-lead-contract.md +1 -1
- package/runtime/python/okstra_ctl/implementation_stage.py +46 -39
- package/runtime/python/okstra_ctl/report_views.py +151 -12
- package/runtime/python/okstra_ctl/run.py +24 -24
- package/runtime/python/okstra_ctl/worktree.py +1 -1
- package/runtime/python/okstra_token_usage/claude.py +58 -19
- package/runtime/python/okstra_token_usage/collect.py +3 -1
- package/runtime/python/okstra_vendor/__init__.py +3 -0
- package/runtime/schemas/final-report-v1.0.schema.json +20 -0
- package/runtime/templates/reports/final-report.template.md +14 -0
- package/runtime/templates/reports/i18n/en.json +23 -12
- package/runtime/templates/reports/i18n/ko.json +23 -12
- package/runtime/templates/reports/report.css +55 -0
- package/runtime/templates/reports/report.js +53 -1
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_approx_clust_coeff.py +0 -41
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_clique.py +0 -112
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_connectivity.py +0 -199
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_density.py +0 -146
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_distance_measures.py +0 -59
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_dominating_set.py +0 -78
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_kcomponents.py +0 -303
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_matching.py +0 -8
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_maxcut.py +0 -94
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_ramsey.py +0 -31
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_steinertree.py +0 -306
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_traveling_salesman.py +0 -1014
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_treewidth.py +0 -274
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_vertex_cover.py +0 -68
- package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/base_test.py +0 -81
- package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/test_connectivity.py +0 -143
- package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/test_correlation.py +0 -122
- package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/test_mixing.py +0 -174
- package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/test_neighbor_degree.py +0 -107
- package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/test_pairs.py +0 -87
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_basic.py +0 -125
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_centrality.py +0 -192
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_cluster.py +0 -84
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_covering.py +0 -33
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_edgelist.py +0 -240
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_extendability.py +0 -334
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_generators.py +0 -407
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_link_analysis.py +0 -218
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_matching.py +0 -327
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_matrix.py +0 -138
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_project.py +0 -409
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_redundancy.py +0 -35
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_spectral_bipartivity.py +0 -80
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_betweenness_centrality.py +0 -923
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_betweenness_centrality_subset.py +0 -354
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_closeness_centrality.py +0 -274
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_current_flow_betweenness_centrality.py +0 -259
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_current_flow_betweenness_centrality_subset.py +0 -147
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_current_flow_closeness.py +0 -43
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_degree_centrality.py +0 -144
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_dispersion.py +0 -73
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_eigenvector_centrality.py +0 -186
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_group.py +0 -277
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_harmonic_centrality.py +0 -122
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_katz_centrality.py +0 -345
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_laplacian_centrality.py +0 -220
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_load_centrality.py +0 -344
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_percolation_centrality.py +0 -87
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_reaching.py +0 -140
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_second_order_centrality.py +0 -82
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_subgraph.py +0 -110
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_trophic.py +0 -302
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_voterank.py +0 -64
- package/runtime/python/okstra_vendor/networkx/algorithms/coloring/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/coloring/tests/test_coloring.py +0 -863
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_asyn_fluid.py +0 -147
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_bipartitions.py +0 -157
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_centrality.py +0 -85
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_divisive.py +0 -106
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_kclique.py +0 -91
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_label_propagation.py +0 -241
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_leiden.py +0 -138
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_local.py +0 -76
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_louvain.py +0 -264
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_lukes.py +0 -152
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_modularity_max.py +0 -340
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_quality.py +0 -139
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_utils.py +0 -26
- package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_attracting.py +0 -70
- package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_biconnected.py +0 -248
- package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_connected.py +0 -138
- package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_semiconnected.py +0 -55
- package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_strongly_connected.py +0 -193
- package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_weakly_connected.py +0 -96
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_connectivity.py +0 -421
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_cuts.py +0 -309
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_disjoint_paths.py +0 -249
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_edge_augmentation.py +0 -502
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_edge_kcomponents.py +0 -488
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_kcomponents.py +0 -323
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_kcutsets.py +0 -280
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_stoer_wagner.py +0 -102
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/gl1.gpickle.bz2 +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/gw1.gpickle.bz2 +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/netgen-2.gpickle.bz2 +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/test_gomory_hu.py +0 -128
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/test_maxflow.py +0 -573
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/test_maxflow_large_graph.py +0 -155
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/test_mincost.py +0 -475
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/test_networksimplex.py +0 -481
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/wlm3.gpickle.bz2 +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/iso_r01_s80.A99 +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/iso_r01_s80.B99 +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/si2_b06_m200.A99 +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/si2_b06_m200.B99 +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_ismags.py +0 -719
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_isomorphism.py +0 -103
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_isomorphvf2.py +0 -490
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_match_helpers.py +0 -64
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_temporalisomorphvf2.py +0 -212
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_tree_isomorphism.py +0 -202
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_vf2pp.py +0 -1655
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_vf2pp_helpers.py +0 -3118
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_vf2userfunc.py +0 -196
- package/runtime/python/okstra_vendor/networkx/algorithms/link_analysis/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/link_analysis/tests/test_hits.py +0 -77
- package/runtime/python/okstra_vendor/networkx/algorithms/link_analysis/tests/test_pagerank.py +0 -213
- package/runtime/python/okstra_vendor/networkx/algorithms/minors/tests/test_contraction.py +0 -544
- package/runtime/python/okstra_vendor/networkx/algorithms/operators/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/operators/tests/test_all.py +0 -328
- package/runtime/python/okstra_vendor/networkx/algorithms/operators/tests/test_binary.py +0 -451
- package/runtime/python/okstra_vendor/networkx/algorithms/operators/tests/test_product.py +0 -491
- package/runtime/python/okstra_vendor/networkx/algorithms/operators/tests/test_unary.py +0 -55
- package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_astar.py +0 -254
- package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_dense.py +0 -212
- package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_dense_numpy.py +0 -88
- package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_generic.py +0 -511
- package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_unweighted.py +0 -149
- package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_weighted.py +0 -983
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_asteroidal.py +0 -23
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_boundary.py +0 -154
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_bridges.py +0 -144
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_broadcasting.py +0 -109
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_chains.py +0 -136
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_chordal.py +0 -129
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_clique.py +0 -300
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_cluster.py +0 -678
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_communicability.py +0 -80
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_core.py +0 -266
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_covering.py +0 -85
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_cuts.py +0 -171
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_cycles.py +0 -984
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_d_separation.py +0 -340
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_dag.py +0 -835
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_distance_measures.py +0 -831
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_distance_regular.py +0 -85
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_dominance.py +0 -299
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_dominating.py +0 -115
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_efficiency.py +0 -58
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_euler.py +0 -314
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_graph_hashing.py +0 -872
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_graphical.py +0 -163
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_hierarchy.py +0 -46
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_hybrid.py +0 -24
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_isolate.py +0 -26
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_link_prediction.py +0 -615
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_lowest_common_ancestors.py +0 -459
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_matching.py +0 -556
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_max_weight_clique.py +0 -179
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_mis.py +0 -62
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_moral.py +0 -15
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_node_classification.py +0 -140
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_non_randomness.py +0 -60
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_perfect_graph.py +0 -27
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_planar_drawing.py +0 -274
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_planarity.py +0 -556
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_polynomials.py +0 -57
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_reciprocity.py +0 -37
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_regular.py +0 -88
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_richclub.py +0 -149
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_similarity.py +0 -1158
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_simple_paths.py +0 -803
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_smallworld.py +0 -76
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_smetric.py +0 -8
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_sparsifiers.py +0 -138
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_structuralholes.py +0 -191
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_summarization.py +0 -642
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_swap.py +0 -179
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_threshold.py +0 -270
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_time_dependent.py +0 -431
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_tournament.py +0 -161
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_triads.py +0 -248
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_vitality.py +0 -41
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_voronoi.py +0 -103
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_walks.py +0 -54
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_wiener.py +0 -157
- package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/test_beamsearch.py +0 -25
- package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/test_bfs.py +0 -203
- package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/test_dfs.py +0 -307
- package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/test_edgebfs.py +0 -147
- package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/test_edgedfs.py +0 -131
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_branchings.py +0 -624
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_coding.py +0 -114
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_decomposition.py +0 -79
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_distance_measures.py +0 -99
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_mst.py +0 -934
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_operations.py +0 -53
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_recognition.py +0 -174
- package/runtime/python/okstra_vendor/networkx/classes/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/classes/tests/dispatch_interface.py +0 -192
- package/runtime/python/okstra_vendor/networkx/classes/tests/historical_tests.py +0 -476
- package/runtime/python/okstra_vendor/networkx/classes/tests/test_coreviews.py +0 -362
- package/runtime/python/okstra_vendor/networkx/classes/tests/test_digraph.py +0 -331
- package/runtime/python/okstra_vendor/networkx/classes/tests/test_digraph_historical.py +0 -110
- package/runtime/python/okstra_vendor/networkx/classes/tests/test_filters.py +0 -177
- package/runtime/python/okstra_vendor/networkx/classes/tests/test_function.py +0 -1045
- package/runtime/python/okstra_vendor/networkx/classes/tests/test_graph.py +0 -950
- package/runtime/python/okstra_vendor/networkx/classes/tests/test_graph_historical.py +0 -12
- package/runtime/python/okstra_vendor/networkx/classes/tests/test_graphviews.py +0 -349
- package/runtime/python/okstra_vendor/networkx/classes/tests/test_multidigraph.py +0 -459
- package/runtime/python/okstra_vendor/networkx/classes/tests/test_multigraph.py +0 -528
- package/runtime/python/okstra_vendor/networkx/classes/tests/test_reportviews.py +0 -1421
- package/runtime/python/okstra_vendor/networkx/classes/tests/test_special.py +0 -131
- package/runtime/python/okstra_vendor/networkx/classes/tests/test_subgraphviews.py +0 -371
- package/runtime/python/okstra_vendor/networkx/conftest.py +0 -261
- package/runtime/python/okstra_vendor/networkx/drawing/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_display_complex.png +0 -0
- package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_display_empty_graph.png +0 -0
- package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_display_house_with_colors.png +0 -0
- package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_display_labels_and_colors.png +0 -0
- package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_display_shortest_path.png +0 -0
- package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_house_with_colors.png +0 -0
- package/runtime/python/okstra_vendor/networkx/drawing/tests/test_agraph.py +0 -237
- package/runtime/python/okstra_vendor/networkx/drawing/tests/test_image_comparison_pylab_mpl.py +0 -229
- package/runtime/python/okstra_vendor/networkx/drawing/tests/test_latex.py +0 -285
- package/runtime/python/okstra_vendor/networkx/drawing/tests/test_layout.py +0 -631
- package/runtime/python/okstra_vendor/networkx/drawing/tests/test_pydot.py +0 -146
- package/runtime/python/okstra_vendor/networkx/drawing/tests/test_pylab.py +0 -1582
- package/runtime/python/okstra_vendor/networkx/generators/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_atlas.py +0 -75
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_classic.py +0 -642
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_cographs.py +0 -20
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_community.py +0 -362
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_degree_seq.py +0 -224
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_directed.py +0 -189
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_duplication.py +0 -103
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_ego.py +0 -39
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_expanders.py +0 -182
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_geometric.py +0 -488
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_harary_graph.py +0 -133
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_internet_as_graphs.py +0 -221
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_intersection.py +0 -28
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_interval_graph.py +0 -144
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_joint_degree_seq.py +0 -125
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_lattice.py +0 -264
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_line.py +0 -316
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_mycielski.py +0 -30
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_nonisomorphic_trees.py +0 -82
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_random_clustered.py +0 -33
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_random_graphs.py +0 -495
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_small.py +0 -220
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_spectral_graph_forge.py +0 -49
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_stochastic.py +0 -72
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_sudoku.py +0 -92
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_time_series.py +0 -64
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_trees.py +0 -195
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_triads.py +0 -15
- package/runtime/python/okstra_vendor/networkx/linalg/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/linalg/tests/test_algebraic_connectivity.py +0 -400
- package/runtime/python/okstra_vendor/networkx/linalg/tests/test_attrmatrix.py +0 -108
- package/runtime/python/okstra_vendor/networkx/linalg/tests/test_bethehessian.py +0 -40
- package/runtime/python/okstra_vendor/networkx/linalg/tests/test_graphmatrix.py +0 -275
- package/runtime/python/okstra_vendor/networkx/linalg/tests/test_laplacian.py +0 -334
- package/runtime/python/okstra_vendor/networkx/linalg/tests/test_modularity.py +0 -86
- package/runtime/python/okstra_vendor/networkx/linalg/tests/test_spectrum.py +0 -70
- package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tests/test_adjacency.py +0 -78
- package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tests/test_cytoscape.py +0 -78
- package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tests/test_node_link.py +0 -109
- package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tests/test_tree.py +0 -48
- package/runtime/python/okstra_vendor/networkx/readwrite/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_adjlist.py +0 -354
- package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_edgelist.py +0 -318
- package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_gexf.py +0 -612
- package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_gml.py +0 -744
- package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_graph6.py +0 -181
- package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_graphml.py +0 -1531
- package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_leda.py +0 -30
- package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_p2g.py +0 -63
- package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_pajek.py +0 -128
- package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_sparse6.py +0 -166
- package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_text.py +0 -1742
- package/runtime/python/okstra_vendor/networkx/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/tests/test_all_random_functions.py +0 -248
- package/runtime/python/okstra_vendor/networkx/tests/test_convert.py +0 -321
- package/runtime/python/okstra_vendor/networkx/tests/test_convert_numpy.py +0 -531
- package/runtime/python/okstra_vendor/networkx/tests/test_convert_pandas.py +0 -349
- package/runtime/python/okstra_vendor/networkx/tests/test_convert_scipy.py +0 -281
- package/runtime/python/okstra_vendor/networkx/tests/test_exceptions.py +0 -40
- package/runtime/python/okstra_vendor/networkx/tests/test_import.py +0 -11
- package/runtime/python/okstra_vendor/networkx/tests/test_lazy_imports.py +0 -96
- package/runtime/python/okstra_vendor/networkx/tests/test_relabel.py +0 -349
- package/runtime/python/okstra_vendor/networkx/tests/test_removed_functions_exception_messages.py +0 -8
- package/runtime/python/okstra_vendor/networkx/utils/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/utils/tests/test__init.py +0 -11
- package/runtime/python/okstra_vendor/networkx/utils/tests/test_backends.py +0 -225
- package/runtime/python/okstra_vendor/networkx/utils/tests/test_config.py +0 -263
- package/runtime/python/okstra_vendor/networkx/utils/tests/test_decorators.py +0 -510
- package/runtime/python/okstra_vendor/networkx/utils/tests/test_heaps.py +0 -131
- package/runtime/python/okstra_vendor/networkx/utils/tests/test_mapped_queue.py +0 -268
- package/runtime/python/okstra_vendor/networkx/utils/tests/test_misc.py +0 -393
- package/runtime/python/okstra_vendor/networkx/utils/tests/test_random_sequence.py +0 -53
- package/runtime/python/okstra_vendor/networkx/utils/tests/test_rcm.py +0 -63
- package/runtime/python/okstra_vendor/networkx/utils/tests/test_unionfind.py +0 -55
|
@@ -1,950 +0,0 @@
|
|
|
1
|
-
import gc
|
|
2
|
-
import pickle
|
|
3
|
-
import platform
|
|
4
|
-
import weakref
|
|
5
|
-
|
|
6
|
-
import pytest
|
|
7
|
-
|
|
8
|
-
import networkx as nx
|
|
9
|
-
from networkx.utils import edges_equal, graphs_equal, nodes_equal
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def test_degree_node_not_found_exception_message():
|
|
13
|
-
"""See gh-7740"""
|
|
14
|
-
G = nx.path_graph(5)
|
|
15
|
-
with pytest.raises(nx.NetworkXError, match="Node.*is not in the graph"):
|
|
16
|
-
G.degree(100)
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class BaseGraphTester:
|
|
20
|
-
"""Tests for data-structure independent graph class features."""
|
|
21
|
-
|
|
22
|
-
def test_contains(self):
|
|
23
|
-
G = self.K3
|
|
24
|
-
assert 1 in G
|
|
25
|
-
assert 4 not in G
|
|
26
|
-
assert "b" not in G
|
|
27
|
-
assert [] not in G # no exception for nonhashable
|
|
28
|
-
assert {1: 1} not in G # no exception for nonhashable
|
|
29
|
-
|
|
30
|
-
def test_order(self):
|
|
31
|
-
G = self.K3
|
|
32
|
-
assert len(G) == 3
|
|
33
|
-
assert G.order() == 3
|
|
34
|
-
assert G.number_of_nodes() == 3
|
|
35
|
-
|
|
36
|
-
def test_nodes(self):
|
|
37
|
-
G = self.K3
|
|
38
|
-
assert isinstance(G._node, G.node_dict_factory)
|
|
39
|
-
assert isinstance(G._adj, G.adjlist_outer_dict_factory)
|
|
40
|
-
assert all(
|
|
41
|
-
isinstance(adj, G.adjlist_inner_dict_factory) for adj in G._adj.values()
|
|
42
|
-
)
|
|
43
|
-
assert sorted(G.nodes()) == self.k3nodes
|
|
44
|
-
assert sorted(G.nodes(data=True)) == [(0, {}), (1, {}), (2, {})]
|
|
45
|
-
|
|
46
|
-
def test_none_node(self):
|
|
47
|
-
G = self.Graph()
|
|
48
|
-
with pytest.raises(ValueError):
|
|
49
|
-
G.add_node(None)
|
|
50
|
-
with pytest.raises(ValueError):
|
|
51
|
-
G.add_nodes_from([None])
|
|
52
|
-
with pytest.raises(ValueError):
|
|
53
|
-
G.add_edge(0, None)
|
|
54
|
-
with pytest.raises(ValueError):
|
|
55
|
-
G.add_edges_from([(0, None)])
|
|
56
|
-
|
|
57
|
-
def test_has_node(self):
|
|
58
|
-
G = self.K3
|
|
59
|
-
assert G.has_node(1)
|
|
60
|
-
assert not G.has_node(4)
|
|
61
|
-
assert not G.has_node([]) # no exception for nonhashable
|
|
62
|
-
assert not G.has_node({1: 1}) # no exception for nonhashable
|
|
63
|
-
|
|
64
|
-
def test_has_edge(self):
|
|
65
|
-
G = self.K3
|
|
66
|
-
assert G.has_edge(0, 1)
|
|
67
|
-
assert not G.has_edge(0, -1)
|
|
68
|
-
|
|
69
|
-
def test_neighbors(self):
|
|
70
|
-
G = self.K3
|
|
71
|
-
assert sorted(G.neighbors(0)) == [1, 2]
|
|
72
|
-
with pytest.raises(nx.NetworkXError):
|
|
73
|
-
G.neighbors(-1)
|
|
74
|
-
|
|
75
|
-
@pytest.mark.skipif(
|
|
76
|
-
platform.python_implementation() == "PyPy", reason="PyPy gc is different"
|
|
77
|
-
)
|
|
78
|
-
def test_memory_leak(self):
|
|
79
|
-
G = self.Graph()
|
|
80
|
-
|
|
81
|
-
def count_objects_of_type(_type):
|
|
82
|
-
# Iterating over all objects tracked by gc can include weak references
|
|
83
|
-
# whose weakly-referenced objects may no longer exist. Calling `isinstance`
|
|
84
|
-
# on such a weak reference will raise ReferenceError. There are at least
|
|
85
|
-
# three workarounds for this: one is to compare type names instead of using
|
|
86
|
-
# `isinstance` such as `type(obj).__name__ == typename`, another is to use
|
|
87
|
-
# `type(obj) == _type`, and the last is to ignore ProxyTypes as we do below.
|
|
88
|
-
# NOTE: even if this safeguard is deemed unnecessary to pass NetworkX tests,
|
|
89
|
-
# we should still keep it for maximum safety for other NetworkX backends.
|
|
90
|
-
return sum(
|
|
91
|
-
1
|
|
92
|
-
for obj in gc.get_objects()
|
|
93
|
-
if not isinstance(obj, weakref.ProxyTypes) and isinstance(obj, _type)
|
|
94
|
-
)
|
|
95
|
-
|
|
96
|
-
gc.collect()
|
|
97
|
-
before = count_objects_of_type(self.Graph)
|
|
98
|
-
G.copy()
|
|
99
|
-
gc.collect()
|
|
100
|
-
after = count_objects_of_type(self.Graph)
|
|
101
|
-
assert before == after
|
|
102
|
-
|
|
103
|
-
# test a subgraph of the base class
|
|
104
|
-
class MyGraph(self.Graph):
|
|
105
|
-
pass
|
|
106
|
-
|
|
107
|
-
gc.collect()
|
|
108
|
-
G = MyGraph()
|
|
109
|
-
before = count_objects_of_type(MyGraph)
|
|
110
|
-
G.copy()
|
|
111
|
-
gc.collect()
|
|
112
|
-
after = count_objects_of_type(MyGraph)
|
|
113
|
-
assert before == after
|
|
114
|
-
|
|
115
|
-
def test_edges(self):
|
|
116
|
-
G = self.K3
|
|
117
|
-
assert isinstance(G._adj, G.adjlist_outer_dict_factory)
|
|
118
|
-
assert edges_equal(G.edges(), [(0, 1), (0, 2), (1, 2)])
|
|
119
|
-
assert edges_equal(G.edges(0), [(0, 1), (0, 2)])
|
|
120
|
-
assert edges_equal(G.edges([0, 1]), [(0, 1), (0, 2), (1, 2)])
|
|
121
|
-
with pytest.raises(nx.NetworkXError):
|
|
122
|
-
G.edges(-1)
|
|
123
|
-
|
|
124
|
-
def test_degree(self):
|
|
125
|
-
G = self.K3
|
|
126
|
-
assert sorted(G.degree()) == [(0, 2), (1, 2), (2, 2)]
|
|
127
|
-
assert dict(G.degree()) == {0: 2, 1: 2, 2: 2}
|
|
128
|
-
assert G.degree(0) == 2
|
|
129
|
-
with pytest.raises(nx.NetworkXError):
|
|
130
|
-
G.degree(-1) # node not in graph
|
|
131
|
-
|
|
132
|
-
def test_size(self):
|
|
133
|
-
G = self.K3
|
|
134
|
-
assert G.size() == 3
|
|
135
|
-
assert G.number_of_edges() == 3
|
|
136
|
-
|
|
137
|
-
def test_nbunch_iter(self):
|
|
138
|
-
G = self.K3
|
|
139
|
-
assert nodes_equal(G.nbunch_iter(), self.k3nodes) # all nodes
|
|
140
|
-
assert nodes_equal(G.nbunch_iter(0), [0]) # single node
|
|
141
|
-
assert nodes_equal(G.nbunch_iter([0, 1]), [0, 1]) # sequence
|
|
142
|
-
# sequence with none in graph
|
|
143
|
-
assert nodes_equal(G.nbunch_iter([-1]), [])
|
|
144
|
-
# string sequence with none in graph
|
|
145
|
-
assert nodes_equal(G.nbunch_iter("foo"), [])
|
|
146
|
-
# node not in graph doesn't get caught upon creation of iterator
|
|
147
|
-
bunch = G.nbunch_iter(-1)
|
|
148
|
-
# but gets caught when iterator used
|
|
149
|
-
with pytest.raises(nx.NetworkXError, match="is not in the graph"):
|
|
150
|
-
list(bunch)
|
|
151
|
-
# unhashable doesn't get caught upon creation of iterator
|
|
152
|
-
bunch = G.nbunch_iter([0, 1, 2, {}])
|
|
153
|
-
# but gets caught when iterator hits the unhashable
|
|
154
|
-
with pytest.raises(
|
|
155
|
-
nx.NetworkXError, match="in sequence nbunch is not a valid node"
|
|
156
|
-
):
|
|
157
|
-
list(bunch)
|
|
158
|
-
|
|
159
|
-
def test_nbunch_iter_node_format_raise(self):
|
|
160
|
-
# Tests that a node that would have failed string formatting
|
|
161
|
-
# doesn't cause an error when attempting to raise a
|
|
162
|
-
# :exc:`nx.NetworkXError`.
|
|
163
|
-
|
|
164
|
-
# For more information, see pull request #1813.
|
|
165
|
-
G = self.Graph()
|
|
166
|
-
nbunch = [("x", set())]
|
|
167
|
-
with pytest.raises(nx.NetworkXError):
|
|
168
|
-
list(G.nbunch_iter(nbunch))
|
|
169
|
-
|
|
170
|
-
def test_selfloop_degree(self):
|
|
171
|
-
G = self.Graph()
|
|
172
|
-
G.add_edge(1, 1)
|
|
173
|
-
assert sorted(G.degree()) == [(1, 2)]
|
|
174
|
-
assert dict(G.degree()) == {1: 2}
|
|
175
|
-
assert G.degree(1) == 2
|
|
176
|
-
assert sorted(G.degree([1])) == [(1, 2)]
|
|
177
|
-
assert G.degree(1, weight="weight") == 2
|
|
178
|
-
|
|
179
|
-
def test_selfloops(self):
|
|
180
|
-
G = self.K3.copy()
|
|
181
|
-
G.add_edge(0, 0)
|
|
182
|
-
assert nodes_equal(nx.nodes_with_selfloops(G), [0])
|
|
183
|
-
assert edges_equal(nx.selfloop_edges(G), [(0, 0)])
|
|
184
|
-
assert nx.number_of_selfloops(G) == 1
|
|
185
|
-
G.remove_edge(0, 0)
|
|
186
|
-
G.add_edge(0, 0)
|
|
187
|
-
G.remove_edges_from([(0, 0)])
|
|
188
|
-
G.add_edge(1, 1)
|
|
189
|
-
G.remove_node(1)
|
|
190
|
-
G.add_edge(0, 0)
|
|
191
|
-
G.add_edge(1, 1)
|
|
192
|
-
G.remove_nodes_from([0, 1])
|
|
193
|
-
|
|
194
|
-
def test_cache_reset(self):
|
|
195
|
-
G = self.K3.copy()
|
|
196
|
-
old_adj = G.adj
|
|
197
|
-
assert id(G.adj) == id(old_adj)
|
|
198
|
-
G._adj = {}
|
|
199
|
-
assert id(G.adj) != id(old_adj)
|
|
200
|
-
|
|
201
|
-
old_nodes = G.nodes
|
|
202
|
-
assert id(G.nodes) == id(old_nodes)
|
|
203
|
-
G._node = {}
|
|
204
|
-
assert id(G.nodes) != id(old_nodes)
|
|
205
|
-
|
|
206
|
-
def test_attributes_cached(self):
|
|
207
|
-
G = self.K3.copy()
|
|
208
|
-
assert id(G.nodes) == id(G.nodes)
|
|
209
|
-
assert id(G.edges) == id(G.edges)
|
|
210
|
-
assert id(G.degree) == id(G.degree)
|
|
211
|
-
assert id(G.adj) == id(G.adj)
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
class BaseAttrGraphTester(BaseGraphTester):
|
|
215
|
-
"""Tests of graph class attribute features."""
|
|
216
|
-
|
|
217
|
-
def test_weighted_degree(self):
|
|
218
|
-
G = self.Graph()
|
|
219
|
-
G.add_edge(1, 2, weight=2, other=3)
|
|
220
|
-
G.add_edge(2, 3, weight=3, other=4)
|
|
221
|
-
assert sorted(d for n, d in G.degree(weight="weight")) == [2, 3, 5]
|
|
222
|
-
assert dict(G.degree(weight="weight")) == {1: 2, 2: 5, 3: 3}
|
|
223
|
-
assert G.degree(1, weight="weight") == 2
|
|
224
|
-
assert nodes_equal((G.degree([1], weight="weight")), [(1, 2)])
|
|
225
|
-
|
|
226
|
-
assert nodes_equal((d for n, d in G.degree(weight="other")), [3, 7, 4])
|
|
227
|
-
assert dict(G.degree(weight="other")) == {1: 3, 2: 7, 3: 4}
|
|
228
|
-
assert G.degree(1, weight="other") == 3
|
|
229
|
-
assert edges_equal((G.degree([1], weight="other")), [(1, 3)])
|
|
230
|
-
|
|
231
|
-
def add_attributes(self, G):
|
|
232
|
-
G.graph["foo"] = []
|
|
233
|
-
G.nodes[0]["foo"] = []
|
|
234
|
-
G.remove_edge(1, 2)
|
|
235
|
-
ll = []
|
|
236
|
-
G.add_edge(1, 2, foo=ll)
|
|
237
|
-
G.add_edge(2, 1, foo=ll)
|
|
238
|
-
|
|
239
|
-
def test_name(self):
|
|
240
|
-
G = self.Graph(name="")
|
|
241
|
-
assert G.name == ""
|
|
242
|
-
G = self.Graph(name="test")
|
|
243
|
-
assert G.name == "test"
|
|
244
|
-
|
|
245
|
-
def test_str_unnamed(self):
|
|
246
|
-
G = self.Graph()
|
|
247
|
-
G.add_edges_from([(1, 2), (2, 3)])
|
|
248
|
-
assert str(G) == f"{type(G).__name__} with 3 nodes and 2 edges"
|
|
249
|
-
|
|
250
|
-
def test_str_named(self):
|
|
251
|
-
G = self.Graph(name="foo")
|
|
252
|
-
G.add_edges_from([(1, 2), (2, 3)])
|
|
253
|
-
assert str(G) == f"{type(G).__name__} named 'foo' with 3 nodes and 2 edges"
|
|
254
|
-
|
|
255
|
-
def test_graph_chain(self):
|
|
256
|
-
G = self.Graph([(0, 1), (1, 2)])
|
|
257
|
-
DG = G.to_directed(as_view=True)
|
|
258
|
-
SDG = DG.subgraph([0, 1])
|
|
259
|
-
RSDG = SDG.reverse(copy=False)
|
|
260
|
-
assert G is DG._graph
|
|
261
|
-
assert DG is SDG._graph
|
|
262
|
-
assert SDG is RSDG._graph
|
|
263
|
-
|
|
264
|
-
def test_copy(self):
|
|
265
|
-
G = self.Graph()
|
|
266
|
-
G.add_node(0)
|
|
267
|
-
G.add_edge(1, 2)
|
|
268
|
-
self.add_attributes(G)
|
|
269
|
-
# copy edge datadict but any container attr are same
|
|
270
|
-
H = G.copy()
|
|
271
|
-
self.graphs_equal(H, G)
|
|
272
|
-
self.different_attrdict(H, G)
|
|
273
|
-
self.shallow_copy_attrdict(H, G)
|
|
274
|
-
|
|
275
|
-
def test_class_copy(self):
|
|
276
|
-
G = self.Graph()
|
|
277
|
-
G.add_node(0)
|
|
278
|
-
G.add_edge(1, 2)
|
|
279
|
-
self.add_attributes(G)
|
|
280
|
-
# copy edge datadict but any container attr are same
|
|
281
|
-
H = G.__class__(G)
|
|
282
|
-
self.graphs_equal(H, G)
|
|
283
|
-
self.different_attrdict(H, G)
|
|
284
|
-
self.shallow_copy_attrdict(H, G)
|
|
285
|
-
|
|
286
|
-
def test_fresh_copy(self):
|
|
287
|
-
G = self.Graph()
|
|
288
|
-
G.add_node(0)
|
|
289
|
-
G.add_edge(1, 2)
|
|
290
|
-
self.add_attributes(G)
|
|
291
|
-
# copy graph structure but use fresh datadict
|
|
292
|
-
H = G.__class__()
|
|
293
|
-
H.add_nodes_from(G)
|
|
294
|
-
H.add_edges_from(G.edges())
|
|
295
|
-
assert len(G.nodes[0]) == 1
|
|
296
|
-
ddict = G.adj[1][2][0] if G.is_multigraph() else G.adj[1][2]
|
|
297
|
-
assert len(ddict) == 1
|
|
298
|
-
assert len(H.nodes[0]) == 0
|
|
299
|
-
ddict = H.adj[1][2][0] if H.is_multigraph() else H.adj[1][2]
|
|
300
|
-
assert len(ddict) == 0
|
|
301
|
-
|
|
302
|
-
def is_deepcopy(self, H, G):
|
|
303
|
-
self.graphs_equal(H, G)
|
|
304
|
-
self.different_attrdict(H, G)
|
|
305
|
-
self.deep_copy_attrdict(H, G)
|
|
306
|
-
|
|
307
|
-
def deep_copy_attrdict(self, H, G):
|
|
308
|
-
self.deepcopy_graph_attr(H, G)
|
|
309
|
-
self.deepcopy_node_attr(H, G)
|
|
310
|
-
self.deepcopy_edge_attr(H, G)
|
|
311
|
-
|
|
312
|
-
def deepcopy_graph_attr(self, H, G):
|
|
313
|
-
assert G.graph["foo"] == H.graph["foo"]
|
|
314
|
-
G.graph["foo"].append(1)
|
|
315
|
-
assert G.graph["foo"] != H.graph["foo"]
|
|
316
|
-
|
|
317
|
-
def deepcopy_node_attr(self, H, G):
|
|
318
|
-
assert G.nodes[0]["foo"] == H.nodes[0]["foo"]
|
|
319
|
-
G.nodes[0]["foo"].append(1)
|
|
320
|
-
assert G.nodes[0]["foo"] != H.nodes[0]["foo"]
|
|
321
|
-
|
|
322
|
-
def deepcopy_edge_attr(self, H, G):
|
|
323
|
-
assert G[1][2]["foo"] == H[1][2]["foo"]
|
|
324
|
-
G[1][2]["foo"].append(1)
|
|
325
|
-
assert G[1][2]["foo"] != H[1][2]["foo"]
|
|
326
|
-
|
|
327
|
-
def is_shallow_copy(self, H, G):
|
|
328
|
-
self.graphs_equal(H, G)
|
|
329
|
-
self.shallow_copy_attrdict(H, G)
|
|
330
|
-
|
|
331
|
-
def shallow_copy_attrdict(self, H, G):
|
|
332
|
-
self.shallow_copy_graph_attr(H, G)
|
|
333
|
-
self.shallow_copy_node_attr(H, G)
|
|
334
|
-
self.shallow_copy_edge_attr(H, G)
|
|
335
|
-
|
|
336
|
-
def shallow_copy_graph_attr(self, H, G):
|
|
337
|
-
assert G.graph["foo"] == H.graph["foo"]
|
|
338
|
-
G.graph["foo"].append(1)
|
|
339
|
-
assert G.graph["foo"] == H.graph["foo"]
|
|
340
|
-
|
|
341
|
-
def shallow_copy_node_attr(self, H, G):
|
|
342
|
-
assert G.nodes[0]["foo"] == H.nodes[0]["foo"]
|
|
343
|
-
G.nodes[0]["foo"].append(1)
|
|
344
|
-
assert G.nodes[0]["foo"] == H.nodes[0]["foo"]
|
|
345
|
-
|
|
346
|
-
def shallow_copy_edge_attr(self, H, G):
|
|
347
|
-
assert G[1][2]["foo"] == H[1][2]["foo"]
|
|
348
|
-
G[1][2]["foo"].append(1)
|
|
349
|
-
assert G[1][2]["foo"] == H[1][2]["foo"]
|
|
350
|
-
|
|
351
|
-
def same_attrdict(self, H, G):
|
|
352
|
-
old_foo = H[1][2]["foo"]
|
|
353
|
-
H.adj[1][2]["foo"] = "baz"
|
|
354
|
-
assert G.edges == H.edges
|
|
355
|
-
H.adj[1][2]["foo"] = old_foo
|
|
356
|
-
assert G.edges == H.edges
|
|
357
|
-
|
|
358
|
-
old_foo = H.nodes[0]["foo"]
|
|
359
|
-
H.nodes[0]["foo"] = "baz"
|
|
360
|
-
assert G.nodes == H.nodes
|
|
361
|
-
H.nodes[0]["foo"] = old_foo
|
|
362
|
-
assert G.nodes == H.nodes
|
|
363
|
-
|
|
364
|
-
def different_attrdict(self, H, G):
|
|
365
|
-
old_foo = H[1][2]["foo"]
|
|
366
|
-
H.adj[1][2]["foo"] = "baz"
|
|
367
|
-
assert G._adj != H._adj
|
|
368
|
-
H.adj[1][2]["foo"] = old_foo
|
|
369
|
-
assert G._adj == H._adj
|
|
370
|
-
|
|
371
|
-
old_foo = H.nodes[0]["foo"]
|
|
372
|
-
H.nodes[0]["foo"] = "baz"
|
|
373
|
-
assert G._node != H._node
|
|
374
|
-
H.nodes[0]["foo"] = old_foo
|
|
375
|
-
assert G._node == H._node
|
|
376
|
-
|
|
377
|
-
def graphs_equal(self, H, G):
|
|
378
|
-
assert G._adj == H._adj
|
|
379
|
-
assert G._node == H._node
|
|
380
|
-
assert G.graph == H.graph
|
|
381
|
-
assert G.name == H.name
|
|
382
|
-
if not G.is_directed() and not H.is_directed():
|
|
383
|
-
assert H._adj[1][2] is H._adj[2][1]
|
|
384
|
-
assert G._adj[1][2] is G._adj[2][1]
|
|
385
|
-
else: # at least one is directed
|
|
386
|
-
if not G.is_directed():
|
|
387
|
-
G._pred = G._adj
|
|
388
|
-
G._succ = G._adj
|
|
389
|
-
if not H.is_directed():
|
|
390
|
-
H._pred = H._adj
|
|
391
|
-
H._succ = H._adj
|
|
392
|
-
assert G._pred == H._pred
|
|
393
|
-
assert G._succ == H._succ
|
|
394
|
-
assert H._succ[1][2] is H._pred[2][1]
|
|
395
|
-
assert G._succ[1][2] is G._pred[2][1]
|
|
396
|
-
|
|
397
|
-
def test_graph_attr(self):
|
|
398
|
-
G = self.K3.copy()
|
|
399
|
-
G.graph["foo"] = "bar"
|
|
400
|
-
assert isinstance(G.graph, G.graph_attr_dict_factory)
|
|
401
|
-
assert G.graph["foo"] == "bar"
|
|
402
|
-
del G.graph["foo"]
|
|
403
|
-
assert G.graph == {}
|
|
404
|
-
H = self.Graph(foo="bar")
|
|
405
|
-
assert H.graph["foo"] == "bar"
|
|
406
|
-
|
|
407
|
-
def test_node_attr(self):
|
|
408
|
-
G = self.K3.copy()
|
|
409
|
-
G.add_node(1, foo="bar")
|
|
410
|
-
assert all(
|
|
411
|
-
isinstance(d, G.node_attr_dict_factory) for u, d in G.nodes(data=True)
|
|
412
|
-
)
|
|
413
|
-
assert nodes_equal(G.nodes(), [0, 1, 2])
|
|
414
|
-
assert nodes_equal(G.nodes(data=True), [(0, {}), (1, {"foo": "bar"}), (2, {})])
|
|
415
|
-
G.nodes[1]["foo"] = "baz"
|
|
416
|
-
assert nodes_equal(G.nodes(data=True), [(0, {}), (1, {"foo": "baz"}), (2, {})])
|
|
417
|
-
assert nodes_equal(G.nodes(data="foo"), [(0, None), (1, "baz"), (2, None)])
|
|
418
|
-
assert nodes_equal(
|
|
419
|
-
G.nodes(data="foo", default="bar"), [(0, "bar"), (1, "baz"), (2, "bar")]
|
|
420
|
-
)
|
|
421
|
-
|
|
422
|
-
def test_node_attr2(self):
|
|
423
|
-
G = self.K3.copy()
|
|
424
|
-
a = {"foo": "bar"}
|
|
425
|
-
G.add_node(3, **a)
|
|
426
|
-
assert nodes_equal(G.nodes(), [0, 1, 2, 3])
|
|
427
|
-
assert nodes_equal(
|
|
428
|
-
G.nodes(data=True), [(0, {}), (1, {}), (2, {}), (3, {"foo": "bar"})]
|
|
429
|
-
)
|
|
430
|
-
|
|
431
|
-
def test_edge_lookup(self):
|
|
432
|
-
G = self.Graph()
|
|
433
|
-
G.add_edge(1, 2, foo="bar")
|
|
434
|
-
assert edges_equal(G.edges[1, 2], {"foo": "bar"})
|
|
435
|
-
|
|
436
|
-
def test_edge_attr(self):
|
|
437
|
-
G = self.Graph()
|
|
438
|
-
G.add_edge(1, 2, foo="bar")
|
|
439
|
-
assert all(
|
|
440
|
-
isinstance(d, G.edge_attr_dict_factory) for u, v, d in G.edges(data=True)
|
|
441
|
-
)
|
|
442
|
-
assert edges_equal(G.edges(data=True), [(1, 2, {"foo": "bar"})])
|
|
443
|
-
assert edges_equal(G.edges(data="foo"), [(1, 2, "bar")])
|
|
444
|
-
|
|
445
|
-
def test_edge_attr2(self):
|
|
446
|
-
G = self.Graph()
|
|
447
|
-
G.add_edges_from([(1, 2), (3, 4)], foo="foo")
|
|
448
|
-
assert edges_equal(
|
|
449
|
-
G.edges(data=True), [(1, 2, {"foo": "foo"}), (3, 4, {"foo": "foo"})]
|
|
450
|
-
)
|
|
451
|
-
assert edges_equal(G.edges(data="foo"), [(1, 2, "foo"), (3, 4, "foo")])
|
|
452
|
-
|
|
453
|
-
def test_edge_attr3(self):
|
|
454
|
-
G = self.Graph()
|
|
455
|
-
G.add_edges_from([(1, 2, {"weight": 32}), (3, 4, {"weight": 64})], foo="foo")
|
|
456
|
-
assert edges_equal(
|
|
457
|
-
G.edges(data=True),
|
|
458
|
-
[
|
|
459
|
-
(1, 2, {"foo": "foo", "weight": 32}),
|
|
460
|
-
(3, 4, {"foo": "foo", "weight": 64}),
|
|
461
|
-
],
|
|
462
|
-
)
|
|
463
|
-
|
|
464
|
-
G.remove_edges_from([(1, 2), (3, 4)])
|
|
465
|
-
G.add_edge(1, 2, data=7, spam="bar", bar="foo")
|
|
466
|
-
assert edges_equal(
|
|
467
|
-
G.edges(data=True), [(1, 2, {"data": 7, "spam": "bar", "bar": "foo"})]
|
|
468
|
-
)
|
|
469
|
-
|
|
470
|
-
def test_edge_attr4(self):
|
|
471
|
-
G = self.Graph()
|
|
472
|
-
G.add_edge(1, 2, data=7, spam="bar", bar="foo")
|
|
473
|
-
assert edges_equal(
|
|
474
|
-
G.edges(data=True), [(1, 2, {"data": 7, "spam": "bar", "bar": "foo"})]
|
|
475
|
-
)
|
|
476
|
-
G[1][2]["data"] = 10 # OK to set data like this
|
|
477
|
-
assert edges_equal(
|
|
478
|
-
G.edges(data=True), [(1, 2, {"data": 10, "spam": "bar", "bar": "foo"})]
|
|
479
|
-
)
|
|
480
|
-
|
|
481
|
-
G.adj[1][2]["data"] = 20
|
|
482
|
-
assert edges_equal(
|
|
483
|
-
G.edges(data=True), [(1, 2, {"data": 20, "spam": "bar", "bar": "foo"})]
|
|
484
|
-
)
|
|
485
|
-
G.edges[1, 2]["data"] = 21 # another spelling, "edge"
|
|
486
|
-
assert edges_equal(
|
|
487
|
-
G.edges(data=True), [(1, 2, {"data": 21, "spam": "bar", "bar": "foo"})]
|
|
488
|
-
)
|
|
489
|
-
G.adj[1][2]["listdata"] = [20, 200]
|
|
490
|
-
G.adj[1][2]["weight"] = 20
|
|
491
|
-
dd = {
|
|
492
|
-
"data": 21,
|
|
493
|
-
"spam": "bar",
|
|
494
|
-
"bar": "foo",
|
|
495
|
-
"listdata": [20, 200],
|
|
496
|
-
"weight": 20,
|
|
497
|
-
}
|
|
498
|
-
assert edges_equal(G.edges(data=True), [(1, 2, dd)])
|
|
499
|
-
|
|
500
|
-
def test_to_undirected(self):
|
|
501
|
-
G = self.K3
|
|
502
|
-
self.add_attributes(G)
|
|
503
|
-
H = nx.Graph(G)
|
|
504
|
-
self.is_shallow_copy(H, G)
|
|
505
|
-
self.different_attrdict(H, G)
|
|
506
|
-
H = G.to_undirected()
|
|
507
|
-
self.is_deepcopy(H, G)
|
|
508
|
-
|
|
509
|
-
def test_to_directed_as_view(self):
|
|
510
|
-
H = nx.path_graph(2, create_using=self.Graph)
|
|
511
|
-
H2 = H.to_directed(as_view=True)
|
|
512
|
-
assert H is H2._graph
|
|
513
|
-
assert H2.has_edge(0, 1)
|
|
514
|
-
assert H2.has_edge(1, 0) or H.is_directed()
|
|
515
|
-
pytest.raises(nx.NetworkXError, H2.add_node, -1)
|
|
516
|
-
pytest.raises(nx.NetworkXError, H2.add_edge, 1, 2)
|
|
517
|
-
H.add_edge(1, 2)
|
|
518
|
-
assert H2.has_edge(1, 2)
|
|
519
|
-
assert H2.has_edge(2, 1) or H.is_directed()
|
|
520
|
-
|
|
521
|
-
def test_to_undirected_as_view(self):
|
|
522
|
-
H = nx.path_graph(2, create_using=self.Graph)
|
|
523
|
-
H2 = H.to_undirected(as_view=True)
|
|
524
|
-
assert H is H2._graph
|
|
525
|
-
assert H2.has_edge(0, 1)
|
|
526
|
-
assert H2.has_edge(1, 0)
|
|
527
|
-
pytest.raises(nx.NetworkXError, H2.add_node, -1)
|
|
528
|
-
pytest.raises(nx.NetworkXError, H2.add_edge, 1, 2)
|
|
529
|
-
H.add_edge(1, 2)
|
|
530
|
-
assert H2.has_edge(1, 2)
|
|
531
|
-
assert H2.has_edge(2, 1)
|
|
532
|
-
|
|
533
|
-
def test_directed_class(self):
|
|
534
|
-
G = self.Graph()
|
|
535
|
-
|
|
536
|
-
class newGraph(G.to_undirected_class()):
|
|
537
|
-
def to_directed_class(self):
|
|
538
|
-
return newDiGraph
|
|
539
|
-
|
|
540
|
-
def to_undirected_class(self):
|
|
541
|
-
return newGraph
|
|
542
|
-
|
|
543
|
-
class newDiGraph(G.to_directed_class()):
|
|
544
|
-
def to_directed_class(self):
|
|
545
|
-
return newDiGraph
|
|
546
|
-
|
|
547
|
-
def to_undirected_class(self):
|
|
548
|
-
return newGraph
|
|
549
|
-
|
|
550
|
-
G = newDiGraph() if G.is_directed() else newGraph()
|
|
551
|
-
H = G.to_directed()
|
|
552
|
-
assert isinstance(H, newDiGraph)
|
|
553
|
-
H = G.to_undirected()
|
|
554
|
-
assert isinstance(H, newGraph)
|
|
555
|
-
|
|
556
|
-
def test_to_directed(self):
|
|
557
|
-
G = self.K3
|
|
558
|
-
self.add_attributes(G)
|
|
559
|
-
H = nx.DiGraph(G)
|
|
560
|
-
self.is_shallow_copy(H, G)
|
|
561
|
-
self.different_attrdict(H, G)
|
|
562
|
-
H = G.to_directed()
|
|
563
|
-
self.is_deepcopy(H, G)
|
|
564
|
-
|
|
565
|
-
def test_subgraph(self):
|
|
566
|
-
G = self.K3
|
|
567
|
-
self.add_attributes(G)
|
|
568
|
-
H = G.subgraph([0, 1, 2, 5])
|
|
569
|
-
self.graphs_equal(H, G)
|
|
570
|
-
self.same_attrdict(H, G)
|
|
571
|
-
self.shallow_copy_attrdict(H, G)
|
|
572
|
-
|
|
573
|
-
H = G.subgraph(0)
|
|
574
|
-
assert H.adj == {0: {}}
|
|
575
|
-
H = G.subgraph([])
|
|
576
|
-
assert H.adj == {}
|
|
577
|
-
assert G.adj != {}
|
|
578
|
-
|
|
579
|
-
def test_selfloops_attr(self):
|
|
580
|
-
G = self.K3.copy()
|
|
581
|
-
G.add_edge(0, 0)
|
|
582
|
-
G.add_edge(1, 1, weight=2)
|
|
583
|
-
assert edges_equal(
|
|
584
|
-
nx.selfloop_edges(G, data=True), [(0, 0, {}), (1, 1, {"weight": 2})]
|
|
585
|
-
)
|
|
586
|
-
assert edges_equal(
|
|
587
|
-
nx.selfloop_edges(G, data="weight"), [(0, 0, None), (1, 1, 2)]
|
|
588
|
-
)
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
class TestGraph(BaseAttrGraphTester):
|
|
592
|
-
"""Tests specific to dict-of-dict-of-dict graph data structure"""
|
|
593
|
-
|
|
594
|
-
def setup_method(self):
|
|
595
|
-
self.Graph = nx.Graph
|
|
596
|
-
# build dict-of-dict-of-dict K3
|
|
597
|
-
ed1, ed2, ed3 = ({}, {}, {})
|
|
598
|
-
self.k3adj = {0: {1: ed1, 2: ed2}, 1: {0: ed1, 2: ed3}, 2: {0: ed2, 1: ed3}}
|
|
599
|
-
self.k3edges = [(0, 1), (0, 2), (1, 2)]
|
|
600
|
-
self.k3nodes = [0, 1, 2]
|
|
601
|
-
self.K3 = self.Graph()
|
|
602
|
-
self.K3._adj = self.k3adj
|
|
603
|
-
self.K3._node = {}
|
|
604
|
-
self.K3._node[0] = {}
|
|
605
|
-
self.K3._node[1] = {}
|
|
606
|
-
self.K3._node[2] = {}
|
|
607
|
-
|
|
608
|
-
def test_pickle(self):
|
|
609
|
-
G = self.K3
|
|
610
|
-
pg = pickle.loads(pickle.dumps(G, -1))
|
|
611
|
-
self.graphs_equal(pg, G)
|
|
612
|
-
pg = pickle.loads(pickle.dumps(G))
|
|
613
|
-
self.graphs_equal(pg, G)
|
|
614
|
-
|
|
615
|
-
def test_data_input(self):
|
|
616
|
-
G = self.Graph({1: [2], 2: [1]}, name="test")
|
|
617
|
-
assert G.name == "test"
|
|
618
|
-
assert sorted(G.adj.items()) == [(1, {2: {}}), (2, {1: {}})]
|
|
619
|
-
|
|
620
|
-
def test_adjacency(self):
|
|
621
|
-
G = self.K3
|
|
622
|
-
assert dict(G.adjacency()) == {
|
|
623
|
-
0: {1: {}, 2: {}},
|
|
624
|
-
1: {0: {}, 2: {}},
|
|
625
|
-
2: {0: {}, 1: {}},
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
def test_getitem(self):
|
|
629
|
-
G = self.K3
|
|
630
|
-
assert G.adj[0] == {1: {}, 2: {}}
|
|
631
|
-
assert G[0] == {1: {}, 2: {}}
|
|
632
|
-
with pytest.raises(KeyError):
|
|
633
|
-
G.__getitem__("j")
|
|
634
|
-
with pytest.raises(TypeError):
|
|
635
|
-
G.__getitem__(["A"])
|
|
636
|
-
|
|
637
|
-
def test_add_node(self):
|
|
638
|
-
G = self.Graph()
|
|
639
|
-
G.add_node(0)
|
|
640
|
-
assert G.adj == {0: {}}
|
|
641
|
-
# test add attributes
|
|
642
|
-
G.add_node(1, c="red")
|
|
643
|
-
G.add_node(2, c="blue")
|
|
644
|
-
G.add_node(3, c="red")
|
|
645
|
-
assert G.nodes[1]["c"] == "red"
|
|
646
|
-
assert G.nodes[2]["c"] == "blue"
|
|
647
|
-
assert G.nodes[3]["c"] == "red"
|
|
648
|
-
# test updating attributes
|
|
649
|
-
G.add_node(1, c="blue")
|
|
650
|
-
G.add_node(2, c="red")
|
|
651
|
-
G.add_node(3, c="blue")
|
|
652
|
-
assert G.nodes[1]["c"] == "blue"
|
|
653
|
-
assert G.nodes[2]["c"] == "red"
|
|
654
|
-
assert G.nodes[3]["c"] == "blue"
|
|
655
|
-
|
|
656
|
-
def test_add_nodes_from(self):
|
|
657
|
-
G = self.Graph()
|
|
658
|
-
G.add_nodes_from([0, 1, 2])
|
|
659
|
-
assert G.adj == {0: {}, 1: {}, 2: {}}
|
|
660
|
-
# test add attributes
|
|
661
|
-
G.add_nodes_from([0, 1, 2], c="red")
|
|
662
|
-
assert G.nodes[0]["c"] == "red"
|
|
663
|
-
assert G.nodes[2]["c"] == "red"
|
|
664
|
-
# test that attribute dicts are not the same
|
|
665
|
-
assert G.nodes[0] is not G.nodes[1]
|
|
666
|
-
# test updating attributes
|
|
667
|
-
G.add_nodes_from([0, 1, 2], c="blue")
|
|
668
|
-
assert G.nodes[0]["c"] == "blue"
|
|
669
|
-
assert G.nodes[2]["c"] == "blue"
|
|
670
|
-
assert G.nodes[0] is not G.nodes[1]
|
|
671
|
-
# test tuple input
|
|
672
|
-
H = self.Graph()
|
|
673
|
-
H.add_nodes_from(G.nodes(data=True))
|
|
674
|
-
assert H.nodes[0]["c"] == "blue"
|
|
675
|
-
assert H.nodes[2]["c"] == "blue"
|
|
676
|
-
assert H.nodes[0] is not H.nodes[1]
|
|
677
|
-
# specific overrides general
|
|
678
|
-
H.add_nodes_from([0, (1, {"c": "green"}), (3, {"c": "cyan"})], c="red")
|
|
679
|
-
assert H.nodes[0]["c"] == "red"
|
|
680
|
-
assert H.nodes[1]["c"] == "green"
|
|
681
|
-
assert H.nodes[2]["c"] == "blue"
|
|
682
|
-
assert H.nodes[3]["c"] == "cyan"
|
|
683
|
-
|
|
684
|
-
def test_remove_node(self):
|
|
685
|
-
G = self.K3.copy()
|
|
686
|
-
G.remove_node(0)
|
|
687
|
-
assert G.adj == {1: {2: {}}, 2: {1: {}}}
|
|
688
|
-
with pytest.raises(nx.NetworkXError):
|
|
689
|
-
G.remove_node(-1)
|
|
690
|
-
|
|
691
|
-
# generator here to implement list,set,string...
|
|
692
|
-
|
|
693
|
-
def test_remove_nodes_from(self):
|
|
694
|
-
G = self.K3.copy()
|
|
695
|
-
G.remove_nodes_from([0, 1])
|
|
696
|
-
assert G.adj == {2: {}}
|
|
697
|
-
G.remove_nodes_from([-1]) # silent fail
|
|
698
|
-
|
|
699
|
-
def test_add_edge(self):
|
|
700
|
-
G = self.Graph()
|
|
701
|
-
G.add_edge(0, 1)
|
|
702
|
-
assert G.adj == {0: {1: {}}, 1: {0: {}}}
|
|
703
|
-
G = self.Graph()
|
|
704
|
-
G.add_edge(*(0, 1))
|
|
705
|
-
assert G.adj == {0: {1: {}}, 1: {0: {}}}
|
|
706
|
-
G = self.Graph()
|
|
707
|
-
with pytest.raises(ValueError):
|
|
708
|
-
G.add_edge(None, "anything")
|
|
709
|
-
|
|
710
|
-
def test_add_edges_from(self):
|
|
711
|
-
G = self.Graph()
|
|
712
|
-
G.add_edges_from([(0, 1), (0, 2, {"weight": 3})])
|
|
713
|
-
assert G.adj == {
|
|
714
|
-
0: {1: {}, 2: {"weight": 3}},
|
|
715
|
-
1: {0: {}},
|
|
716
|
-
2: {0: {"weight": 3}},
|
|
717
|
-
}
|
|
718
|
-
G = self.Graph()
|
|
719
|
-
G.add_edges_from([(0, 1), (0, 2, {"weight": 3}), (1, 2, {"data": 4})], data=2)
|
|
720
|
-
assert G.adj == {
|
|
721
|
-
0: {1: {"data": 2}, 2: {"weight": 3, "data": 2}},
|
|
722
|
-
1: {0: {"data": 2}, 2: {"data": 4}},
|
|
723
|
-
2: {0: {"weight": 3, "data": 2}, 1: {"data": 4}},
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
with pytest.raises(nx.NetworkXError):
|
|
727
|
-
G.add_edges_from([(0,)]) # too few in tuple
|
|
728
|
-
with pytest.raises(nx.NetworkXError):
|
|
729
|
-
G.add_edges_from([(0, 1, 2, 3)]) # too many in tuple
|
|
730
|
-
with pytest.raises(TypeError):
|
|
731
|
-
G.add_edges_from([0]) # not a tuple
|
|
732
|
-
with pytest.raises(ValueError):
|
|
733
|
-
G.add_edges_from([(None, 3), (3, 2)]) # None cannot be a node
|
|
734
|
-
|
|
735
|
-
def test_remove_edge(self):
|
|
736
|
-
G = self.K3.copy()
|
|
737
|
-
G.remove_edge(0, 1)
|
|
738
|
-
assert G.adj == {0: {2: {}}, 1: {2: {}}, 2: {0: {}, 1: {}}}
|
|
739
|
-
with pytest.raises(nx.NetworkXError):
|
|
740
|
-
G.remove_edge(-1, 0)
|
|
741
|
-
|
|
742
|
-
def test_remove_edges_from(self):
|
|
743
|
-
G = self.K3.copy()
|
|
744
|
-
G.remove_edges_from([(0, 1)])
|
|
745
|
-
assert G.adj == {0: {2: {}}, 1: {2: {}}, 2: {0: {}, 1: {}}}
|
|
746
|
-
G.remove_edges_from([(0, 0)]) # silent fail
|
|
747
|
-
|
|
748
|
-
def test_clear(self):
|
|
749
|
-
G = self.K3.copy()
|
|
750
|
-
G.graph["name"] = "K3"
|
|
751
|
-
G.clear()
|
|
752
|
-
assert list(G.nodes) == []
|
|
753
|
-
assert G.adj == {}
|
|
754
|
-
assert G.graph == {}
|
|
755
|
-
|
|
756
|
-
def test_clear_edges(self):
|
|
757
|
-
G = self.K3.copy()
|
|
758
|
-
G.graph["name"] = "K3"
|
|
759
|
-
nodes = list(G.nodes)
|
|
760
|
-
G.clear_edges()
|
|
761
|
-
assert list(G.nodes) == nodes
|
|
762
|
-
assert G.adj == {0: {}, 1: {}, 2: {}}
|
|
763
|
-
assert list(G.edges) == []
|
|
764
|
-
assert G.graph["name"] == "K3"
|
|
765
|
-
|
|
766
|
-
def test_edges_data(self):
|
|
767
|
-
G = self.K3
|
|
768
|
-
all_edges = [(0, 1, {}), (0, 2, {}), (1, 2, {})]
|
|
769
|
-
assert edges_equal(G.edges(data=True), all_edges)
|
|
770
|
-
assert edges_equal(G.edges(0, data=True), [(0, 1, {}), (0, 2, {})])
|
|
771
|
-
assert edges_equal(G.edges([0, 1], data=True), all_edges)
|
|
772
|
-
with pytest.raises(nx.NetworkXError):
|
|
773
|
-
G.edges(-1, True)
|
|
774
|
-
|
|
775
|
-
def test_get_edge_data(self):
|
|
776
|
-
G = self.K3.copy()
|
|
777
|
-
assert G.get_edge_data(0, 1) == {}
|
|
778
|
-
assert G[0][1] == {}
|
|
779
|
-
assert G.get_edge_data(10, 20) is None
|
|
780
|
-
assert G.get_edge_data(-1, 0) is None
|
|
781
|
-
assert G.get_edge_data(-1, 0, default=1) == 1
|
|
782
|
-
|
|
783
|
-
def test_update(self):
|
|
784
|
-
# specify both edges and nodes
|
|
785
|
-
G = self.K3.copy()
|
|
786
|
-
G.update(nodes=[3, (4, {"size": 2})], edges=[(4, 5), (6, 7, {"weight": 2})])
|
|
787
|
-
nlist = [
|
|
788
|
-
(0, {}),
|
|
789
|
-
(1, {}),
|
|
790
|
-
(2, {}),
|
|
791
|
-
(3, {}),
|
|
792
|
-
(4, {"size": 2}),
|
|
793
|
-
(5, {}),
|
|
794
|
-
(6, {}),
|
|
795
|
-
(7, {}),
|
|
796
|
-
]
|
|
797
|
-
assert sorted(G.nodes.data()) == nlist
|
|
798
|
-
if G.is_directed():
|
|
799
|
-
elist = [
|
|
800
|
-
(0, 1, {}),
|
|
801
|
-
(0, 2, {}),
|
|
802
|
-
(1, 0, {}),
|
|
803
|
-
(1, 2, {}),
|
|
804
|
-
(2, 0, {}),
|
|
805
|
-
(2, 1, {}),
|
|
806
|
-
(4, 5, {}),
|
|
807
|
-
(6, 7, {"weight": 2}),
|
|
808
|
-
]
|
|
809
|
-
else:
|
|
810
|
-
elist = [
|
|
811
|
-
(0, 1, {}),
|
|
812
|
-
(0, 2, {}),
|
|
813
|
-
(1, 2, {}),
|
|
814
|
-
(4, 5, {}),
|
|
815
|
-
(6, 7, {"weight": 2}),
|
|
816
|
-
]
|
|
817
|
-
assert sorted(G.edges.data()) == elist
|
|
818
|
-
assert G.graph == {}
|
|
819
|
-
|
|
820
|
-
# no keywords -- order is edges, nodes
|
|
821
|
-
G = self.K3.copy()
|
|
822
|
-
G.update([(4, 5), (6, 7, {"weight": 2})], [3, (4, {"size": 2})])
|
|
823
|
-
assert sorted(G.nodes.data()) == nlist
|
|
824
|
-
assert sorted(G.edges.data()) == elist
|
|
825
|
-
assert G.graph == {}
|
|
826
|
-
|
|
827
|
-
# update using only a graph
|
|
828
|
-
G = self.Graph()
|
|
829
|
-
G.graph["foo"] = "bar"
|
|
830
|
-
G.add_node(2, data=4)
|
|
831
|
-
G.add_edge(0, 1, weight=0.5)
|
|
832
|
-
GG = G.copy()
|
|
833
|
-
H = self.Graph()
|
|
834
|
-
GG.update(H)
|
|
835
|
-
assert graphs_equal(G, GG)
|
|
836
|
-
H.update(G)
|
|
837
|
-
assert graphs_equal(H, G)
|
|
838
|
-
|
|
839
|
-
# update nodes only
|
|
840
|
-
H = self.Graph()
|
|
841
|
-
H.update(nodes=[3, 4])
|
|
842
|
-
assert H.nodes ^ {3, 4} == set()
|
|
843
|
-
assert H.size() == 0
|
|
844
|
-
|
|
845
|
-
# update edges only
|
|
846
|
-
H = self.Graph()
|
|
847
|
-
H.update(edges=[(3, 4)])
|
|
848
|
-
assert sorted(H.edges.data()) == [(3, 4, {})]
|
|
849
|
-
assert H.size() == 1
|
|
850
|
-
|
|
851
|
-
# No inputs -> exception
|
|
852
|
-
with pytest.raises(nx.NetworkXError):
|
|
853
|
-
nx.Graph().update()
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
class TestEdgeSubgraph:
|
|
857
|
-
"""Unit tests for the :meth:`Graph.edge_subgraph` method."""
|
|
858
|
-
|
|
859
|
-
def setup_method(self):
|
|
860
|
-
# Create a path graph on five nodes.
|
|
861
|
-
G = nx.path_graph(5)
|
|
862
|
-
# Add some node, edge, and graph attributes.
|
|
863
|
-
for i in range(5):
|
|
864
|
-
G.nodes[i]["name"] = f"node{i}"
|
|
865
|
-
G.edges[0, 1]["name"] = "edge01"
|
|
866
|
-
G.edges[3, 4]["name"] = "edge34"
|
|
867
|
-
G.graph["name"] = "graph"
|
|
868
|
-
# Get the subgraph induced by the first and last edges.
|
|
869
|
-
self.G = G
|
|
870
|
-
self.H = G.edge_subgraph([(0, 1), (3, 4)])
|
|
871
|
-
|
|
872
|
-
def test_correct_nodes(self):
|
|
873
|
-
"""Tests that the subgraph has the correct nodes."""
|
|
874
|
-
assert [0, 1, 3, 4] == sorted(self.H.nodes())
|
|
875
|
-
|
|
876
|
-
def test_correct_edges(self):
|
|
877
|
-
"""Tests that the subgraph has the correct edges."""
|
|
878
|
-
assert [(0, 1, "edge01"), (3, 4, "edge34")] == sorted(self.H.edges(data="name"))
|
|
879
|
-
|
|
880
|
-
def test_add_node(self):
|
|
881
|
-
"""Tests that adding a node to the original graph does not
|
|
882
|
-
affect the nodes of the subgraph.
|
|
883
|
-
|
|
884
|
-
"""
|
|
885
|
-
self.G.add_node(5)
|
|
886
|
-
assert [0, 1, 3, 4] == sorted(self.H.nodes())
|
|
887
|
-
|
|
888
|
-
def test_remove_node(self):
|
|
889
|
-
"""Tests that removing a node in the original graph does
|
|
890
|
-
affect the nodes of the subgraph.
|
|
891
|
-
|
|
892
|
-
"""
|
|
893
|
-
self.G.remove_node(0)
|
|
894
|
-
assert [1, 3, 4] == sorted(self.H.nodes())
|
|
895
|
-
|
|
896
|
-
def test_node_attr_dict(self):
|
|
897
|
-
"""Tests that the node attribute dictionary of the two graphs is
|
|
898
|
-
the same object.
|
|
899
|
-
|
|
900
|
-
"""
|
|
901
|
-
for v in self.H:
|
|
902
|
-
assert self.G.nodes[v] == self.H.nodes[v]
|
|
903
|
-
# Making a change to G should make a change in H and vice versa.
|
|
904
|
-
self.G.nodes[0]["name"] = "foo"
|
|
905
|
-
assert self.G.nodes[0] == self.H.nodes[0]
|
|
906
|
-
self.H.nodes[1]["name"] = "bar"
|
|
907
|
-
assert self.G.nodes[1] == self.H.nodes[1]
|
|
908
|
-
|
|
909
|
-
def test_edge_attr_dict(self):
|
|
910
|
-
"""Tests that the edge attribute dictionary of the two graphs is
|
|
911
|
-
the same object.
|
|
912
|
-
|
|
913
|
-
"""
|
|
914
|
-
for u, v in self.H.edges():
|
|
915
|
-
assert self.G.edges[u, v] == self.H.edges[u, v]
|
|
916
|
-
# Making a change to G should make a change in H and vice versa.
|
|
917
|
-
self.G.edges[0, 1]["name"] = "foo"
|
|
918
|
-
assert self.G.edges[0, 1]["name"] == self.H.edges[0, 1]["name"]
|
|
919
|
-
self.H.edges[3, 4]["name"] = "bar"
|
|
920
|
-
assert self.G.edges[3, 4]["name"] == self.H.edges[3, 4]["name"]
|
|
921
|
-
|
|
922
|
-
def test_graph_attr_dict(self):
|
|
923
|
-
"""Tests that the graph attribute dictionary of the two graphs
|
|
924
|
-
is the same object.
|
|
925
|
-
|
|
926
|
-
"""
|
|
927
|
-
assert self.G.graph is self.H.graph
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
def test_graph_new_extra_args():
|
|
931
|
-
"""Test that subclasses can accept additional arguments.
|
|
932
|
-
|
|
933
|
-
See: https://github.com/networkx/networkx/issues/8367
|
|
934
|
-
"""
|
|
935
|
-
|
|
936
|
-
class MyGraph(nx.Graph):
|
|
937
|
-
def __init__(self, incoming_graph_data=None, extra_arg=None, **attr):
|
|
938
|
-
super().__init__(incoming_graph_data, **attr)
|
|
939
|
-
self.extra_arg = extra_arg
|
|
940
|
-
|
|
941
|
-
G = MyGraph(extra_arg="extra arg")
|
|
942
|
-
assert G.extra_arg == "extra arg"
|
|
943
|
-
|
|
944
|
-
G = MyGraph([], "extra arg")
|
|
945
|
-
assert G.extra_arg == "extra arg"
|
|
946
|
-
|
|
947
|
-
G = MyGraph([(0, 1)], extra_arg="foo", name="bar")
|
|
948
|
-
assert G.extra_arg == "foo"
|
|
949
|
-
assert G.graph["name"] == "bar"
|
|
950
|
-
assert nx.utils.edges_equal(G.edges, [(0, 1)])
|