You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Is your feature request related to a problem? Please describe.
Currently, multitenant apps need to lock-and-register at .plot() to ensure the right credentials are used at upload time
It'd be easier if we had some sort of first-class functional client model where a client can be configured, with its own creds, and as long as the right client is used, the plot works
Recall that g objects functionally build up, like g2 = g1.edges(df)
Each plottable will either set its client, or a reference to another plottable and use its dynamically resolvable client, to be dynamically determined upon use (e.g., plot). For convenience, the client will be set for legacy convenient global notebook cases + more controllable multitenant scenarios:
Backwards compatible global/single-tenant: for notebook etc users + legacy
module has a single global client
graphistry.register(); g = graphistry.bind(...); g.plot():
top-level graphistry.register() mutates global client
by default, chained items use the latest global client
add graphistry.register(client=...)
potentially deprecate old access flows
modifying the client c bound in client=c impacts all plottables using it
access via c = graphistry.client_root() and graphistry.client_root(c)
New: Custom chainable roots, for multitenant
Generate a top-level g via explicit client instantiation
g = ClientUserPass().g()
g = graphistry.client(ClientUserPass())
Mid-chain, setting a new root that impacts all downstream, and optionally the current
g2 = g1.client(Client(...)) <- g2 uses a diff client
g1.set_client(Client(..) <- update g1's client, and also downstream like g2
Question
Default behavior during chaining: I can imagine g.copy() chaining to automatically do one of these:
* g2._client_root = g1 # so changing g1 will change g2
* g2._client_root = g1._client_root # so changing g1's root will change g2's, but changing g1 will not (unless it has the root)
Basically, is:
g._client_root : Client, so by ref eq of a client set at time of chain
g._client_root : Union[Plottable, Client], so when Plottable, a plot-time dynamic lookup of a parent plottable
and is that parent plottable g1? so requiring a traversal as deep as the functional chain
... or g1._client_root, which short-cuts the chain to probably just 1-2 hops, so just explicit client/set_client points at time of creation?
Clients: Start with just user/pass and api key, for simplicity
Roots: Do both root + downstream modes, so flexibility in when setting new tenants
Register interaction: minimize
Do not yet refactor register(...) params to use clients
When client mode is detected (e.g., existence of clients), ignore the register flow
Throw an Unsupported warning when detect mixing new vs old modes
Phase 2: SSO
Add SSO client support
Phase 3: Backport
Refactor old register code paths to use new ones
Probably as a sequence of PRs, like userpass/api/jwt first, and then sso after
Decide whether to deprecate old calling forms, keep current form as nice sugar, or give warnings if this reveals ambiguities
Describe alternatives you've considered
We may also be able to do something simple like overload plot():
c=ClientXYZ(..)
g.plot(client=c)
But I rather not complicate plot, and move to something more decoupled, like via locks, contexts, or these _client objects
withClientXYZ(...) asc:
g.plot()
Additional context
Current multitenancy workaround is a locked register() right before plot():
# create a shared global lockfromthreadingimportLockglobal_lock=Lock()
# do normal graphistry plottable buildup as usualg_1=graphistry.edges(...)...
...
g_n=g_1...
# change plot() call to include a locked just-in-time register:withglobal_lock:
graphistry.register(...)
g_n.plot()
The text was updated successfully, but these errors were encountered:
Is your feature request related to a problem? Please describe.
Currently, multitenant apps need to lock-and-register at
.plot()
to ensure the right credentials are used at upload timeIt'd be easier if we had some sort of first-class functional client model where a client can be configured, with its own creds, and as long as the right client is used, the plot works
Describe the solution you'd like
Internal base interface
Client
g.client() : Client
,g._client.token()
,g._client.refresh()
,g._client.switch()
, etcClientUnconfigured
,ClientUserPass
,ClientAPIKey
,ClientSSO
, ...Global and root chain clients
Recall that
g
objects functionally build up, likeg2 = g1.edges(df)
Each plottable will either set its client, or a reference to another plottable and use its dynamically resolvable client, to be dynamically determined upon use (e.g., plot). For convenience, the client will be set for legacy convenient global notebook cases + more controllable multitenant scenarios:
graphistry.register(); g = graphistry.bind(...); g.plot()
:graphistry.register()
mutates global clientgraphistry.register(client=...)
c
bound inclient=c
impacts all plottables using itc = graphistry.client_root()
andgraphistry.client_root(c)
Generate a top-level g via explicit client instantiation
g = ClientUserPass().g()
g = graphistry.client(ClientUserPass())
Mid-chain, setting a new root that impacts all downstream, and optionally the current
g2 = g1.client(Client(...))
<-g2
uses a diff clientg1.set_client(Client(..)
<- updateg1
's client, and also downstream likeg2
Question
Default behavior during chaining: I can imagine
g.copy()
chaining to automatically do one of these:*
g2._client_root = g1
# so changing g1 will change g2*
g2._client_root = g1._client_root
# so changing g1's root will change g2's, but changing g1 will not (unless it has the root)Basically, is:
g._client_root : Client
, so by ref eq of a client set at time of chaing._client_root : Union[Plottable, Client]
, so whenPlottable
, a plot-time dynamic lookup of a parent plottableg1
? so requiring a traversal as deep as the functional chaing1._client_root
, which short-cuts the chain to probably just 1-2 hops, so just explicit client/set_client points at time of creation?Examples
No need to track and work at the initial g root level
Rollout
Initially, we can likely target something like:
Phase 1: Simple standalone clients
register(...)
params to use clientsPhase 2: SSO
Phase 3: Backport
Describe alternatives you've considered
We may also be able to do something simple like overload plot():
But I rather not complicate plot, and move to something more decoupled, like via locks, contexts, or these _client objects
Additional context
Current multitenancy workaround is a locked
register()
right beforeplot()
:The text was updated successfully, but these errors were encountered: