napistu 0.2.5.dev7__py3-none-any.whl → 0.3.1__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.
Files changed (107) hide show
  1. napistu/__main__.py +126 -96
  2. napistu/constants.py +35 -41
  3. napistu/context/__init__.py +10 -0
  4. napistu/context/discretize.py +462 -0
  5. napistu/context/filtering.py +387 -0
  6. napistu/gcs/__init__.py +1 -1
  7. napistu/identifiers.py +74 -15
  8. napistu/indices.py +68 -0
  9. napistu/ingestion/__init__.py +1 -1
  10. napistu/ingestion/bigg.py +47 -62
  11. napistu/ingestion/constants.py +18 -133
  12. napistu/ingestion/gtex.py +113 -0
  13. napistu/ingestion/hpa.py +147 -0
  14. napistu/ingestion/sbml.py +0 -97
  15. napistu/ingestion/string.py +2 -2
  16. napistu/matching/__init__.py +10 -0
  17. napistu/matching/constants.py +18 -0
  18. napistu/matching/interactions.py +518 -0
  19. napistu/matching/mount.py +529 -0
  20. napistu/matching/species.py +510 -0
  21. napistu/mcp/__init__.py +7 -4
  22. napistu/mcp/__main__.py +128 -72
  23. napistu/mcp/client.py +16 -25
  24. napistu/mcp/codebase.py +201 -145
  25. napistu/mcp/component_base.py +170 -0
  26. napistu/mcp/config.py +223 -0
  27. napistu/mcp/constants.py +45 -2
  28. napistu/mcp/documentation.py +253 -136
  29. napistu/mcp/documentation_utils.py +13 -48
  30. napistu/mcp/execution.py +372 -305
  31. napistu/mcp/health.py +47 -65
  32. napistu/mcp/profiles.py +10 -6
  33. napistu/mcp/server.py +161 -80
  34. napistu/mcp/tutorials.py +139 -87
  35. napistu/modify/__init__.py +1 -1
  36. napistu/modify/gaps.py +1 -1
  37. napistu/network/__init__.py +1 -1
  38. napistu/network/constants.py +101 -34
  39. napistu/network/data_handling.py +388 -0
  40. napistu/network/ig_utils.py +351 -0
  41. napistu/network/napistu_graph_core.py +354 -0
  42. napistu/network/neighborhoods.py +40 -40
  43. napistu/network/net_create.py +373 -309
  44. napistu/network/net_propagation.py +47 -19
  45. napistu/network/{net_utils.py → ng_utils.py} +124 -272
  46. napistu/network/paths.py +67 -51
  47. napistu/network/precompute.py +11 -11
  48. napistu/ontologies/__init__.py +10 -0
  49. napistu/ontologies/constants.py +129 -0
  50. napistu/ontologies/dogma.py +243 -0
  51. napistu/ontologies/genodexito.py +649 -0
  52. napistu/ontologies/mygene.py +369 -0
  53. napistu/ontologies/renaming.py +198 -0
  54. napistu/rpy2/__init__.py +229 -86
  55. napistu/rpy2/callr.py +47 -77
  56. napistu/rpy2/constants.py +24 -23
  57. napistu/rpy2/rids.py +61 -648
  58. napistu/sbml_dfs_core.py +587 -222
  59. napistu/scverse/__init__.py +15 -0
  60. napistu/scverse/constants.py +28 -0
  61. napistu/scverse/loading.py +727 -0
  62. napistu/utils.py +118 -10
  63. {napistu-0.2.5.dev7.dist-info → napistu-0.3.1.dist-info}/METADATA +8 -3
  64. napistu-0.3.1.dist-info/RECORD +133 -0
  65. tests/conftest.py +22 -0
  66. tests/test_context_discretize.py +56 -0
  67. tests/test_context_filtering.py +267 -0
  68. tests/test_identifiers.py +100 -0
  69. tests/test_indices.py +65 -0
  70. tests/{test_edgelist.py → test_ingestion_napistu_edgelist.py} +2 -2
  71. tests/test_matching_interactions.py +108 -0
  72. tests/test_matching_mount.py +305 -0
  73. tests/test_matching_species.py +394 -0
  74. tests/test_mcp_config.py +193 -0
  75. tests/test_mcp_documentation_utils.py +12 -3
  76. tests/test_mcp_server.py +156 -19
  77. tests/test_network_data_handling.py +397 -0
  78. tests/test_network_ig_utils.py +23 -0
  79. tests/test_network_neighborhoods.py +19 -0
  80. tests/test_network_net_create.py +459 -0
  81. tests/test_network_ng_utils.py +30 -0
  82. tests/test_network_paths.py +56 -0
  83. tests/{test_precomputed_distances.py → test_network_precompute.py} +8 -6
  84. tests/test_ontologies_genodexito.py +58 -0
  85. tests/test_ontologies_mygene.py +39 -0
  86. tests/test_ontologies_renaming.py +110 -0
  87. tests/test_rpy2_callr.py +79 -0
  88. tests/test_rpy2_init.py +151 -0
  89. tests/test_sbml.py +0 -31
  90. tests/test_sbml_dfs_core.py +134 -10
  91. tests/test_scverse_loading.py +778 -0
  92. tests/test_set_coverage.py +2 -2
  93. tests/test_utils.py +121 -1
  94. napistu/mechanism_matching.py +0 -1353
  95. napistu/rpy2/netcontextr.py +0 -467
  96. napistu-0.2.5.dev7.dist-info/RECORD +0 -98
  97. tests/test_igraph.py +0 -367
  98. tests/test_mechanism_matching.py +0 -784
  99. tests/test_net_utils.py +0 -149
  100. tests/test_netcontextr.py +0 -105
  101. tests/test_rpy2.py +0 -61
  102. /napistu/ingestion/{cpr_edgelist.py → napistu_edgelist.py} +0 -0
  103. {napistu-0.2.5.dev7.dist-info → napistu-0.3.1.dist-info}/WHEEL +0 -0
  104. {napistu-0.2.5.dev7.dist-info → napistu-0.3.1.dist-info}/entry_points.txt +0 -0
  105. {napistu-0.2.5.dev7.dist-info → napistu-0.3.1.dist-info}/licenses/LICENSE +0 -0
  106. {napistu-0.2.5.dev7.dist-info → napistu-0.3.1.dist-info}/top_level.txt +0 -0
  107. /tests/{test_obo.py → test_ingestion_obo.py} +0 -0
