From 89f3d5bd2f453a97ed2e55f1fe806132dd140ff3 Mon Sep 17 00:00:00 2001 From: Vaim Dev Date: Thu, 17 Oct 2024 13:32:38 +0800 Subject: [PATCH 01/34] fix (typecheck): fix typecheck issue --- graphistry/compute/ast.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphistry/compute/ast.py b/graphistry/compute/ast.py index d478c23f28..22683c76dd 100644 --- a/graphistry/compute/ast.py +++ b/graphistry/compute/ast.py @@ -299,7 +299,7 @@ def from_json(cls, d: dict) -> 'ASTEdge': direction=d['direction'] if 'direction' in d else None, edge_match=maybe_filter_dict_from_json(d, 'edge_match'), hops=d['hops'] if 'hops' in d else None, - to_fixed_point=d['to_fixed_point'] if 'to_fixed_point' in d else None, + to_fixed_point=d['to_fixed_point'] if 'to_fixed_point' in d else DEFAULT_FIXED_POINT, source_node_match=maybe_filter_dict_from_json(d, 'source_node_match'), destination_node_match=maybe_filter_dict_from_json(d, 'destination_node_match'), source_node_query=d['source_node_query'] if 'source_node_query' in d else None, From dbad1475296a5e1db1ad2a6eae318be75e6eec30 Mon Sep 17 00:00:00 2001 From: Vaim Dev Date: Mon, 28 Oct 2024 13:25:22 +0800 Subject: [PATCH 02/34] feat: Add databricks helper class and functions --- graphistry/pygraphistry.py | 72 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/graphistry/pygraphistry.py b/graphistry/pygraphistry.py index 0925a6a744..b14262d69f 100644 --- a/graphistry/pygraphistry.py +++ b/graphistry/pygraphistry.py @@ -2448,6 +2448,74 @@ def _handle_api_response(response): + # Databricks Dashboard SSO helper functions + + class DatabricksHelper(): + + @staticmethod + def sso_repeat_get_token(repeat, wait): + time.sleep(wait) + + for i in range(repeat): + token = PyGraphistry.sso_get_token() + if token: + return token + time.sleep(2) + + return + + @staticmethod + def databricks_sso_wait_for_token(repeat=5, wait=20): + from IPython.display import display, HTML + if not PyGraphistry.api_token(): + msg_html = '
.... ' + if not PyGraphistry.sso_repeat_get_token(repeat, wait): + msg_html = f'{msg_html}
Failed to get token after {repeat} .... ' + raise Exception(f"Failed to get token after {repeat} retries") + msg_html = f'{msg_html}
Got token' + display(HTML(msg_html)) + else: + display(HTML(f'
Token is valid, no waiting required.')) + + @staticmethod + def databricks_sso_login_init(wait=20): + from IPython.display import display, HTML, clear_output + def init_login(wait): + clear_output() + token = PyGraphistry.api_token() + if token: + is_valid = PyGraphistry.verify_token() + if not is_valid: + print("***********token not valid, refresh token*****************") + display(HTML(f'
Refresh token ....')) + try: + PyGraphistry.refresh() + except Exception: + pass + + else: + print("Token is still valid") + display(HTML(f'
Token is still valid ....')) + + else: + print("***********Prepare to sign in*****************") + + msg_html = f'
Prepare to sign in ....
Please Login with the link appear later. Waiting for success login for {wait} seconds, please login within {wait} seconds....
Please close the browser tab and come back to dashboard....' + + display(HTML(msg_html)) + init_login(wait) + + + @staticmethod + def databricks_sso_login(server="hub.graphistry.com", org_name=None, idp_name=None, retry=5, wait=20): + from IPython.display import clear_output + clear_output() + if not PyGraphistry.api_token(): + PyGraphistry.register(api=3, protocol="https", server=server, is_sso_login=True, org_name=org_name, idp_name=idp_name, sso_timeout=None, sso_opt_into_type="display") + + + + client_protocol_hostname = PyGraphistry.client_protocol_hostname store_token_creds_in_memory = PyGraphistry.store_token_creds_in_memory @@ -2502,6 +2570,10 @@ def _handle_api_response(response): switch_org = PyGraphistry.switch_org +databricks_sso_wait_for_token = PyGraphistry.DatabricksHelper.databricks_sso_wait_for_token +databricks_sso_login_init = PyGraphistry.DatabricksHelper.databricks_sso_login_init +databricks_sso_login = PyGraphistry.DatabricksHelper.databricks_sso_login + class NumpyJSONEncoder(json.JSONEncoder): def default(self, obj): From 799e93b0a8b2a93e262c33035a917a44bc0b16cb Mon Sep 17 00:00:00 2001 From: Vaim Dev Date: Mon, 28 Oct 2024 20:38:16 +0800 Subject: [PATCH 03/34] fix (refresh token, lint): Fix refresh token and lint issue --- graphistry/pygraphistry.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/graphistry/pygraphistry.py b/graphistry/pygraphistry.py index b14262d69f..1395e127b9 100644 --- a/graphistry/pygraphistry.py +++ b/graphistry/pygraphistry.py @@ -406,6 +406,8 @@ def refresh(token=None, fail_silent=False): logger.debug("2. @PyGraphistry refresh :relogin") if isinstance(e, TokenExpireException): print("Token is expired, you need to relogin") + PyGraphistry._config['api_token'] = None + PyGraphistry._is_authenticated = False return PyGraphistry.relogin() if not fail_silent: @@ -2475,7 +2477,7 @@ def databricks_sso_wait_for_token(repeat=5, wait=20): msg_html = f'{msg_html}
Got token' display(HTML(msg_html)) else: - display(HTML(f'
Token is valid, no waiting required.')) + display(HTML('
Token is valid, no waiting required.')) @staticmethod def databricks_sso_login_init(wait=20): @@ -2487,7 +2489,7 @@ def init_login(wait): is_valid = PyGraphistry.verify_token() if not is_valid: print("***********token not valid, refresh token*****************") - display(HTML(f'
Refresh token ....')) + display(HTML('
Refresh token ....')) try: PyGraphistry.refresh() except Exception: @@ -2495,7 +2497,7 @@ def init_login(wait): else: print("Token is still valid") - display(HTML(f'
Token is still valid ....')) + display(HTML('
Token is still valid ....')) else: print("***********Prepare to sign in*****************") @@ -2514,9 +2516,6 @@ def databricks_sso_login(server="hub.graphistry.com", org_name=None, idp_name=No PyGraphistry.register(api=3, protocol="https", server=server, is_sso_login=True, org_name=org_name, idp_name=idp_name, sso_timeout=None, sso_opt_into_type="display") - - - client_protocol_hostname = PyGraphistry.client_protocol_hostname store_token_creds_in_memory = PyGraphistry.store_token_creds_in_memory server = PyGraphistry.server @@ -2569,7 +2568,7 @@ def databricks_sso_login(server="hub.graphistry.com", org_name=None, idp_name=No personal_key_secret = PyGraphistry.personal_key_secret switch_org = PyGraphistry.switch_org - +# databricks dashboard helper functions databricks_sso_wait_for_token = PyGraphistry.DatabricksHelper.databricks_sso_wait_for_token databricks_sso_login_init = PyGraphistry.DatabricksHelper.databricks_sso_login_init databricks_sso_login = PyGraphistry.DatabricksHelper.databricks_sso_login From e1737d84846cac187c827f4fc5efc954a18e8cd3 Mon Sep 17 00:00:00 2001 From: Vaim Dev Date: Tue, 29 Oct 2024 12:19:31 +0800 Subject: [PATCH 04/34] fix (lint): fix lint issue --- graphistry/pygraphistry.py | 1 + 1 file changed, 1 insertion(+) diff --git a/graphistry/pygraphistry.py b/graphistry/pygraphistry.py index 1395e127b9..62d3a6bb91 100644 --- a/graphistry/pygraphistry.py +++ b/graphistry/pygraphistry.py @@ -2482,6 +2482,7 @@ def databricks_sso_wait_for_token(repeat=5, wait=20): @staticmethod def databricks_sso_login_init(wait=20): from IPython.display import display, HTML, clear_output + def init_login(wait): clear_output() token = PyGraphistry.api_token() From caa7809a4a01c07e1c5461d88663067bdad533ea Mon Sep 17 00:00:00 2001 From: Vaim Dev Date: Tue, 29 Oct 2024 12:38:19 +0800 Subject: [PATCH 05/34] fix (databricks helper): fix missing function definition --- graphistry/__init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/graphistry/__init__.py b/graphistry/__init__.py index befef2c1a2..35de6f354d 100644 --- a/graphistry/__init__.py +++ b/graphistry/__init__.py @@ -46,7 +46,10 @@ ArrowFileUploader, PyGraphistry, from_igraph, - from_cugraph + from_cugraph, + databricks_sso_wait_for_token, + databricks_sso_login_init, + databricks_sso_login ) from graphistry.compute import ( From 71c5eb17f219ee8eabfeaf861ba42e8c8132a745 Mon Sep 17 00:00:00 2001 From: Vaim Dev Date: Wed, 30 Oct 2024 16:24:44 +0800 Subject: [PATCH 06/34] fix (databricks helpers): fix function call namespace --- graphistry/pygraphistry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphistry/pygraphistry.py b/graphistry/pygraphistry.py index 62d3a6bb91..38e777d73d 100644 --- a/graphistry/pygraphistry.py +++ b/graphistry/pygraphistry.py @@ -2471,7 +2471,7 @@ def databricks_sso_wait_for_token(repeat=5, wait=20): from IPython.display import display, HTML if not PyGraphistry.api_token(): msg_html = '
.... ' - if not PyGraphistry.sso_repeat_get_token(repeat, wait): + if not PyGraphistry.DatabricksHelper.sso_repeat_get_token(repeat, wait): msg_html = f'{msg_html}
Failed to get token after {repeat} .... ' raise Exception(f"Failed to get token after {repeat} retries") msg_html = f'{msg_html}
Got token' From c187ead41bcafb5ee6e0706495b8365286f3e474 Mon Sep 17 00:00:00 2001 From: Vaim Dev Date: Wed, 6 Nov 2024 00:02:29 +0800 Subject: [PATCH 07/34] wip (sso logic): Add SSO flow token verification in plot function, which originally just a refresh() --- graphistry/PlotterBase.py | 14 +++- graphistry/__init__.py | 5 +- graphistry/pygraphistry.py | 151 +++++++++++++++++++++++-------------- 3 files changed, 108 insertions(+), 62 deletions(-) diff --git a/graphistry/PlotterBase.py b/graphistry/PlotterBase.py index d56d07f6b6..3f8daff49e 100644 --- a/graphistry/PlotterBase.py +++ b/graphistry/PlotterBase.py @@ -1403,7 +1403,19 @@ def plot( info = PyGraphistry._etl1(dataset) elif api_version == 3: logger.debug("3. @PloatterBase plot: PyGraphistry.org_name(): {}".format(PyGraphistry.org_name())) - PyGraphistry.refresh() + + if not PyGraphistry.api_token() and PyGraphistry.sso_state(): # if it is sso login + if in_ipython() or in_databricks() or PyGraphistry._config["sso_opt_into_type"] == 'display': + PyGraphistry.sso_wait_for_token_html_display() + if not PyGraphistry.sso_verify_token_html(): + PyGraphistry.sso_wait_for_token_html_display() + PyGraphistry.refresh() + else: + PyGraphistry.sso_repeat_get_token() + + + else: # if not sso mode, just refresh to make sure token is valid + PyGraphistry.refresh() logger.debug("4. @PloatterBase plot: PyGraphistry.org_name(): {}".format(PyGraphistry.org_name())) dataset = self._plot_dispatch(g, n, name, description, 'arrow', self._style, memoize) diff --git a/graphistry/__init__.py b/graphistry/__init__.py index 35de6f354d..d7af05f064 100644 --- a/graphistry/__init__.py +++ b/graphistry/__init__.py @@ -47,9 +47,8 @@ PyGraphistry, from_igraph, from_cugraph, - databricks_sso_wait_for_token, - databricks_sso_login_init, - databricks_sso_login + sso_wait_for_token_html_display, + register_databricks_sso, ) from graphistry.compute import ( diff --git a/graphistry/pygraphistry.py b/graphistry/pygraphistry.py index 38e777d73d..9f015776c9 100644 --- a/graphistry/pygraphistry.py +++ b/graphistry/pygraphistry.py @@ -135,6 +135,12 @@ def __reset_token_creds_in_memory(): PyGraphistry._config["api_key"] = None PyGraphistry._is_authenticated = False + @staticmethod + def __reset_sso_variables_in_memory(): + """Reset the sso related variable in memory, used when switching hosts, switching register method""" + + PyGraphistry._config["sso_state"] = None + PyGraphistry._config["sso_opt_into_type"] = None @staticmethod @@ -572,6 +578,11 @@ def certificate_validation(value=None): def set_bolt_driver(driver=None): PyGraphistry._config["bolt_driver"] = bolt_util.to_bolt_driver(driver) + @staticmethod + def set_sso_opt_into_type(value: Optional[str]): + PyGraphistry._config["sso_opt_into_type"] = value + + @staticmethod def register( key: Optional[str] = None, @@ -709,6 +720,8 @@ def register( PyGraphistry.set_bolt_driver(bolt) # Reset token creds PyGraphistry.__reset_token_creds_in_memory() + # Reset sso_state in memory + PyGraphistry.__reset_sso_variables_in_memory() if not (username is None) and not (password is None): PyGraphistry.login(username, password, org_name) @@ -2448,73 +2461,94 @@ def _handle_api_response(response): logger.error('Error: %s', response, exc_info=True) raise Exception("Unknown Error") + @staticmethod + def sso_repeat_get_token(repeat: int = 20, wait: int = 5): + """ Function to repeatly call to obtain the jwt token after sso login + Function to obtain the JWT token after SSO login + """ + + for _ in range(repeat): + token = PyGraphistry.sso_get_token() + if token: + return token + time.sleep(wait) + return + + @staticmethod + def sso_wait_for_token_html_display(repeat: int = 20, wait: int = 5): + """Get the JWT token for SSO login and display corresponding message in HTML + Get the JWT token for SSO login and display corresponding message in HTML + """ + from IPython.display import display, HTML + if not PyGraphistry.api_token(): + msg_html = '
.... ' + if not PyGraphistry.sso_repeat_get_token(repeat, wait): + msg_html = f'{msg_html}
Failed to get token after {repeat*wait} seconds .... ' + raise Exception(f"Failed to get token after {repeat*wait} seconds ....") + msg_html = f'{msg_html}
Got token' + display(HTML(msg_html)) + else: + display(HTML('
Token is valid, no waiting required.')) - # Databricks Dashboard SSO helper functions - class DatabricksHelper(): - - @staticmethod - def sso_repeat_get_token(repeat, wait): - time.sleep(wait) - - for i in range(repeat): - token = PyGraphistry.sso_get_token() - if token: - return token - time.sleep(2) - - return - - @staticmethod - def databricks_sso_wait_for_token(repeat=5, wait=20): - from IPython.display import display, HTML - if not PyGraphistry.api_token(): - msg_html = '
.... ' - if not PyGraphistry.DatabricksHelper.sso_repeat_get_token(repeat, wait): - msg_html = f'{msg_html}
Failed to get token after {repeat} .... ' - raise Exception(f"Failed to get token after {repeat} retries") - msg_html = f'{msg_html}
Got token' - display(HTML(msg_html)) + @staticmethod + def sso_verify_token_html( + repeat: int = 20, + wait: int = 5, + ) -> bool: + from IPython.display import display, HTML, clear_output + + clear_output() + token = PyGraphistry.api_token() + if token: + is_valid = PyGraphistry.verify_token() + if not is_valid: + print("***********token not valid, refresh token*****************") + display(HTML('
Refresh token ....')) + try: + PyGraphistry.refresh() + except Exception: + pass + else: - display(HTML('
Token is valid, no waiting required.')) + print("Token is still valid") + display(HTML('
Token is still valid ....')) - @staticmethod - def databricks_sso_login_init(wait=20): - from IPython.display import display, HTML, clear_output - - def init_login(wait): - clear_output() - token = PyGraphistry.api_token() - if token: - is_valid = PyGraphistry.verify_token() - if not is_valid: - print("***********token not valid, refresh token*****************") - display(HTML('
Refresh token ....')) - try: - PyGraphistry.refresh() - except Exception: - pass + else: + print("***********Prepare to sign in*****************") + msg_html = f'
Prepare to sign in ....
Please Login with the link appear later. Waiting for success login for {repeat*wait} seconds, please login within {wait} seconds....
Please close the browser tab and come back to dashboard....' + display(HTML(msg_html)) - else: - print("Token is still valid") - display(HTML('
Token is still valid ....')) + return False - else: - print("***********Prepare to sign in*****************") - - msg_html = f'
Prepare to sign in ....
Please Login with the link appear later. Waiting for success login for {wait} seconds, please login within {wait} seconds....
Please close the browser tab and come back to dashboard....' + return True - display(HTML(msg_html)) - init_login(wait) - + # Databricks Dashboard SSO helper functions + class DatabricksHelper(): + """Helper class for databricks. + + **Helper class to improve the sso login flow** + + """ @staticmethod - def databricks_sso_login(server="hub.graphistry.com", org_name=None, idp_name=None, retry=5, wait=20): - from IPython.display import clear_output - clear_output() + def register_databricks_sso( + server: Optional[str] = None, + org_name: Optional[str] = None, + idp_name: Optional[str] = None, + **kwargs + ): if not PyGraphistry.api_token(): PyGraphistry.register(api=3, protocol="https", server=server, is_sso_login=True, org_name=org_name, idp_name=idp_name, sso_timeout=None, sso_opt_into_type="display") + + + # @staticmethod + # def databricks_sso_login(server="hub.graphistry.com", org_name=None, idp_name=None, retry=5, wait=20): + # from IPython.display import clear_output + # clear_output() + # if not PyGraphistry.api_token(): + # PyGraphistry.register(api=3, protocol="https", server=server, is_sso_login=True, org_name=org_name, idp_name=idp_name, sso_timeout=None, sso_opt_into_type="display") client_protocol_hostname = PyGraphistry.client_protocol_hostname @@ -2570,9 +2604,10 @@ def databricks_sso_login(server="hub.graphistry.com", org_name=None, idp_name=No switch_org = PyGraphistry.switch_org # databricks dashboard helper functions -databricks_sso_wait_for_token = PyGraphistry.DatabricksHelper.databricks_sso_wait_for_token -databricks_sso_login_init = PyGraphistry.DatabricksHelper.databricks_sso_login_init -databricks_sso_login = PyGraphistry.DatabricksHelper.databricks_sso_login +sso_wait_for_token_html_display = PyGraphistry.sso_wait_for_token_html_display +sso_verify_token_html = PyGraphistry.sso_verify_token_html +sso_repeat_get_token = PyGraphistry.sso_repeat_get_token +register_databricks_sso = PyGraphistry.DatabricksHelper.register_databricks_sso class NumpyJSONEncoder(json.JSONEncoder): From 412e944009a10c726a892e15f6fb8eae00207d13 Mon Sep 17 00:00:00 2001 From: Vaim Dev Date: Wed, 6 Nov 2024 10:12:08 +0800 Subject: [PATCH 08/34] wip (sso): fix whether to throw exception when fail to get token --- graphistry/pygraphistry.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/graphistry/pygraphistry.py b/graphistry/pygraphistry.py index 9f015776c9..192dc4b2fb 100644 --- a/graphistry/pygraphistry.py +++ b/graphistry/pygraphistry.py @@ -2476,7 +2476,7 @@ def sso_repeat_get_token(repeat: int = 20, wait: int = 5): return @staticmethod - def sso_wait_for_token_html_display(repeat: int = 20, wait: int = 5): + def sso_wait_for_token_html_display(repeat: int = 20, wait: int = 5, fail_silently: bool = True): """Get the JWT token for SSO login and display corresponding message in HTML Get the JWT token for SSO login and display corresponding message in HTML """ @@ -2485,7 +2485,8 @@ def sso_wait_for_token_html_display(repeat: int = 20, wait: int = 5): msg_html = '
.... ' if not PyGraphistry.sso_repeat_get_token(repeat, wait): msg_html = f'{msg_html}
Failed to get token after {repeat*wait} seconds .... ' - raise Exception(f"Failed to get token after {repeat*wait} seconds ....") + if not fail_silently: + raise Exception(f"Failed to get token after {repeat*wait} seconds ....") msg_html = f'{msg_html}
Got token' display(HTML(msg_html)) else: From 9283e8ad582eecf1541ae23209a8953be5c10064 Mon Sep 17 00:00:00 2001 From: Vaim Dev Date: Wed, 6 Nov 2024 10:31:20 +0800 Subject: [PATCH 09/34] wip (sso): fix message display logic --- graphistry/pygraphistry.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/graphistry/pygraphistry.py b/graphistry/pygraphistry.py index 192dc4b2fb..a2982bd393 100644 --- a/graphistry/pygraphistry.py +++ b/graphistry/pygraphistry.py @@ -2476,7 +2476,7 @@ def sso_repeat_get_token(repeat: int = 20, wait: int = 5): return @staticmethod - def sso_wait_for_token_html_display(repeat: int = 20, wait: int = 5, fail_silently: bool = True): + def sso_wait_for_token_html_display(repeat: int = 20, wait: int = 5, fail_silently: bool = False): """Get the JWT token for SSO login and display corresponding message in HTML Get the JWT token for SSO login and display corresponding message in HTML """ @@ -2486,7 +2486,12 @@ def sso_wait_for_token_html_display(repeat: int = 20, wait: int = 5, fail_silent if not PyGraphistry.sso_repeat_get_token(repeat, wait): msg_html = f'{msg_html}
Failed to get token after {repeat*wait} seconds .... ' if not fail_silently: - raise Exception(f"Failed to get token after {repeat*wait} seconds ....") + raise Exception(f"Failed to get token after {repeat*wait} seconds. Please re-run the process") + else: + msg_html = f'{msg_html}
Got token' + display(HTML(msg_html)) + return + msg_html = f'{msg_html}
Got token' display(HTML(msg_html)) else: From be26deeb1487dbc247a5721192aeecfe0c416c4f Mon Sep 17 00:00:00 2001 From: Vaim Dev Date: Wed, 6 Nov 2024 11:04:35 +0800 Subject: [PATCH 10/34] fix (sso): fix flow --- graphistry/pygraphistry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphistry/pygraphistry.py b/graphistry/pygraphistry.py index a2982bd393..48ac13f96e 100644 --- a/graphistry/pygraphistry.py +++ b/graphistry/pygraphistry.py @@ -2486,7 +2486,7 @@ def sso_wait_for_token_html_display(repeat: int = 20, wait: int = 5, fail_silent if not PyGraphistry.sso_repeat_get_token(repeat, wait): msg_html = f'{msg_html}
Failed to get token after {repeat*wait} seconds .... ' if not fail_silently: - raise Exception(f"Failed to get token after {repeat*wait} seconds. Please re-run the process") + raise Exception(f"Failed to get token after {repeat*wait} seconds. Please re-run the login process") else: msg_html = f'{msg_html}
Got token' display(HTML(msg_html)) From 5ea4841889d2163d375365f609c3802fdc882898 Mon Sep 17 00:00:00 2001 From: Vaim Dev Date: Wed, 6 Nov 2024 22:49:22 +0800 Subject: [PATCH 11/34] fix (sso): fix display message flow --- graphistry/pygraphistry.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/graphistry/pygraphistry.py b/graphistry/pygraphistry.py index 48ac13f96e..c56049fd8c 100644 --- a/graphistry/pygraphistry.py +++ b/graphistry/pygraphistry.py @@ -422,7 +422,7 @@ def refresh(token=None, fail_silent=False): @staticmethod def verify_token(token=None, fail_silent=False) -> bool: - """Return True iff current or provided token is still valid""" + """Return True if current or provided token is still valid""" using_self_token = token is None try: logger.debug("JWT refresh") @@ -2476,7 +2476,7 @@ def sso_repeat_get_token(repeat: int = 20, wait: int = 5): return @staticmethod - def sso_wait_for_token_html_display(repeat: int = 20, wait: int = 5, fail_silently: bool = False): + def sso_wait_for_token_html_display(repeat: int = 20, wait: int = 5, fail_silent: bool = False): """Get the JWT token for SSO login and display corresponding message in HTML Get the JWT token for SSO login and display corresponding message in HTML """ @@ -2485,7 +2485,7 @@ def sso_wait_for_token_html_display(repeat: int = 20, wait: int = 5, fail_silent msg_html = '
.... ' if not PyGraphistry.sso_repeat_get_token(repeat, wait): msg_html = f'{msg_html}
Failed to get token after {repeat*wait} seconds .... ' - if not fail_silently: + if not fail_silent: raise Exception(f"Failed to get token after {repeat*wait} seconds. Please re-run the login process") else: msg_html = f'{msg_html}
Got token' @@ -2506,6 +2506,7 @@ def sso_verify_token_html( from IPython.display import display, HTML, clear_output clear_output() + required_login = False token = PyGraphistry.api_token() if token: is_valid = PyGraphistry.verify_token() @@ -2515,20 +2516,22 @@ def sso_verify_token_html( try: PyGraphistry.refresh() except Exception: - pass + required_login = True else: print("Token is still valid") display(HTML('
Token is still valid ....')) else: + required_login = True + + if required_login: print("***********Prepare to sign in*****************") msg_html = f'
Prepare to sign in ....
Please Login with the link appear later. Waiting for success login for {repeat*wait} seconds, please login within {wait} seconds....
Please close the browser tab and come back to dashboard....' display(HTML(msg_html)) - return False - return True + return not required_login # Databricks Dashboard SSO helper functions From 8a482b5abb7f2bff0bc75ef9c6b83d98723b3526 Mon Sep 17 00:00:00 2001 From: Vaim Dev Date: Thu, 7 Nov 2024 21:47:10 +0800 Subject: [PATCH 12/34] fix (sso): Graph is not shown in dashboard due to only the first HTML will be displayed. --- graphistry/PlotterBase.py | 4 ++-- graphistry/pygraphistry.py | 47 ++++++++++++++++++++++++++++++++------ 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/graphistry/PlotterBase.py b/graphistry/PlotterBase.py index 3f8daff49e..4deb76c6ff 100644 --- a/graphistry/PlotterBase.py +++ b/graphistry/PlotterBase.py @@ -1406,9 +1406,9 @@ def plot( if not PyGraphistry.api_token() and PyGraphistry.sso_state(): # if it is sso login if in_ipython() or in_databricks() or PyGraphistry._config["sso_opt_into_type"] == 'display': - PyGraphistry.sso_wait_for_token_html_display() + PyGraphistry.sso_wait_for_token_text_display() if not PyGraphistry.sso_verify_token_html(): - PyGraphistry.sso_wait_for_token_html_display() + PyGraphistry.sso_wait_for_token_text_display() PyGraphistry.refresh() else: PyGraphistry.sso_repeat_get_token() diff --git a/graphistry/pygraphistry.py b/graphistry/pygraphistry.py index c56049fd8c..43dbb47ba2 100644 --- a/graphistry/pygraphistry.py +++ b/graphistry/pygraphistry.py @@ -277,7 +277,7 @@ def _handle_auth_url(auth_url, sso_timeout, sso_opt_into_type): if in_ipython() or in_databricks() or sso_opt_into_type == 'display': # If run in notebook, just display the HTML # from IPython.core.display import HTML from IPython.display import display, HTML - display(HTML(f'Login SSO')) + display(HTML(f'Login SSO
Please click the above URL to open browser to login')) print("Please click the above URL to open browser to login") print(f"If you cannot see the URL, please open browser, browse to this URL: {auth_url}") print("Please close browser tab after SSO login to back to notebook") @@ -2474,7 +2474,36 @@ def sso_repeat_get_token(repeat: int = 20, wait: int = 5): time.sleep(wait) return - + + @staticmethod + def sso_wait_for_token_display(repeat: int = 20, wait: int = 5, fail_silent: bool = False, display_mode: str = 'text'): + if display_mode == 'html': + PyGraphistry.sso_wait_for_token_html_display(repeat, wait, fail_silent) + else: + PyGraphistry.sso_wait_for_token_text_display(repeat, wait, fail_silent) + + @staticmethod + def sso_wait_for_token_text_display(repeat: int = 20, wait: int = 5, fail_silent: bool = False): + """Get the JWT token for SSO login and display corresponding message in text + Get the JWT token for SSO login and display corresponding message in text + """ + if not PyGraphistry.api_token(): + msg_text = '....' + if not PyGraphistry.sso_repeat_get_token(repeat, wait): + msg_text = f'{msg_text}\nFailed to get token after {repeat*wait} seconds ....' + if not fail_silent: + raise Exception(f"Failed to get token after {repeat*wait} seconds. Please re-run the login process") + else: + msg_text = f'{msg_text}\nGot token' + print(msg_text) + return + + msg_text = f'{msg_text}\nGot token' + print(msg_text) + else: + print('Token is valid, no waiting required.') + + @staticmethod def sso_wait_for_token_html_display(repeat: int = 20, wait: int = 5, fail_silent: bool = False): """Get the JWT token for SSO login and display corresponding message in HTML @@ -2499,20 +2528,23 @@ def sso_wait_for_token_html_display(repeat: int = 20, wait: int = 5, fail_silent @staticmethod - def sso_verify_token_html( + def sso_verify_token_display( repeat: int = 20, wait: int = 5, + display_mode: str = 'text' ) -> bool: - from IPython.display import display, HTML, clear_output + if display_mode == 'html': + from IPython.display import display, HTML, clear_output + clear_output() - clear_output() required_login = False token = PyGraphistry.api_token() if token: is_valid = PyGraphistry.verify_token() if not is_valid: print("***********token not valid, refresh token*****************") - display(HTML('
Refresh token ....')) + if display_mode == 'html': + display(HTML('
Refresh token ....')) try: PyGraphistry.refresh() except Exception: @@ -2520,7 +2552,8 @@ def sso_verify_token_html( else: print("Token is still valid") - display(HTML('
Token is still valid ....')) + if display_mode == 'html': + display(HTML('
Token is still valid ....')) else: required_login = True From ab2794ca49bfa6df12f32dee6b1d4cfb6688127a Mon Sep 17 00:00:00 2001 From: Vaim Dev Date: Thu, 7 Nov 2024 21:58:45 +0800 Subject: [PATCH 13/34] wip (sso): fix syntax error --- graphistry/PlotterBase.py | 4 ++-- graphistry/__init__.py | 2 +- graphistry/pygraphistry.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/graphistry/PlotterBase.py b/graphistry/PlotterBase.py index 4deb76c6ff..8d4913b03c 100644 --- a/graphistry/PlotterBase.py +++ b/graphistry/PlotterBase.py @@ -1407,8 +1407,8 @@ def plot( if not PyGraphistry.api_token() and PyGraphistry.sso_state(): # if it is sso login if in_ipython() or in_databricks() or PyGraphistry._config["sso_opt_into_type"] == 'display': PyGraphistry.sso_wait_for_token_text_display() - if not PyGraphistry.sso_verify_token_html(): - PyGraphistry.sso_wait_for_token_text_display() + if not PyGraphistry.sso_verify_token_display(): + PyGraphistry.sso_wait_for_token_display() PyGraphistry.refresh() else: PyGraphistry.sso_repeat_get_token() diff --git a/graphistry/__init__.py b/graphistry/__init__.py index d7af05f064..f5e98be771 100644 --- a/graphistry/__init__.py +++ b/graphistry/__init__.py @@ -47,7 +47,7 @@ PyGraphistry, from_igraph, from_cugraph, - sso_wait_for_token_html_display, + sso_wait_for_token_display, register_databricks_sso, ) diff --git a/graphistry/pygraphistry.py b/graphistry/pygraphistry.py index 43dbb47ba2..c49c38fcde 100644 --- a/graphistry/pygraphistry.py +++ b/graphistry/pygraphistry.py @@ -2646,8 +2646,8 @@ def register_databricks_sso( switch_org = PyGraphistry.switch_org # databricks dashboard helper functions -sso_wait_for_token_html_display = PyGraphistry.sso_wait_for_token_html_display -sso_verify_token_html = PyGraphistry.sso_verify_token_html +sso_wait_for_token_display = PyGraphistry.sso_wait_for_token_display +sso_verify_token_display = PyGraphistry.sso_verify_token_display sso_repeat_get_token = PyGraphistry.sso_repeat_get_token register_databricks_sso = PyGraphistry.DatabricksHelper.register_databricks_sso From 5b35284328eaeae968245876a857afd4c3403701 Mon Sep 17 00:00:00 2001 From: Vaim Dev Date: Fri, 8 Nov 2024 08:47:28 +0800 Subject: [PATCH 14/34] wip (sso): debugging code --- graphistry/pygraphistry.py | 1 + 1 file changed, 1 insertion(+) diff --git a/graphistry/pygraphistry.py b/graphistry/pygraphistry.py index c49c38fcde..48b8961b6b 100644 --- a/graphistry/pygraphistry.py +++ b/graphistry/pygraphistry.py @@ -438,6 +438,7 @@ def verify_token(token=None, fail_silent=False) -> bool: PyGraphistry._is_authenticated = ok return ok except Exception as e: + raise e if not fail_silent: util.error("Failed to verify token: %s" % str(e)) return False From 8355b0f04b1baf97bba4ca1b2992b14ef86b2a77 Mon Sep 17 00:00:00 2001 From: Vaim Dev Date: Fri, 8 Nov 2024 09:22:16 +0800 Subject: [PATCH 15/34] wip (debug): add debug print --- graphistry/pygraphistry.py | 1 + 1 file changed, 1 insertion(+) diff --git a/graphistry/pygraphistry.py b/graphistry/pygraphistry.py index 48b8961b6b..c7434a98e8 100644 --- a/graphistry/pygraphistry.py +++ b/graphistry/pygraphistry.py @@ -2542,6 +2542,7 @@ def sso_verify_token_display( token = PyGraphistry.api_token() if token: is_valid = PyGraphistry.verify_token() + print(f"is_valid : {is_valid") if not is_valid: print("***********token not valid, refresh token*****************") if display_mode == 'html': From 1a2ab33ad49f8c4a6d0c4d148ba1c91c7b7b6999 Mon Sep 17 00:00:00 2001 From: Vaim Dev Date: Fri, 8 Nov 2024 09:24:41 +0800 Subject: [PATCH 16/34] wip (fix): syntax error --- graphistry/pygraphistry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphistry/pygraphistry.py b/graphistry/pygraphistry.py index c7434a98e8..0ba30eba5c 100644 --- a/graphistry/pygraphistry.py +++ b/graphistry/pygraphistry.py @@ -2542,7 +2542,7 @@ def sso_verify_token_display( token = PyGraphistry.api_token() if token: is_valid = PyGraphistry.verify_token() - print(f"is_valid : {is_valid") + print(f"is_valid : {is_valid}") if not is_valid: print("***********token not valid, refresh token*****************") if display_mode == 'html': From a53664886f5f20ccc8196d3974c2ac9cdb22e20a Mon Sep 17 00:00:00 2001 From: Vaim Dev Date: Fri, 8 Nov 2024 10:58:01 +0800 Subject: [PATCH 17/34] wip (debug):debugging print --- graphistry/pygraphistry.py | 1 + 1 file changed, 1 insertion(+) diff --git a/graphistry/pygraphistry.py b/graphistry/pygraphistry.py index 0ba30eba5c..cfd580e89b 100644 --- a/graphistry/pygraphistry.py +++ b/graphistry/pygraphistry.py @@ -424,6 +424,7 @@ def refresh(token=None, fail_silent=False): def verify_token(token=None, fail_silent=False) -> bool: """Return True if current or provided token is still valid""" using_self_token = token is None + print(f"token to verify: {PyGraphistry.api_token() if using_self_token else token}") try: logger.debug("JWT refresh") if using_self_token: From dd29430693e527b3ac3a17b45e85169c7067bc4c Mon Sep 17 00:00:00 2001 From: Vaim Dev Date: Fri, 8 Nov 2024 11:06:42 +0800 Subject: [PATCH 18/34] wip (debug): debugging print --- graphistry/arrow_uploader.py | 1 + 1 file changed, 1 insertion(+) diff --git a/graphistry/arrow_uploader.py b/graphistry/arrow_uploader.py index c4a4127643..a0e1bc44b2 100644 --- a/graphistry/arrow_uploader.py +++ b/graphistry/arrow_uploader.py @@ -393,6 +393,7 @@ def verify(self, token=None) -> bool: verify=self.certificate_validation, json={'token': token}) log_requests_error(out) + return out.text return out.status_code == requests.codes.ok def create_dataset(self, json, validate: bool = True): # noqa: F811 From 36fcfea604c18774ba3bc895e69fa7b6ce5ae169 Mon Sep 17 00:00:00 2001 From: Vaim Dev Date: Sat, 9 Nov 2024 00:14:44 +0800 Subject: [PATCH 19/34] wip (sso): attempt to display error in iframe --- graphistry/PlotterBase.py | 6 +++--- graphistry/util.py | 10 +++++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/graphistry/PlotterBase.py b/graphistry/PlotterBase.py index 8d4913b03c..f242410f55 100644 --- a/graphistry/PlotterBase.py +++ b/graphistry/PlotterBase.py @@ -23,7 +23,7 @@ ) from .util import ( error, hash_pdf, in_ipython, in_databricks, make_iframe, random_string, warn, - cache_coercion, cache_coercion_helper, WeakValueWrapper + cache_coercion, cache_coercion_helper, WeakValueWrapper, make_iframe_srcdoc ) from .bolt_util import ( @@ -1408,8 +1408,8 @@ def plot( if in_ipython() or in_databricks() or PyGraphistry._config["sso_opt_into_type"] == 'display': PyGraphistry.sso_wait_for_token_text_display() if not PyGraphistry.sso_verify_token_display(): - PyGraphistry.sso_wait_for_token_display() - PyGraphistry.refresh() + msg_html = "Invalid token due to login timeout" + extra_html = f"{extra_html} {make_iframe_srcdoc(msg_html)}" else: PyGraphistry.sso_repeat_get_token() diff --git a/graphistry/util.py b/graphistry/util.py index c2c47996f1..e4b2b0a3c2 100644 --- a/graphistry/util.py +++ b/graphistry/util.py @@ -10,7 +10,7 @@ import uuid import warnings from functools import lru_cache -from typing import Any +from typing import Any, Optional from collections import UserDict from .constants import VERBOSE, CACHE_COERCION_SIZE, TRACE @@ -172,8 +172,12 @@ def check_set_memoize( weakref[hashed] = w return False +def make_iframe_srcdoc(srcdoc: str): + srcdoc = 'srcdoc="{srcdoc}" onload="this.removeAttribute(\'srcdoc\')"' + return srcdoc -def make_iframe(url, height, extra_html="", override_html_style=None): + +def make_iframe(url, height, extra_html="", override_html_style=None, srcdoc: Optional[str] = None): id = uuid.uuid4() height_str = ( @@ -203,7 +207,7 @@ def make_iframe(url, height, extra_html="", override_html_style=None): ) iframe = """ -