napistu 0.2.5.dev6__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.
- napistu/__main__.py +126 -96
- napistu/constants.py +35 -41
- napistu/context/__init__.py +10 -0
- napistu/context/discretize.py +462 -0
- napistu/context/filtering.py +387 -0
- napistu/gcs/__init__.py +1 -1
- napistu/identifiers.py +74 -15
- napistu/indices.py +68 -0
- napistu/ingestion/__init__.py +1 -1
- napistu/ingestion/bigg.py +47 -62
- napistu/ingestion/constants.py +18 -133
- napistu/ingestion/gtex.py +113 -0
- napistu/ingestion/hpa.py +147 -0
- napistu/ingestion/sbml.py +0 -97
- napistu/ingestion/string.py +2 -2
- napistu/matching/__init__.py +10 -0
- napistu/matching/constants.py +18 -0
- napistu/matching/interactions.py +518 -0
- napistu/matching/mount.py +529 -0
- napistu/matching/species.py +510 -0
- napistu/mcp/__init__.py +7 -4
- napistu/mcp/__main__.py +128 -72
- napistu/mcp/client.py +16 -25
- napistu/mcp/codebase.py +201 -153
- napistu/mcp/component_base.py +170 -0
- napistu/mcp/config.py +223 -0
- napistu/mcp/constants.py +45 -2
- napistu/mcp/documentation.py +253 -136
- napistu/mcp/documentation_utils.py +13 -48
- napistu/mcp/execution.py +372 -305
- napistu/mcp/health.py +49 -67
- napistu/mcp/profiles.py +10 -6
- napistu/mcp/server.py +161 -80
- napistu/mcp/tutorials.py +139 -87
- napistu/modify/__init__.py +1 -1
- napistu/modify/gaps.py +1 -1
- napistu/network/__init__.py +1 -1
- napistu/network/constants.py +101 -34
- napistu/network/data_handling.py +388 -0
- napistu/network/ig_utils.py +351 -0
- napistu/network/napistu_graph_core.py +354 -0
- napistu/network/neighborhoods.py +40 -40
- napistu/network/net_create.py +373 -309
- napistu/network/net_propagation.py +47 -19
- napistu/network/{net_utils.py → ng_utils.py} +124 -272
- napistu/network/paths.py +67 -51
- napistu/network/precompute.py +11 -11
- napistu/ontologies/__init__.py +10 -0
- napistu/ontologies/constants.py +129 -0
- napistu/ontologies/dogma.py +243 -0
- napistu/ontologies/genodexito.py +649 -0
- napistu/ontologies/mygene.py +369 -0
- napistu/ontologies/renaming.py +198 -0
- napistu/rpy2/__init__.py +229 -86
- napistu/rpy2/callr.py +47 -77
- napistu/rpy2/constants.py +24 -23
- napistu/rpy2/rids.py +61 -648
- napistu/sbml_dfs_core.py +587 -222
- napistu/scverse/__init__.py +15 -0
- napistu/scverse/constants.py +28 -0
- napistu/scverse/loading.py +727 -0
- napistu/utils.py +118 -10
- {napistu-0.2.5.dev6.dist-info → napistu-0.3.1.dist-info}/METADATA +8 -3
- napistu-0.3.1.dist-info/RECORD +133 -0
- tests/conftest.py +22 -0
- tests/test_context_discretize.py +56 -0
- tests/test_context_filtering.py +267 -0
- tests/test_identifiers.py +100 -0
- tests/test_indices.py +65 -0
- tests/{test_edgelist.py → test_ingestion_napistu_edgelist.py} +2 -2
- tests/test_matching_interactions.py +108 -0
- tests/test_matching_mount.py +305 -0
- tests/test_matching_species.py +394 -0
- tests/test_mcp_config.py +193 -0
- tests/test_mcp_documentation_utils.py +12 -3
- tests/test_mcp_server.py +356 -0
- tests/test_network_data_handling.py +397 -0
- tests/test_network_ig_utils.py +23 -0
- tests/test_network_neighborhoods.py +19 -0
- tests/test_network_net_create.py +459 -0
- tests/test_network_ng_utils.py +30 -0
- tests/test_network_paths.py +56 -0
- tests/{test_precomputed_distances.py → test_network_precompute.py} +8 -6
- tests/test_ontologies_genodexito.py +58 -0
- tests/test_ontologies_mygene.py +39 -0
- tests/test_ontologies_renaming.py +110 -0
- tests/test_rpy2_callr.py +79 -0
- tests/test_rpy2_init.py +151 -0
- tests/test_sbml.py +0 -31
- tests/test_sbml_dfs_core.py +134 -10
- tests/test_scverse_loading.py +778 -0
- tests/test_set_coverage.py +2 -2
- tests/test_utils.py +121 -1
- napistu/mechanism_matching.py +0 -1353
- napistu/rpy2/netcontextr.py +0 -467
- napistu-0.2.5.dev6.dist-info/RECORD +0 -97
- tests/test_igraph.py +0 -367
- tests/test_mechanism_matching.py +0 -784
- tests/test_net_utils.py +0 -149
- tests/test_netcontextr.py +0 -105
- tests/test_rpy2.py +0 -61
- /napistu/ingestion/{cpr_edgelist.py → napistu_edgelist.py} +0 -0
- {napistu-0.2.5.dev6.dist-info → napistu-0.3.1.dist-info}/WHEEL +0 -0
- {napistu-0.2.5.dev6.dist-info → napistu-0.3.1.dist-info}/entry_points.txt +0 -0
- {napistu-0.2.5.dev6.dist-info → napistu-0.3.1.dist-info}/licenses/LICENSE +0 -0
- {napistu-0.2.5.dev6.dist-info → napistu-0.3.1.dist-info}/top_level.txt +0 -0
- /tests/{test_obo.py → test_ingestion_obo.py} +0 -0
napistu/mcp/__main__.py
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# src/napistu/mcp/__main__.py
|
2
1
|
"""
|
3
2
|
MCP (Model Context Protocol) Server CLI for Napistu.
|
4
3
|
"""
|
@@ -16,6 +15,15 @@ from napistu.mcp.client import (
|
|
16
15
|
list_server_resources,
|
17
16
|
read_server_resource,
|
18
17
|
)
|
18
|
+
from napistu.mcp.config import (
|
19
|
+
validate_server_config_flags,
|
20
|
+
validate_client_config_flags,
|
21
|
+
server_config_options,
|
22
|
+
client_config_options,
|
23
|
+
local_server_config,
|
24
|
+
local_client_config,
|
25
|
+
production_client_config,
|
26
|
+
)
|
19
27
|
|
20
28
|
logger = logging.getLogger(napistu.__name__)
|
21
29
|
click_logging.basic_config(logger)
|
@@ -35,157 +43,205 @@ def server():
|
|
35
43
|
|
36
44
|
@server.command(name="start")
|
37
45
|
@click.option(
|
38
|
-
"--profile", type=click.Choice(["
|
46
|
+
"--profile", type=click.Choice(["execution", "docs", "full"]), default="docs"
|
39
47
|
)
|
40
|
-
@
|
41
|
-
@click.option("--port", type=int, default=8765)
|
42
|
-
@click.option("--server-name", type=str)
|
48
|
+
@server_config_options
|
43
49
|
@click_logging.simple_verbosity_option(logger)
|
44
|
-
def start_server(profile, host, port, server_name):
|
50
|
+
def start_server(profile, production, local, host, port, server_name):
|
45
51
|
"""Start an MCP server with the specified profile."""
|
46
|
-
|
52
|
+
try:
|
53
|
+
config = validate_server_config_flags(
|
54
|
+
local, production, host, port, server_name
|
55
|
+
)
|
56
|
+
|
57
|
+
click.echo("Starting server with configuration:")
|
58
|
+
click.echo(f" Profile: {profile}")
|
59
|
+
click.echo(f" Host: {config.host}")
|
60
|
+
click.echo(f" Port: {config.port}")
|
61
|
+
click.echo(f" Server Name: {config.server_name}")
|
62
|
+
|
63
|
+
start_mcp_server(profile, config)
|
64
|
+
|
65
|
+
except click.BadParameter as e:
|
66
|
+
raise click.ClickException(str(e))
|
47
67
|
|
48
68
|
|
49
69
|
@server.command(name="local")
|
50
|
-
@click.option("--server-name", type=str, default="napistu-local")
|
51
70
|
@click_logging.simple_verbosity_option(logger)
|
52
|
-
def start_local(
|
71
|
+
def start_local():
|
53
72
|
"""Start a local MCP server optimized for function execution."""
|
54
|
-
|
73
|
+
config = local_server_config()
|
74
|
+
click.echo("Starting local development server (execution profile)")
|
75
|
+
click.echo(f" Host: {config.host}")
|
76
|
+
click.echo(f" Port: {config.port}")
|
77
|
+
click.echo(f" Server Name: {config.server_name}")
|
78
|
+
|
79
|
+
start_mcp_server("execution", config)
|
55
80
|
|
56
81
|
|
57
82
|
@server.command(name="full")
|
58
|
-
@click.option("--server-name", type=str, default="napistu-full")
|
59
83
|
@click_logging.simple_verbosity_option(logger)
|
60
|
-
def start_full(
|
84
|
+
def start_full():
|
61
85
|
"""Start a full MCP server with all components enabled (local debugging)."""
|
62
|
-
|
86
|
+
config = local_server_config()
|
87
|
+
# Override server name for full profile
|
88
|
+
config.server_name = "napistu-full"
|
89
|
+
|
90
|
+
click.echo("Starting full development server (all components)")
|
91
|
+
click.echo(f" Host: {config.host}")
|
92
|
+
click.echo(f" Port: {config.port}")
|
93
|
+
click.echo(f" Server Name: {config.server_name}")
|
94
|
+
|
95
|
+
start_mcp_server("full", config)
|
63
96
|
|
64
97
|
|
65
98
|
@cli.command()
|
66
|
-
@
|
99
|
+
@client_config_options
|
67
100
|
@click_logging.simple_verbosity_option(logger)
|
68
|
-
def health(
|
101
|
+
def health(production, local, host, port, https):
|
69
102
|
"""Quick health check of MCP server."""
|
70
103
|
|
71
104
|
async def run_health_check():
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
105
|
+
try:
|
106
|
+
config = validate_client_config_flags(local, production, host, port, https)
|
107
|
+
|
108
|
+
print("🏥 Napistu MCP Server Health Check")
|
109
|
+
print("=" * 40)
|
110
|
+
print(f"Server URL: {config.base_url}")
|
111
|
+
print()
|
76
112
|
|
77
|
-
|
78
|
-
|
113
|
+
health = await check_server_health(config)
|
114
|
+
print_health_status(health)
|
115
|
+
|
116
|
+
except click.BadParameter as e:
|
117
|
+
raise click.ClickException(str(e))
|
79
118
|
|
80
119
|
asyncio.run(run_health_check())
|
81
120
|
|
82
121
|
|
83
122
|
@cli.command()
|
84
|
-
@
|
123
|
+
@client_config_options
|
85
124
|
@click_logging.simple_verbosity_option(logger)
|
86
|
-
def resources(
|
125
|
+
def resources(production, local, host, port, https):
|
87
126
|
"""List all available resources on the MCP server."""
|
88
127
|
|
89
128
|
async def run_list_resources():
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
129
|
+
try:
|
130
|
+
config = validate_client_config_flags(local, production, host, port, https)
|
131
|
+
|
132
|
+
print("📋 Napistu MCP Server Resources")
|
133
|
+
print("=" * 40)
|
134
|
+
print(f"Server URL: {config.base_url}")
|
135
|
+
print()
|
136
|
+
|
137
|
+
resources = await list_server_resources(config)
|
138
|
+
|
139
|
+
if resources:
|
140
|
+
print(f"Found {len(resources)} resources:")
|
141
|
+
for resource in resources:
|
142
|
+
print(f" 📄 {resource.uri}")
|
143
|
+
if resource.name != resource.uri:
|
144
|
+
print(f" Name: {resource.name}")
|
145
|
+
if hasattr(resource, "description") and resource.description:
|
146
|
+
print(f" Description: {resource.description}")
|
147
|
+
print()
|
148
|
+
else:
|
149
|
+
print("❌ Could not retrieve resources")
|
150
|
+
|
151
|
+
except click.BadParameter as e:
|
152
|
+
raise click.ClickException(str(e))
|
108
153
|
|
109
154
|
asyncio.run(run_list_resources())
|
110
155
|
|
111
156
|
|
112
157
|
@cli.command()
|
113
158
|
@click.argument("resource_uri")
|
114
|
-
@
|
159
|
+
@client_config_options
|
115
160
|
@click.option(
|
116
161
|
"--output", type=click.File("w"), default="-", help="Output file (default: stdout)"
|
117
162
|
)
|
118
163
|
@click_logging.simple_verbosity_option(logger)
|
119
|
-
def read(resource_uri,
|
164
|
+
def read(resource_uri, production, local, host, port, https, output):
|
120
165
|
"""Read a specific resource from the MCP server."""
|
121
166
|
|
122
167
|
async def run_read_resource():
|
123
|
-
|
124
|
-
|
125
|
-
file=output if output.name != "<stdout>" else None,
|
126
|
-
)
|
127
|
-
print(f"Server URL: {url}", file=output if output.name != "<stdout>" else None)
|
128
|
-
print("=" * 50, file=output if output.name != "<stdout>" else None)
|
168
|
+
try:
|
169
|
+
config = validate_client_config_flags(local, production, host, port, https)
|
129
170
|
|
130
|
-
content = await read_server_resource(resource_uri, server_url=url)
|
131
|
-
|
132
|
-
if content:
|
133
|
-
print(content, file=output)
|
134
|
-
else:
|
135
171
|
print(
|
136
|
-
"
|
172
|
+
f"📖 Reading Resource: {resource_uri}",
|
173
|
+
file=output if output.name != "<stdout>" else None,
|
174
|
+
)
|
175
|
+
print(
|
176
|
+
f"Server URL: {config.base_url}",
|
137
177
|
file=output if output.name != "<stdout>" else None,
|
138
178
|
)
|
179
|
+
print("=" * 50, file=output if output.name != "<stdout>" else None)
|
180
|
+
|
181
|
+
content = await read_server_resource(resource_uri, config)
|
182
|
+
|
183
|
+
if content:
|
184
|
+
print(content, file=output)
|
185
|
+
else:
|
186
|
+
print(
|
187
|
+
"❌ Could not read resource",
|
188
|
+
file=output if output.name != "<stdout>" else None,
|
189
|
+
)
|
190
|
+
|
191
|
+
except click.BadParameter as e:
|
192
|
+
raise click.ClickException(str(e))
|
139
193
|
|
140
194
|
asyncio.run(run_read_resource())
|
141
195
|
|
142
196
|
|
143
197
|
@cli.command()
|
144
|
-
@click.option("--local-url", default="http://127.0.0.1:8765", help="Local server URL")
|
145
|
-
@click.option("--remote-url", required=True, help="Remote server URL")
|
146
198
|
@click_logging.simple_verbosity_option(logger)
|
147
|
-
def compare(
|
148
|
-
"""Compare health between local and
|
199
|
+
def compare():
|
200
|
+
"""Compare health between local development and production servers."""
|
149
201
|
|
150
202
|
async def run_comparison():
|
151
|
-
|
203
|
+
|
204
|
+
local_config = local_client_config()
|
205
|
+
production_config = production_client_config()
|
206
|
+
|
207
|
+
print("🔍 Local vs Production Server Comparison")
|
152
208
|
print("=" * 50)
|
153
209
|
|
154
|
-
print(f"\n📍 Local Server: {
|
155
|
-
local_health = await check_server_health(
|
210
|
+
print(f"\n📍 Local Server: {local_config.base_url}")
|
211
|
+
local_health = await check_server_health(local_config)
|
156
212
|
print_health_status(local_health)
|
157
213
|
|
158
|
-
print(f"\n🌐
|
159
|
-
|
160
|
-
print_health_status(
|
214
|
+
print(f"\n🌐 Production Server: {production_config.base_url}")
|
215
|
+
production_health = await check_server_health(production_config)
|
216
|
+
print_health_status(production_health)
|
161
217
|
|
162
218
|
# Compare results
|
163
219
|
print("\n📊 Comparison Summary:")
|
164
|
-
if local_health and
|
220
|
+
if local_health and production_health:
|
165
221
|
local_components = local_health.get("components", {})
|
166
|
-
|
222
|
+
production_components = production_health.get("components", {})
|
167
223
|
|
168
224
|
all_components = set(local_components.keys()) | set(
|
169
|
-
|
225
|
+
production_components.keys()
|
170
226
|
)
|
171
227
|
|
172
228
|
for component in sorted(all_components):
|
173
229
|
local_status = local_components.get(component, {}).get(
|
174
230
|
"status", "missing"
|
175
231
|
)
|
176
|
-
|
232
|
+
production_status = production_components.get(component, {}).get(
|
177
233
|
"status", "missing"
|
178
234
|
)
|
179
235
|
|
180
|
-
if local_status ==
|
236
|
+
if local_status == production_status == "healthy":
|
181
237
|
icon = "✅"
|
182
|
-
elif local_status !=
|
238
|
+
elif local_status != production_status:
|
183
239
|
icon = "⚠️ "
|
184
240
|
else:
|
185
241
|
icon = "❌"
|
186
242
|
|
187
243
|
print(
|
188
|
-
f" {icon} {component}: Local={local_status},
|
244
|
+
f" {icon} {component}: Local={local_status}, Production={production_status}"
|
189
245
|
)
|
190
246
|
else:
|
191
247
|
print(" ❌ Cannot compare - one or both servers unreachable")
|
napistu/mcp/client.py
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# src/napistu/mcp/client.py
|
2
1
|
"""
|
3
2
|
MCP client for testing and interacting with Napistu MCP servers.
|
4
3
|
"""
|
@@ -8,20 +7,19 @@ import logging
|
|
8
7
|
from typing import Optional, Dict, Any, Mapping
|
9
8
|
|
10
9
|
from fastmcp import Client
|
10
|
+
from napistu.mcp.config import MCPClientConfig
|
11
11
|
|
12
12
|
logger = logging.getLogger(__name__)
|
13
13
|
|
14
14
|
|
15
|
-
async def check_server_health(
|
16
|
-
server_url: str = "http://127.0.0.1:8765",
|
17
|
-
) -> Optional[Dict[str, Any]]:
|
15
|
+
async def check_server_health(config: MCPClientConfig) -> Optional[Dict[str, Any]]:
|
18
16
|
"""
|
19
17
|
Health check using FastMCP client.
|
20
18
|
|
21
19
|
Parameters
|
22
20
|
----------
|
23
|
-
|
24
|
-
|
21
|
+
config : MCPClientConfig
|
22
|
+
Client configuration object with validated settings.
|
25
23
|
|
26
24
|
Returns
|
27
25
|
-------
|
@@ -37,13 +35,10 @@ async def check_server_health(
|
|
37
35
|
- components : Dict[str, Dict[str, str]]
|
38
36
|
Status of each component ('healthy', 'inactive', or 'unavailable')
|
39
37
|
"""
|
40
|
-
|
41
38
|
try:
|
42
|
-
|
43
|
-
mcp_url = server_url.rstrip("/") + "/mcp"
|
44
|
-
logger.info(f"Connecting to MCP server at: {mcp_url}")
|
39
|
+
logger.info(f"Connecting to MCP server at: {config.mcp_url}")
|
45
40
|
|
46
|
-
client = Client(mcp_url)
|
41
|
+
client = Client(config.mcp_url)
|
47
42
|
|
48
43
|
async with client:
|
49
44
|
logger.info("✅ FastMCP client connected")
|
@@ -137,16 +132,14 @@ def print_health_status(health: Optional[Mapping[str, Any]]) -> None:
|
|
137
132
|
print(f"Version: {health['version']}")
|
138
133
|
|
139
134
|
|
140
|
-
async def list_server_resources(
|
141
|
-
server_url: str = "http://127.0.0.1:8765",
|
142
|
-
) -> Optional[list]:
|
135
|
+
async def list_server_resources(config: MCPClientConfig) -> Optional[list]:
|
143
136
|
"""
|
144
137
|
List all available resources on the MCP server.
|
145
138
|
|
146
139
|
Parameters
|
147
140
|
----------
|
148
|
-
|
149
|
-
|
141
|
+
config : MCPClientConfig
|
142
|
+
Client configuration object with validated settings.
|
150
143
|
|
151
144
|
Returns
|
152
145
|
-------
|
@@ -154,10 +147,9 @@ async def list_server_resources(
|
|
154
147
|
List of available resources, or None if failed.
|
155
148
|
"""
|
156
149
|
try:
|
157
|
-
|
158
|
-
logger.info(f"Listing resources from: {mcp_url}")
|
150
|
+
logger.info(f"Listing resources from: {config.mcp_url}")
|
159
151
|
|
160
|
-
client = Client(mcp_url)
|
152
|
+
client = Client(config.mcp_url)
|
161
153
|
|
162
154
|
async with client:
|
163
155
|
resources = await client.list_resources()
|
@@ -170,7 +162,7 @@ async def list_server_resources(
|
|
170
162
|
|
171
163
|
|
172
164
|
async def read_server_resource(
|
173
|
-
resource_uri: str,
|
165
|
+
resource_uri: str, config: MCPClientConfig
|
174
166
|
) -> Optional[str]:
|
175
167
|
"""
|
176
168
|
Read a specific resource from the MCP server.
|
@@ -179,8 +171,8 @@ async def read_server_resource(
|
|
179
171
|
----------
|
180
172
|
resource_uri : str
|
181
173
|
URI of the resource to read (e.g., 'napistu://health')
|
182
|
-
|
183
|
-
|
174
|
+
config : MCPClientConfig
|
175
|
+
Client configuration object with validated settings.
|
184
176
|
|
185
177
|
Returns
|
186
178
|
-------
|
@@ -188,10 +180,9 @@ async def read_server_resource(
|
|
188
180
|
Resource content as text, or None if failed.
|
189
181
|
"""
|
190
182
|
try:
|
191
|
-
|
192
|
-
logger.info(f"Reading resource {resource_uri} from: {mcp_url}")
|
183
|
+
logger.info(f"Reading resource {resource_uri} from: {config.mcp_url}")
|
193
184
|
|
194
|
-
client = Client(mcp_url)
|
185
|
+
client = Client(config.mcp_url)
|
195
186
|
|
196
187
|
async with client:
|
197
188
|
result = await client.read_resource(resource_uri)
|