@@ -0,0 +1,397 @@
1
+ from __future__ import annotations
2
+
3
+ import pytest
4
+
5
+ import igraph as ig
6
+ import pandas as pd
7
+
8
+ from napistu.network import data_handling, net_create
9
+
10
+
11
+ # Fixtures
12
+ @pytest.fixture
13
+ def mock_sbml_dfs():
14
+ """Create a mock SBML_dfs object with test data."""
15
+
16
+ class MockSBMLDfs:
17
+ def __init__(self):
18
+ self.species_data = {
19
+ "test_table": pd.DataFrame(
20
+ {
21
+ "col1": [1, 2, 3],
22
+ "col2": ["a", "b", "c"],
23
+ "test_prefix_col": [4, 5, 6],
24
+ }
25
+ ),
26
+ "another_table": pd.DataFrame(
27
+ {"col3": [7, 8, 9], "col4": ["d", "e", "f"]}
28
+ ),
29
+ }
30
+ self.reactions_data = {
31
+ "reaction_table": pd.DataFrame(
32
+ {"rxn_col1": [10, 11, 12], "rxn_col2": ["g", "h", "i"]}
33
+ )
34
+ }
35
+
36
+ return MockSBMLDfs()
37
+
38
+
39
+ @pytest.fixture
40
+ def test_entity_data():
41
+ """Create a test data table."""
42
+ return pd.DataFrame(
43
+ {
44
+ "attr1": [1, 2, 3],
45
+ "attr2": ["a", "b", "c"],
46
+ "test_prefix_attr": [4, 5, 6],
47
+ "another_attr": [7, 8, 9],
48
+ }
49
+ )
50
+
51
+
52
+ def test_select_sbml_dfs_data_table(mock_sbml_dfs):
53
+ """Test selecting data tables from SBML_dfs object."""
54
+ # Test selecting specific species table
55
+ result = data_handling._select_sbml_dfs_data_table(
56
+ mock_sbml_dfs, "test_table", "species"
57
+ )
58
+ assert isinstance(result, pd.DataFrame)
59
+ assert result.equals(mock_sbml_dfs.species_data["test_table"])
60
+
61
+ # Test selecting reactions table
62
+ result = data_handling._select_sbml_dfs_data_table(
63
+ mock_sbml_dfs, "reaction_table", "reactions"
64
+ )
65
+ assert isinstance(result, pd.DataFrame)
66
+ assert result.equals(mock_sbml_dfs.reactions_data["reaction_table"])
67
+
68
+ # Test error cases
69
+ with pytest.raises(ValueError, match="Invalid table_type"):
70
+ data_handling._select_sbml_dfs_data_table(
71
+ mock_sbml_dfs, table_type="invalid_type"
72
+ )
73
+
74
+ with pytest.raises(ValueError, match="Invalid table_name"):
75
+ data_handling._select_sbml_dfs_data_table(
76
+ mock_sbml_dfs, "invalid_table", "species"
77
+ )
78
+
79
+ # Test no data case
80
+ mock_sbml_dfs.species_data = {}
81
+ with pytest.raises(ValueError, match="No species data found"):
82
+ data_handling._select_sbml_dfs_data_table(mock_sbml_dfs)
83
+
84
+ # Test multiple tables without specifying name
85
+ mock_sbml_dfs.species_data = {
86
+ "table1": pd.DataFrame({"col1": [1]}),
87
+ "table2": pd.DataFrame({"col2": [2]}),
88
+ }
89
+ with pytest.raises(
90
+ ValueError, match="Expected a single species data table but found 2"
91
+ ):
92
+ data_handling._select_sbml_dfs_data_table(mock_sbml_dfs)
93
+
94
+
95
+ def test_select_data_table_attrs_basic(test_entity_data):
96
+ """Test basic attribute selection from data table."""
97
+ # Test single attribute as list
98
+ result = data_handling._create_data_table_column_mapping(
99
+ test_entity_data, ["attr1"]
100
+ )
101
+ assert isinstance(result, dict)
102
+ assert result == {"attr1": "attr1"}
103
+
104
+ # Test multiple attributes
105
+ result = data_handling._create_data_table_column_mapping(
106
+ test_entity_data, ["attr1", "attr2"]
107
+ )
108
+ assert isinstance(result, dict)
109
+ assert result == {"attr1": "attr1", "attr2": "attr2"}
110
+
111
+ # Test invalid attribute
112
+ with pytest.raises(ValueError, match="following attributes were missing"):
113
+ data_handling._create_data_table_column_mapping(
114
+ test_entity_data, ["invalid_attr"]
115
+ )
116
+
117
+
118
+ def test_select_data_table_attrs_advanced(test_entity_data):
119
+ """Test advanced attribute selection features."""
120
+ # Test dictionary renaming
121
+ result = data_handling._create_data_table_column_mapping(
122
+ test_entity_data, {"attr1": "new_name1", "attr2": "new_name2"}
123
+ )
124
+ assert isinstance(result, dict)
125
+ assert result == {"attr1": "new_name1", "attr2": "new_name2"}
126
+
127
+ # Test empty dictionary
128
+ with pytest.raises(ValueError, match="No attributes found in the dictionary"):
129
+ data_handling._create_data_table_column_mapping(test_entity_data, {})
130
+
131
+ # Test invalid source columns
132
+ with pytest.raises(ValueError, match="following source columns were missing"):
133
+ data_handling._create_data_table_column_mapping(
134
+ test_entity_data, {"invalid_attr": "new_name"}
135
+ )
136
+
137
+ # Test conflicting new column names
138
+ with pytest.raises(
139
+ ValueError, match="following new column names conflict with existing columns"
140
+ ):
141
+ data_handling._create_data_table_column_mapping(
142
+ test_entity_data,
143
+ {"attr1": "attr2"}, # trying to rename attr1 to attr2, which already exists
144
+ )
145
+
146
+ # Test None returns identity mapping for all columns
147
+ result = data_handling._create_data_table_column_mapping(test_entity_data, None)
148
+ assert isinstance(result, dict)
149
+ expected = {col: col for col in test_entity_data.columns}
150
+ assert result == expected
151
+
152
+ # Test string pattern matching
153
+ result = data_handling._create_data_table_column_mapping(
154
+ test_entity_data, "test_prefix_.*"
155
+ )
156
+ assert isinstance(result, dict)
157
+ assert result == {"test_prefix_attr": "test_prefix_attr"}
158
+
159
+
160
+ def test_create_graph_attrs_config():
161
+ """Test creating graph attributes configuration with a single table and transformation."""
162
+ # Test basic case with single table and transformation
163
+ result = data_handling._create_graph_attrs_config(
164
+ column_mapping={"col1": "col1"},
165
+ data_type="species",
166
+ table_name="test_table",
167
+ transformation="identity",
168
+ )
169
+
170
+ expected = {
171
+ "species": {
172
+ "col1": {
173
+ "table": "test_table",
174
+ "variable": "col1",
175
+ "trans": "identity",
176
+ }
177
+ }
178
+ }
179
+ assert result == expected
180
+
181
+ # Test with column renaming
182
+ result = data_handling._create_graph_attrs_config(
183
+ column_mapping={"original_col": "new_col"},
184
+ data_type="species",
185
+ table_name="test_table",
186
+ transformation="squared",
187
+ )
188
+
189
+ expected = {
190
+ "species": {
191
+ "new_col": {
192
+ "table": "test_table",
193
+ "variable": "original_col",
194
+ "trans": "squared",
195
+ }
196
+ }
197
+ }
198
+ assert result == expected
199
+
200
+ # Test with multiple columns but same table and transformation
201
+ result = data_handling._create_graph_attrs_config(
202
+ column_mapping={"col1": "col1", "col2": "renamed_col2"},
203
+ data_type="species",
204
+ table_name="test_table",
205
+ transformation="identity",
206
+ )
207
+
208
+ expected = {
209
+ "species": {
210
+ "col1": {
211
+ "table": "test_table",
212
+ "variable": "col1",
213
+ "trans": "identity",
214
+ },
215
+ "renamed_col2": {
216
+ "table": "test_table",
217
+ "variable": "col2",
218
+ "trans": "identity",
219
+ },
220
+ }
221
+ }
222
+ assert result == expected
223
+
224
+
225
+ def test_add_results_table_to_graph(sbml_dfs_glucose_metabolism):
226
+ """Test adding results table to graph."""
227
+ # Create a test graph using create_napistu_graph
228
+ graph = net_create.create_napistu_graph(
229
+ sbml_dfs_glucose_metabolism, directed=True, graph_type="regulatory"
230
+ )
231
+
232
+ # Add some test data to sbml_dfs
233
+ test_data = pd.DataFrame(
234
+ {"test_attr": [1.0, 2.0, 3.0]},
235
+ index=pd.Index(
236
+ list(sbml_dfs_glucose_metabolism.species.index[:3]), name="s_id"
237
+ ),
238
+ )
239
+ sbml_dfs_glucose_metabolism.add_species_data("test_table", test_data)
240
+
241
+ # Test basic case - single attribute
242
+ result = data_handling.add_results_table_to_graph(
243
+ napistu_graph=graph,
244
+ sbml_dfs=sbml_dfs_glucose_metabolism,
245
+ attribute_names=["test_attr"],
246
+ table_name="test_table",
247
+ inplace=False,
248
+ )
249
+ assert "test_attr" in result.vs.attributes()
250
+
251
+ # Test with transformation
252
+ def square(x):
253
+ return x**2
254
+
255
+ result = data_handling.add_results_table_to_graph(
256
+ napistu_graph=graph,
257
+ sbml_dfs=sbml_dfs_glucose_metabolism,
258
+ attribute_names=["test_attr"],
259
+ table_name="test_table",
260
+ transformation="square",
261
+ custom_transformations={"square": square},
262
+ inplace=False,
263
+ )
264
+ assert "test_attr" in result.vs.attributes()
265
+
266
+ # Test inplace=True
267
+ original_graph = graph.copy()
268
+ assert (
269
+ "test_attr" not in original_graph.vs.attributes()
270
+ ) # Verify attribute doesn't exist before
271
+ result = data_handling.add_results_table_to_graph(
272
+ napistu_graph=original_graph,
273
+ sbml_dfs=sbml_dfs_glucose_metabolism,
274
+ attribute_names=["test_attr"],
275
+ table_name="test_table",
276
+ inplace=True,
277
+ )
278
+ assert result is None # Function should return None when inplace=True
279
+ assert (
280
+ "test_attr" in original_graph.vs.attributes()
281
+ ) # Verify original graph was modified
282
+
283
+ # Test error cases
284
+ with pytest.raises(ValueError, match="Invalid table_type"):
285
+ data_handling.add_results_table_to_graph(
286
+ napistu_graph=graph,
287
+ sbml_dfs=sbml_dfs_glucose_metabolism,
288
+ table_type="invalid",
289
+ )
290
+
291
+ with pytest.raises(NotImplementedError, match="Reactions are not yet supported"):
292
+ data_handling.add_results_table_to_graph(
293
+ napistu_graph=graph,
294
+ sbml_dfs=sbml_dfs_glucose_metabolism,
295
+ table_type="reactions",
296
+ )
297
+
298
+
299
+ def test_add_graph_species_attribute(sbml_dfs_glucose_metabolism):
300
+ """Test adding species attributes to graph."""
301
+ # Create a test graph using create_napistu_graph
302
+ graph = net_create.create_napistu_graph(
303
+ sbml_dfs_glucose_metabolism, directed=True, graph_type="regulatory"
304
+ )
305
+
306
+ # Add test data to sbml_dfs
307
+ test_data = pd.DataFrame(
308
+ {"test_attr": [1.0, 2.0, 3.0]},
309
+ index=pd.Index(
310
+ list(sbml_dfs_glucose_metabolism.species.index[:3]), name="s_id"
311
+ ),
312
+ )
313
+ sbml_dfs_glucose_metabolism.add_species_data("test_table", test_data)
314
+
315
+ # Define custom transformations
316
+ custom_transformations = {"square": lambda x: x**2}
317
+
318
+ # Test attempting to overwrite an existing vertex attribute
319
+ collision_attrs = {
320
+ "species": {
321
+ "name": { # Using 'name' which is a required vertex attribute
322
+ "table": "test_table",
323
+ "variable": "test_attr",
324
+ "trans": "identity",
325
+ }
326
+ }
327
+ }
328
+
329
+ with pytest.raises(
330
+ ValueError, match="Attribute 'name' already exists in graph vertices"
331
+ ):
332
+ data_handling._add_graph_species_attribute(
333
+ graph, sbml_dfs_glucose_metabolism, collision_attrs
334
+ )
335
+
336
+ # Test basic attribute addition
337
+ species_graph_attrs = {
338
+ "species": {
339
+ "new_attr": {
340
+ "table": "test_table",
341
+ "variable": "test_attr",
342
+ "trans": "identity",
343
+ }
344
+ }
345
+ }
346
+
347
+ result = data_handling._add_graph_species_attribute(
348
+ graph, sbml_dfs_glucose_metabolism, species_graph_attrs
349
+ )
350
+
351
+ assert "new_attr" in result.vs.attributes()
352
+
353
+ # Test with custom transformation
354
+ species_graph_attrs = {
355
+ "species": {
356
+ "squared_attr": {
357
+ "table": "test_table",
358
+ "variable": "test_attr",
359
+ "trans": "square",
360
+ }
361
+ }
362
+ }
363
+
364
+ result = data_handling._add_graph_species_attribute(
365
+ graph,
366
+ sbml_dfs_glucose_metabolism,
367
+ species_graph_attrs,
368
+ custom_transformations=custom_transformations,
369
+ )
370
+
371
+ assert "squared_attr" in result.vs.attributes()
372
+
373
+ # Test error cases
374
+ with pytest.raises(TypeError, match="species_graph_attrs must be a dict"):
375
+ data_handling._add_graph_species_attribute(
376
+ graph, sbml_dfs_glucose_metabolism, species_graph_attrs=[]
377
+ )
378
+
379
+ # Test missing required attributes in graph
380
+ bad_graph = ig.Graph()
381
+ bad_graph.add_vertices(3)
382
+
383
+ # Use basic transformation to avoid transformation error
384
+ basic_attrs = {
385
+ "species": {
386
+ "new_attr": {
387
+ "table": "test_table",
388
+ "variable": "test_attr",
389
+ "trans": "identity",
390
+ }
391
+ }
392
+ }
393
+
394
+ with pytest.raises(ValueError, match="required attributes were missing"):
395
+ data_handling._add_graph_species_attribute(
396
+ bad_graph, sbml_dfs_glucose_metabolism, basic_attrs
397
+ )
@@ -0,0 +1,23 @@
1
+ from __future__ import annotations
2
+
3
+ import pytest
4
+
5
+ from napistu.network import ig_utils
6
+ from napistu.network import net_create
7
+
8
+
9
+ def test_validate_graph_attributes(sbml_dfs):
10
+
11
+ napistu_graph = net_create.process_napistu_graph(
12
+ sbml_dfs, directed=True, weighting_strategy="topology"
13
+ )
14
+
15
+ assert (
16
+ ig_utils.validate_edge_attributes(
17
+ napistu_graph, ["weights", "upstream_weights"]
18
+ )
19
+ is None
20
+ )
21
+ assert ig_utils.validate_vertex_attributes(napistu_graph, "node_type") is None
22
+ with pytest.raises(ValueError):
23
+ ig_utils.validate_vertex_attributes(napistu_graph, "baz")
@@ -0,0 +1,19 @@
1
+ from napistu.network import ng_utils
2
+ from napistu.network import neighborhoods
3
+
4
+
5
+ def test_neighborhood(sbml_dfs, napistu_graph):
6
+ species = sbml_dfs.species
7
+ source_species = species[species["s_name"] == "NADH"].index.tolist()
8
+
9
+ query_sc_species = ng_utils.compartmentalize_species(sbml_dfs, source_species)
10
+ compartmentalized_species = query_sc_species["sc_id"].tolist()
11
+
12
+ neighborhood = neighborhoods.find_neighborhoods(
13
+ sbml_dfs,
14
+ napistu_graph,
15
+ compartmentalized_species=compartmentalized_species,
16
+ order=3,
17
+ )
18
+
19
+ assert neighborhood["species_73473"]["vertices"].shape[0] == 6