Skip to content

Plugins: Give more flexibility to the user how to init client#663

Merged
exrhizo merged 6 commits into
feat/kustofrom
feat/plugin-flexible-client
Jun 11, 2025
Merged

Plugins: Give more flexibility to the user how to init client#663
exrhizo merged 6 commits into
feat/kustofrom
feat/plugin-flexible-client

Conversation

@exrhizo

@exrhizo exrhizo commented Jun 10, 2025

Copy link
Copy Markdown
Contributor

XyzGraph as an XyzClientWrapper with convenience methods

Changes:

  • Give more flexibility to users how to init (so louie can evolve independently)
  • XyzGraph decouple from Plottable - This way we can be more confident about independence

Requested by Thomas

  • Client to only stay open during query and then close
    • So I made a context manager & only keep the credentials on the Plottable

KustoGraph

  • kusto_query -> List[pd.DataFrame]
  • query_graph -> Plottable

It is very difficult to predict what kusto will output as far as nodes and edges, so we have an ergonomic hook to visualize graphs and the more flexible query, that just returns a list of dfs. query also has a hueristic for unpacking the nested tables from a graph project.

@exrhizo exrhizo requested review from DataBoyTX and tanmoyio June 10, 2025 16:53
Comment thread graphistry/PlotterBase.py Outdated
from .plugins.kustograph import KustoGraph
res = copy.copy(self)
res._kustograph = KustoGraph(res, kusto_config)
res._kustograph = KustoGraph.from_config(kusto_config)

@lmeyerov lmeyerov Jun 10, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm more of a fan of the previous mode because it doesn't lose current self bindings from the Plottable::copy() , which is our typical pattern here. The important part for safety is it's a fresh base instance object for client-local state.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(and if the caller wants empty, they can start with an empty)

@exrhizo exrhizo Jun 10, 2025

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the crux of what I am trying to reverse

I don't think these XyzGraphs should know anything about what is bound to the Plottable, that is the whole issue we are having in louie with it being unclear if these are multi tenant / thread safe / global values involved

Comment thread graphistry/PlotterBase.py Outdated
nodes, edges = res._spannergraph.gql_to_graph(query)

# TODO(tcook): add more error handling here if nodes or edges are empty
return res.nodes(nodes, 'identifier').edges(edges, 'source', 'destination')

@lmeyerov lmeyerov Jun 10, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hardcoding bindings here is a little weird to me in that it moves control of the schema out from gql_to_graph, causing coordination confusion, so maybe it should return bindings too? at that point, i think it should just return a plottable as before...

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the goal is a fresh one, maybe:

g = res._spannergraph.gql_to_graph(query)
return res.nodes(g._nodes, g._node).edges(g._edges, g._source, g._destination)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see the way I did it this time

self.connection.close()
logger.info("Connection to Spanner database closed.")
self.connection.close()
logger.info("Closed Spanner connection.")

@lmeyerov lmeyerov Jun 10, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fwiw, does this mean the caller is supposed to do res_g = g.kusto_query_to_graph(query); res_g._kusto_client.close() ? Not a blocker for the this PR, but am curious

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(In general, unsure what lifecycle pattern we want for reconnecting, closing connections, etc, getting back to the whole louie discussion)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the past the clients are never closed -- here I am assuming that the SpannerGraph is basically a client wrapper with convenience functions

Usually a user is using the graphistry object that seems more optimized for notebooks then for memory management

If someone wants memory management, then I think they can instantiate the SpannerGraph directly, like I want to do in louie

Comment thread graphistry/plugins/kustograph.py Outdated
Comment thread graphistry/plugins/spannergraph.py Outdated


def gql_to_graph(self, res: Plottable, query: str) -> Plottable:
def gql_to_graph(self, res: Plottable, query: str) -> Tuple[pd.DataFrame, pd.DataFrame]:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. I like having these explicit versions to help with explicit consumers, so we can do gql_df: str -> df and gql_graph: str -> plottable and consumer has known type

  2. scenarios like louie, and maybe convenience ones for users, benefit from gql: str -> df | plottable, and up to the consumer to handle the union type

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The weird thing to me is what if I don't want to chain in my Plottable

Comment thread graphistry/plugins/spannergraph.py Outdated

# TODO(tcook): add more error handling here if nodes or edges are empty
return res.nodes(nodes_df, 'identifier').edges(edges_df, 'source', 'destination')
return nodes_df, edges_df

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be problematic for louie. Louie expects plottable from gql_to_graph. Any specific reason for this?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Louie pins the graphistry version so we can change the interface, I don't feel as strongly about this - see comments to Leo

@lmeyerov lmeyerov Jun 10, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit lost on internal methods vs public

wrt public:

  • see: Plugins: Give more flexibility to the user how to init client #663 (comment)

  • Louie afaict benefits from a generic str -> pd.DataFrame | Plottable, where louie can do its own isinstance(...) and handle appropriately

  • I think beginner/vibes-y python users would benefit from that more dynamic type signature too...

  • ... and only when we do more 'serious' typed code would we want the explicit gql_to_g / gql_to_df variants (or maybe there is magic where we can gql<pd.DataFrame>(...)?). So I'd want "both" vs picking

I hit the same thing when we exposed the remote python+gfql endpoints and we wanted to support multiple return types

Comment thread graphistry/plugins/spannergraph.py Outdated
import time
from typing import Any, List, Dict, Optional

from google.cloud.spanner_dbapi.connection import connect, Connection

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same imports issue: #663 (comment)

@lmeyerov lmeyerov Jun 10, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can release in louie off of this PR sooner than later, but blocks landing as a public graphistry release

@exrhizo exrhizo merged commit 56a0f9d into feat/kusto Jun 11, 2025
17 of 27 checks passed
@exrhizo exrhizo deleted the feat/plugin-flexible-client branch June 11, 2025 03:53
@exrhizo

exrhizo commented Jun 11, 2025

Copy link
Copy Markdown
Contributor Author

Merged into #659

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants