Skip to content

Commit 7880a93

Browse files
author
Daniel Dror
committed
fix flake
1 parent 012094c commit 7880a93

File tree

1 file changed

+65
-28
lines changed

1 file changed

+65
-28
lines changed

fabric_rti_mcp/kusto/kusto_service.py

Lines changed: 65 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from fabric_rti_mcp.kusto.kusto_connection import KustoConnection, sanitize_uri
1818
from fabric_rti_mcp.kusto.kusto_formatter import KustoFormatter
1919

20+
2021
def canonical_entity_type(entity_type: str) -> str:
2122
"""
2223
Converts various entity type inputs to a canonical form.
@@ -34,10 +35,19 @@ def canonical_entity_type(entity_type: str) -> str:
3435
elif entity_type in ["database", "databases"]:
3536
return "database"
3637
else:
37-
raise ValueError(f"Unknown entity type '{entity_type}'. Supported types: table, materialized-view, function, graph, database.")
38+
raise ValueError(
39+
f"Unknown entity type '{entity_type}'. "
40+
"Supported types: table, materialized-view, function, graph, database."
41+
)
42+
3843

3944
CONFIG = KustoConfig.from_env()
40-
_DEFAULT_DB_NAME = CONFIG.default_service.default_database if CONFIG.default_service else KustoConnectionStringBuilder.DEFAULT_DATABASE_NAME
45+
_DEFAULT_DB_NAME = (
46+
CONFIG.default_service.default_database
47+
if CONFIG.default_service
48+
else KustoConnectionStringBuilder.DEFAULT_DATABASE_NAME
49+
)
50+
4151

4252
class KustoConnectionManager:
4353
def __init__(self) -> None:
@@ -186,56 +196,72 @@ def kusto_query(query: str, cluster_uri: str, database: Optional[str] = None) ->
186196
"""
187197
return _execute(query, cluster_uri, database=database)
188198

189-
def kusto_graph_query(graph_name:str, query: str, cluster_uri: str, database: str | None) -> Dict[str, Any]:
199+
200+
def kusto_graph_query(graph_name: str, query: str, cluster_uri: str, database: str | None) -> Dict[str, Any]:
190201
"""
191-
Intelligently executes a graph query using snapshots if they exist, otherwise falls back to transient graphs.
202+
Intelligently executes a graph query using snapshots if they exist,
203+
otherwise falls back to transient graphs.
192204
If no database is provided, uses the default database.
193205
194206
:param graph_name: Name of the graph to query.
195-
:param query: The KQL query to execute after the graph() function. Must include proper project clause for graph-match queries.
207+
:param query: The KQL query to execute after the graph() function.
208+
Must include proper project clause for graph-match queries.
196209
:param cluster_uri: The URI of the Kusto cluster.
197210
:param database: Optional database name. If not provided, uses the default database.
198211
:return: List of dictionaries containing query results.
199-
212+
200213
Critical:
201-
* Graph queries must have a graph-match clause and a projection clause. Optionally they may contain a where clause.
202-
* Graph entities are only accessible in the graph-match context. When leaving the context (sub-sequent '|'), the data is treated as a table, and graph-specific functions (like labels()) will not be available.
203-
* Always prefer expressing everything with graph patterns. Avoid using graph-to-table operator unless you have no other way around it.
204-
* There is no id() function on graph entities. If you need a unique identifier, make sure to check the schema and use an appropriate property.
205-
* There is no `type` property on graph entities. Use `labels()` function to get the list of labels for a node or edge.
206-
* Properties that are used outside the graph-match context are renamed to `_` instead of `.`. For example, `node.name` becomes `node_name`.
207-
* For variable length paths, you can use `all` or `any` to enforce conditions on all/any edges in variable path length elements (e.g. `()-[e*1..3]->() where all(e, labels() has 'Label')`).
214+
* Graph queries must have a graph-match clause and a projection clause.
215+
Optionally they may contain a where clause.
216+
* Graph entities are only accessible in the graph-match scope.
217+
When leaving that scope (sub-sequent '|'), the data is treated as a table,
218+
and graph-specific functions (like labels()) will not be available.
219+
* Always prefer expressing everything with graph patterns.
220+
Avoid using graph-to-table operator unless you have no other way around it.
221+
* There is no id() function on graph entities. If you need a unique identifier,
222+
make sure to check the schema and use an appropriate property.
223+
* There is no `type` property on graph entities.
224+
Use `labels()` function to get the list of labels for a node or edge.
225+
* Properties that are used outside the graph-match context are renamed to `_` instead of `.`.
226+
For example, `node.name` becomes `node_name`.
227+
* For variable length paths, you can use `all` or `any` to enforce conditions on all/any edges
228+
in variable path length elements (e.g. `()-[e*1..3]->() where all(e, labels() has 'Label')`).
208229
209230
Examples:
210-
231+
211232
# Basic node counting with graph-match (MUST include project clause):
212233
kusto_graph_query(
213-
"MyGraph",
214-
"| graph-match (node) project labels=labels(node) | mv-expand label = labels | summarize count() by tostring(label)",
234+
"MyGraph",
235+
"| graph-match (node) project labels=labels(node)
236+
| mv-expand label = labels
237+
| summarize count() by tostring(label)",
215238
cluster_uri
216239
)
217-
240+
218241
# Relationship matching:
219242
kusto_graph_query(
220-
"MyGraph",
221-
"| graph-match (house)-[relationship]->(character)
222-
where labels(house) has 'House' and labels(character) has 'Character'
243+
"MyGraph",
244+
"| graph-match (house)-[relationship]->(character)
245+
where labels(house) has 'House' and labels(character) has 'Character'
223246
project house.name, character.firstName, character.lastName
224247
| project house_name=house_name, character_full_name=character_firstName + ' ' + character_lastName
225248
| limit 10",
226249
cluster_uri
227250
)
228-
251+
229252
# Variable length path matching:
230253
kusto_graph_query(
231-
"MyGraph",
254+
"MyGraph",
232255
"| graph-match (source)-[path*1..3]->(destination) project source, destination, path | take 100",
233256
cluster_uri
234257
)
235258
"""
236-
query = f"graph('{graph_name}') {query}" # todo: this should properly choose between graph() and make-graph operator
259+
query = (
260+
f"graph('{graph_name}') {query}" # todo: this should properly choose between graph() and make-graph operator
261+
)
237262
return _execute(query, cluster_uri, database=database)
238263

264+
239265
@destructive_operation
240266
def kusto_command(command: str, cluster_uri: str, database: Optional[str] = None) -> Dict[str, Any]:
241267
"""
@@ -255,7 +281,8 @@ def kusto_list_entities(cluster_uri: str, entity_type: str, database: str | None
255281
Retrieves a list of all entities (databases, tables, materialized views, functions, graphs) in the Kusto cluster.
256282
257283
:param entity_type: Type of entities to list: "databases", "tables", "materialized-views", "functions", "graphs".
258-
:param database: The name of the database to list entities from. Required for all types except "databases" (which are top-level).
284+
:param database: The name of the database to list entities from.
285+
Required for all types except "databases" (which are top-level).
259286
:param cluster_uri: The URI of the Kusto cluster.
260287
261288
:return: List of dictionaries containing entity information.
@@ -274,6 +301,7 @@ def kusto_list_entities(cluster_uri: str, entity_type: str, database: str | None
274301
return _execute(".show graph_models", cluster_uri, database=database)
275302
return {}
276303

304+
277305
def kusto_describe_database(cluster_uri: str, database: str | None) -> Dict[str, Any]:
278306
"""
279307
Retrieves schema information for all entities (tables, materialized views, functions, graphs)
@@ -292,7 +320,9 @@ def kusto_describe_database(cluster_uri: str, database: str | None) -> Dict[str,
292320
)
293321

294322

295-
def kusto_describe_database_entity(entity_name: str, entity_type: str, cluster_uri: str, database: Optional[str] = None) -> Dict[str, Any]:
323+
def kusto_describe_database_entity(
324+
entity_name: str, entity_type: str, cluster_uri: str, database: Optional[str] = None
325+
) -> Dict[str, Any]:
296326
"""
297327
Retrieves the schema information for a specific entity (table, materialized view, function, graph)
298328
in the specified database. If no database is provided, uses the default database.
@@ -310,12 +340,20 @@ def kusto_describe_database_entity(entity_name: str, entity_type: str, cluster_u
310340
elif entity_type.lower() == "function":
311341
return _execute(f".show function {entity_name}", cluster_uri, database=database)
312342
elif entity_type.lower() == "materialized-view":
313-
return _execute(f".show materialized-view {entity_name} | project Name, SourceTable, Query, LastRun, LastRunResult, IsHealthy, IsEnabled, DocString", cluster_uri, database=database)
343+
return _execute(
344+
f".show materialized-view {entity_name} "
345+
"| project Name, SourceTable, Query, LastRun, LastRunResult, IsHealthy, IsEnabled, DocString",
346+
cluster_uri,
347+
database=database,
348+
)
314349
elif entity_type.lower() == "graph":
315-
return _execute(f".show graph_model {entity_name} details | project Name, Model", cluster_uri, database=database)
350+
return _execute(
351+
f".show graph_model {entity_name} details | project Name, Model", cluster_uri, database=database
352+
)
316353
# Add more entity types as needed
317354
return {}
318355

356+
319357
def kusto_sample_entity(
320358
entity_name: str,
321359
entity_type: str,
@@ -340,7 +378,6 @@ def kusto_sample_entity(
340378
if entity_type.lower() == "graph":
341379
# TODO: handle transient graphs properly
342380
return _execute(f"graph('{entity_name}') | sample {sample_size}", cluster_uri, database=database)
343-
344381

345382
raise ValueError(f"Sampling not supported for entity type '{entity_type}'.")
346383

0 commit comments

Comments
 (0)