napistu 0.3.7__py3-none-any.whl → 0.4.0__py3-none-any.whl

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.
@@ -1,20 +1,26 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import os
4
- import pytest
5
4
 
6
5
  import numpy as np
7
6
  import pandas as pd
7
+ import pandas.testing as pdt
8
+ import pytest
8
9
 
9
10
  from napistu import sbml_dfs_core
10
11
  from napistu.ingestion import sbml
11
12
  from napistu.network import net_create
13
+ from napistu.network import net_create_utils
12
14
  from napistu.network import ng_utils
13
- from napistu.constants import MINI_SBO_FROM_NAME
14
15
  from napistu.constants import SBML_DFS
15
- from napistu.network.constants import DEFAULT_WT_TRANS
16
- from napistu.network.constants import WEIGHTING_SPEC
17
-
16
+ from napistu.network.constants import (
17
+ DROP_REACTIONS_WHEN,
18
+ DEFAULT_WT_TRANS,
19
+ WEIGHTING_SPEC,
20
+ GRAPH_WIRING_APPROACHES,
21
+ NAPISTU_GRAPH_EDGES,
22
+ VALID_GRAPH_WIRING_APPROACHES,
23
+ )
18
24
 
19
25
  test_path = os.path.abspath(os.path.join(__file__, os.pardir))
20
26
  test_data = os.path.join(test_path, "test_data")
@@ -24,102 +30,72 @@ sbml_model = sbml.SBML(sbml_path)
24
30
  sbml_dfs = sbml_dfs_core.SBML_dfs(sbml_model)
25
31
 
26
32
 
27
- @pytest.fixture
28
- def reaction_species_examples(sbml_dfs):
29
- """
30
- Pytest fixture providing a dictionary of example reaction species DataFrames for various test cases.
31
- """
32
- r_id = sbml_dfs.reactions.index[0]
33
- d = dict()
34
- d["valid_interactor"] = pd.DataFrame(
35
- {
36
- "r_id": [r_id, r_id],
37
- "sbo_term": [
38
- MINI_SBO_FROM_NAME["interactor"],
39
- MINI_SBO_FROM_NAME["interactor"],
40
- ],
41
- "sc_id": ["sc1", "sc2"],
42
- "stoichiometry": [0, 0],
43
- }
44
- ).set_index(["r_id", "sbo_term"])
45
- d["invalid_interactor"] = pd.DataFrame(
46
- {
47
- "r_id": [r_id, r_id],
48
- "sbo_term": [
49
- MINI_SBO_FROM_NAME["interactor"],
50
- MINI_SBO_FROM_NAME["product"],
51
- ],
52
- "sc_id": ["sc1", "sc2"],
53
- "stoichiometry": [0, 0],
54
- }
55
- ).set_index(["r_id", "sbo_term"])
56
- d["sub_and_prod"] = pd.DataFrame(
57
- {
58
- "r_id": [r_id, r_id],
59
- "sbo_term": [MINI_SBO_FROM_NAME["reactant"], MINI_SBO_FROM_NAME["product"]],
60
- "sc_id": ["sub", "prod"],
61
- "stoichiometry": [-1, 1],
62
- }
63
- ).set_index(["r_id", "sbo_term"])
64
- d["stimulator"] = pd.DataFrame(
65
- {
66
- "r_id": [r_id, r_id, r_id],
67
- "sbo_term": [
68
- MINI_SBO_FROM_NAME["reactant"],
69
- MINI_SBO_FROM_NAME["product"],
70
- MINI_SBO_FROM_NAME["stimulator"],
71
- ],
72
- "sc_id": ["sub", "prod", "stim"],
73
- "stoichiometry": [-1, 1, 0],
74
- }
75
- ).set_index(["r_id", "sbo_term"])
76
- d["all_entities"] = pd.DataFrame(
77
- {
78
- "r_id": [r_id, r_id, r_id, r_id],
79
- "sbo_term": [
80
- MINI_SBO_FROM_NAME["reactant"],
81
- MINI_SBO_FROM_NAME["product"],
82
- MINI_SBO_FROM_NAME["stimulator"],
83
- MINI_SBO_FROM_NAME["catalyst"],
84
- ],
85
- "sc_id": ["sub", "prod", "stim", "cat"],
86
- "stoichiometry": [-1, 1, 0, 0],
87
- }
88
- ).set_index(["r_id", "sbo_term"])
89
- d["no_substrate"] = pd.DataFrame(
90
- {
91
- "r_id": [r_id, r_id, r_id, r_id, r_id],
92
- "sbo_term": [
93
- MINI_SBO_FROM_NAME["product"],
94
- MINI_SBO_FROM_NAME["stimulator"],
95
- MINI_SBO_FROM_NAME["stimulator"],
96
- MINI_SBO_FROM_NAME["inhibitor"],
97
- MINI_SBO_FROM_NAME["catalyst"],
98
- ],
99
- "sc_id": ["prod", "stim1", "stim2", "inh", "cat"],
100
- "stoichiometry": [1, 0, 0, 0, 0],
101
- }
102
- ).set_index(["r_id", "sbo_term"])
33
+ def test_create_napistu_graph():
34
+ _ = net_create.create_napistu_graph(
35
+ sbml_dfs, wiring_approach=GRAPH_WIRING_APPROACHES.BIPARTITE
36
+ )
37
+ _ = net_create.create_napistu_graph(
38
+ sbml_dfs, wiring_approach=GRAPH_WIRING_APPROACHES.REGULATORY
39
+ )
40
+ _ = net_create.create_napistu_graph(
41
+ sbml_dfs, wiring_approach=GRAPH_WIRING_APPROACHES.SURROGATE
42
+ )
103
43
 
104
- return r_id, d
105
44
 
45
+ def test_bipartite_regression():
46
+ bipartite_og = net_create.create_napistu_graph(
47
+ sbml_dfs, wiring_approach="bipartite_og"
48
+ )
106
49
 
107
- def test_create_napistu_graph():
108
- _ = net_create.create_napistu_graph(sbml_dfs, graph_type="bipartite")
109
- _ = net_create.create_napistu_graph(sbml_dfs, graph_type="regulatory")
110
- _ = net_create.create_napistu_graph(sbml_dfs, graph_type="surrogate")
50
+ bipartite = net_create.create_napistu_graph(
51
+ sbml_dfs, wiring_approach=GRAPH_WIRING_APPROACHES.BIPARTITE
52
+ )
53
+
54
+ bipartite_og_edges = bipartite_og.get_edge_dataframe()
55
+ bipartite_edges = bipartite.get_edge_dataframe()
56
+
57
+ try:
58
+ pdt.assert_frame_equal(
59
+ bipartite_og_edges, bipartite_edges, check_like=True, check_dtype=False
60
+ )
61
+ except AssertionError as e:
62
+ # Print detailed differences
63
+ print("DataFrames are not equal!")
64
+ print(
65
+ "Shape original:",
66
+ bipartite_og_edges.shape,
67
+ "Shape new:",
68
+ bipartite_edges.shape,
69
+ )
70
+ print(
71
+ "Columns original:",
72
+ bipartite_og_edges.columns.tolist(),
73
+ "Columns new:",
74
+ bipartite_edges.columns.tolist(),
75
+ )
76
+ # Show head of both for quick inspection
77
+ print("Original head:\n", bipartite_og_edges.head())
78
+ print("New head:\n", bipartite_edges.head())
79
+ # Optionally, show where values differ
80
+ if bipartite_og_edges.shape == bipartite_edges.shape:
81
+ diff = bipartite_og_edges != bipartite_edges
82
+ print("Differences (first 5 rows):\n", diff.head())
83
+ raise e # Re-raise to fail the test
111
84
 
112
85
 
113
86
  def test_create_napistu_graph_edge_reversed():
114
87
  """Test that edge_reversed=True properly reverses edges in the graph for all graph types."""
115
88
  # Test each graph type
116
- for graph_type in ["bipartite", "regulatory", "surrogate"]:
89
+ for wiring_approach in VALID_GRAPH_WIRING_APPROACHES:
117
90
  # Create graphs with and without edge reversal
118
91
  normal_graph = net_create.create_napistu_graph(
119
- sbml_dfs, graph_type=graph_type, directed=True, edge_reversed=False
92
+ sbml_dfs,
93
+ wiring_approach=wiring_approach,
94
+ directed=True,
95
+ edge_reversed=False,
120
96
  )
121
97
  reversed_graph = net_create.create_napistu_graph(
122
- sbml_dfs, graph_type=graph_type, directed=True, edge_reversed=True
98
+ sbml_dfs, wiring_approach=wiring_approach, directed=True, edge_reversed=True
123
99
  )
124
100
 
125
101
  # Get edge dataframes for comparison
@@ -127,53 +103,55 @@ def test_create_napistu_graph_edge_reversed():
127
103
  reversed_edges = reversed_graph.get_edge_dataframe()
128
104
 
129
105
  # Verify we have edges to test
130
- assert len(normal_edges) > 0, f"No edges found in {graph_type} graph"
106
+ assert len(normal_edges) > 0, f"No edges found in {wiring_approach} graph"
131
107
  assert len(normal_edges) == len(
132
108
  reversed_edges
133
- ), f"Edge count mismatch in {graph_type} graph"
109
+ ), f"Edge count mismatch in {wiring_approach} graph"
134
110
 
135
111
  # Test edge reversal
136
112
  # Check a few edges to verify from/to are swapped
137
113
  for i in range(min(5, len(normal_edges))):
138
114
  # Check from/to are swapped
139
115
  assert (
140
- normal_edges.iloc[i]["from"] == reversed_edges.iloc[i]["to"]
141
- ), f"From/to not properly swapped in {graph_type} graph"
116
+ normal_edges.iloc[i][NAPISTU_GRAPH_EDGES.FROM]
117
+ == reversed_edges.iloc[i][NAPISTU_GRAPH_EDGES.TO]
118
+ ), f"From/to not properly swapped in {wiring_approach} graph"
142
119
  assert (
143
- normal_edges.iloc[i]["to"] == reversed_edges.iloc[i]["from"]
144
- ), f"From/to not properly swapped in {graph_type} graph"
120
+ normal_edges.iloc[i][NAPISTU_GRAPH_EDGES.TO]
121
+ == reversed_edges.iloc[i][NAPISTU_GRAPH_EDGES.FROM]
122
+ ), f"From/to not properly swapped in {wiring_approach} graph"
145
123
 
146
124
  # Check stoichiometry is negated
147
125
  assert (
148
- normal_edges.iloc[i]["stoichiometry"]
149
- == -reversed_edges.iloc[i]["stoichiometry"]
150
- ), f"Stoichiometry not properly negated in {graph_type} graph"
126
+ normal_edges.iloc[i][SBML_DFS.STOICHIOMETRY]
127
+ == -reversed_edges.iloc[i][SBML_DFS.STOICHIOMETRY]
128
+ ), f"Stoichiometry not properly negated in {wiring_approach} graph"
151
129
 
152
130
  # Check direction attributes are properly swapped
153
131
  if normal_edges.iloc[i]["direction"] == "forward":
154
132
  assert (
155
133
  reversed_edges.iloc[i]["direction"] == "reverse"
156
- ), f"Direction not properly reversed (forward->reverse) in {graph_type} graph"
134
+ ), f"Direction not properly reversed (forward->reverse) in {wiring_approach} graph"
157
135
  elif normal_edges.iloc[i]["direction"] == "reverse":
158
136
  assert (
159
137
  reversed_edges.iloc[i]["direction"] == "forward"
160
- ), f"Direction not properly reversed (reverse->forward) in {graph_type} graph"
138
+ ), f"Direction not properly reversed (reverse->forward) in {wiring_approach} graph"
161
139
 
162
140
  # Check parents/children are swapped
163
141
  assert (
164
142
  normal_edges.iloc[i]["sc_parents"]
165
143
  == reversed_edges.iloc[i]["sc_children"]
166
- ), f"Parents/children not properly swapped in {graph_type} graph"
144
+ ), f"Parents/children not properly swapped in {wiring_approach} graph"
167
145
  assert (
168
146
  normal_edges.iloc[i]["sc_children"]
169
147
  == reversed_edges.iloc[i]["sc_parents"]
170
- ), f"Parents/children not properly swapped in {graph_type} graph"
148
+ ), f"Parents/children not properly swapped in {wiring_approach} graph"
171
149
 
172
150
 
173
151
  def test_create_napistu_graph_none_attrs():
174
152
  # Should not raise when reaction_graph_attrs is None
175
153
  _ = net_create.create_napistu_graph(
176
- sbml_dfs, reaction_graph_attrs=None, graph_type="bipartite"
154
+ sbml_dfs, reaction_graph_attrs=None, wiring_approach="bipartite"
177
155
  )
178
156
 
179
157
 
@@ -186,29 +164,29 @@ def test_process_napistu_graph_none_attrs():
186
164
  def test_igraph_loading():
187
165
  # test read/write of an igraph network
188
166
  directeds = [True, False]
189
- graph_types = ["bipartite", "regulatory"]
167
+ wiring_approaches = ["bipartite", "regulatory"]
190
168
 
191
169
  ng_utils.export_networks(
192
170
  sbml_dfs,
193
171
  model_prefix="tmp",
194
172
  outdir="/tmp",
195
173
  directeds=directeds,
196
- graph_types=graph_types,
174
+ wiring_approaches=wiring_approaches,
197
175
  )
198
176
 
199
- for graph_type in graph_types:
177
+ for wiring_approach in wiring_approaches:
200
178
  for directed in directeds:
201
179
  import_pkl_path = ng_utils._create_network_save_string(
202
180
  model_prefix="tmp",
203
181
  outdir="/tmp",
204
182
  directed=directed,
205
- graph_type=graph_type,
183
+ wiring_approach=wiring_approach,
206
184
  )
207
185
  network_graph = ng_utils.read_network_pkl(
208
186
  model_prefix="tmp",
209
187
  network_dir="/tmp",
210
188
  directed=directed,
211
- graph_type=graph_type,
189
+ wiring_approach=wiring_approach,
212
190
  )
213
191
 
214
192
  assert network_graph.is_directed() == directed
@@ -216,102 +194,15 @@ def test_igraph_loading():
216
194
  os.unlink(import_pkl_path)
217
195
 
218
196
 
219
- def test_format_interactors(reaction_species_examples):
220
- r_id, reaction_species_examples_dict = reaction_species_examples
221
- # interactions are formatted
222
-
223
- graph_hierarchy_df = net_create._create_graph_hierarchy_df("regulatory")
224
-
225
- assert (
226
- net_create._format_tiered_reaction_species(
227
- r_id,
228
- reaction_species_examples_dict["valid_interactor"],
229
- sbml_dfs,
230
- graph_hierarchy_df,
231
- ).shape[0]
232
- == 1
233
- )
234
-
235
- print("Re-enable test once Issue #102 is solved")
236
-
237
- # catch error from invalid interactor specification
238
- # with pytest.raises(ValueError) as excinfo:
239
- # net_create._format_tiered_reaction_species(
240
- # r_id, reaction_species_examples_dict["invalid_interactor"], sbml_dfs
241
- # )
242
- # assert str(excinfo.value).startswith("Invalid combinations of SBO_terms")
243
-
244
- # simple reaction with just substrates and products
245
- assert (
246
- net_create._format_tiered_reaction_species(
247
- r_id,
248
- reaction_species_examples_dict["sub_and_prod"],
249
- sbml_dfs,
250
- graph_hierarchy_df,
251
- ).shape[0]
252
- == 2
253
- )
254
-
255
- # add a stimulator (activator)
256
- rxn_edges = net_create._format_tiered_reaction_species(
257
- r_id, reaction_species_examples_dict["stimulator"], sbml_dfs, graph_hierarchy_df
258
- )
259
-
260
- assert rxn_edges.shape[0] == 3
261
- assert rxn_edges.iloc[0][["from", "to"]].tolist() == ["stim", "sub"]
262
-
263
- # add catalyst + stimulator
264
- rxn_edges = net_create._format_tiered_reaction_species(
265
- r_id,
266
- reaction_species_examples_dict["all_entities"],
267
- sbml_dfs,
268
- graph_hierarchy_df,
269
- )
270
-
271
- assert rxn_edges.shape[0] == 4
272
- assert rxn_edges.iloc[0][["from", "to"]].tolist() == ["stim", "cat"]
273
- assert rxn_edges.iloc[1][["from", "to"]].tolist() == ["cat", "sub"]
274
-
275
- # no substrate
276
- rxn_edges = net_create._format_tiered_reaction_species(
277
- r_id,
278
- reaction_species_examples_dict["no_substrate"],
279
- sbml_dfs,
280
- graph_hierarchy_df,
281
- )
282
-
283
- assert rxn_edges.shape[0] == 5
284
- # stimulator -> reactant
285
- assert rxn_edges.iloc[0][["from", "to"]].tolist() == ["stim1", "cat"]
286
- assert rxn_edges.iloc[1][["from", "to"]].tolist() == ["stim2", "cat"]
287
- assert rxn_edges.iloc[2][["from", "to"]].tolist() == ["inh", "cat"]
288
-
289
- # use the surrogate model tiered layout also
290
-
291
- graph_hierarchy_df = net_create._create_graph_hierarchy_df("surrogate")
292
-
293
- rxn_edges = net_create._format_tiered_reaction_species(
294
- r_id,
295
- reaction_species_examples_dict["all_entities"],
296
- sbml_dfs,
297
- graph_hierarchy_df,
298
- )
299
-
300
- assert rxn_edges.shape[0] == 4
301
- assert rxn_edges.iloc[0][["from", "to"]].tolist() == ["stim", "sub"]
302
- assert rxn_edges.iloc[1][["from", "to"]].tolist() == ["sub", "cat"]
303
-
304
-
305
197
  def test_reverse_network_edges(reaction_species_examples):
306
- r_id, reaction_species_examples_dict = reaction_species_examples
307
198
 
308
- graph_hierarchy_df = net_create._create_graph_hierarchy_df("regulatory")
199
+ graph_hierarchy_df = net_create_utils.create_graph_hierarchy_df("regulatory")
309
200
 
310
- rxn_edges = net_create._format_tiered_reaction_species(
311
- r_id,
312
- reaction_species_examples_dict["all_entities"],
313
- sbml_dfs,
314
- graph_hierarchy_df,
201
+ rxn_edges = net_create_utils.format_tiered_reaction_species(
202
+ rxn_species=reaction_species_examples["all_entities"],
203
+ r_id="foo",
204
+ graph_hierarchy_df=graph_hierarchy_df,
205
+ drop_reactions_when=DROP_REACTIONS_WHEN.SAME_TIER,
315
206
  )
316
207
  augmented_network_edges = rxn_edges.assign(r_isreversible=True)
317
208
  augmented_network_edges["sc_parents"] = range(0, augmented_network_edges.shape[0])