From c19d78e867995a754bb992ecc950b6b24a0c073b Mon Sep 17 00:00:00 2001 From: Chengbiao Jin Date: Wed, 2 Jul 2025 22:55:48 -0500 Subject: [PATCH 01/10] add function to get schema version --- pyTigerGraph/__init__.py | 2 +- pyTigerGraph/pyTigerGraphSchema.py | 92 ++++++++++++++++++++ pyTigerGraph/pytgasync/pyTigerGraphSchema.py | 92 ++++++++++++++++++++ 3 files changed, 185 insertions(+), 1 deletion(-) diff --git a/pyTigerGraph/__init__.py b/pyTigerGraph/__init__.py index 0a46f960..f916bb34 100644 --- a/pyTigerGraph/__init__.py +++ b/pyTigerGraph/__init__.py @@ -2,6 +2,6 @@ from pyTigerGraph.pytgasync.pyTigerGraph import AsyncTigerGraphConnection from pyTigerGraph.common.exception import TigerGraphException -__version__ = "1.9.0" +__version__ = "1.9.1" __license__ = "Apache 2" diff --git a/pyTigerGraph/pyTigerGraphSchema.py b/pyTigerGraph/pyTigerGraphSchema.py index 1c6e52a0..d56759c7 100644 --- a/pyTigerGraph/pyTigerGraphSchema.py +++ b/pyTigerGraph/pyTigerGraphSchema.py @@ -13,6 +13,7 @@ _prep_upsert_data, _prep_get_endpoints ) +from pyTigerGraph.common.exception import TigerGraphException from pyTigerGraph.pyTigerGraphBase import pyTigerGraphBase logger = logging.getLogger(__name__) @@ -84,6 +85,97 @@ def getSchema(self, udts: bool = True, force: bool = False) -> dict: return self.schema + def getSchemaVer(self) -> int: + """Retrieves the schema version of the graph by running an interpreted query. + + Returns: + The schema version as an integer. + + Endpoint: + - `POST /gsqlserver/interpreted_query` (In TigerGraph versions 3.x) + - `POST /gsql/v1/queries/interpret` (In TigerGraph versions 4.x) + """ + logger.info("entry: getSchemaVer") + if logger.level == logging.DEBUG: + logger.debug("params: " + self._locals(locals())) + + # Create the interpreted query to get schema version + query_text = f'INTERPRET QUERY () FOR GRAPH {self.graphname} {{ PRINT "OK"; }}' + + try: + # Run the interpreted query + result = self.runInterpretedQuery(query_text) + + # Parse the JSON result to extract schema version + if isinstance(result, list) and len(result) > 0: + # Look for version information in the result + for item in result: + if isinstance(item, dict): + # Check if this item contains version information + if "version" in item: + version_info = item["version"] + if isinstance(version_info, dict) and "schema" in version_info: + schema_version = version_info["schema"] + # Convert to integer + try: + schema_version_int = int(schema_version) + if logger.level == logging.DEBUG: + logger.debug("return: " + str(schema_version_int)) + logger.info("exit: getSchemaVer") + return schema_version_int + except (ValueError, TypeError): + logger.warning(f"Schema version '{schema_version}' could not be converted to integer") + return None + # Also check if the item itself contains schema version directly + elif "schema" in item: + schema_version = item["schema"] + try: + schema_version_int = int(schema_version) + if logger.level == logging.DEBUG: + logger.debug("return: " + str(schema_version_int)) + logger.info("exit: getSchemaVer") + return schema_version_int + except (ValueError, TypeError): + logger.warning(f"Schema version '{schema_version}' could not be converted to integer") + return None + elif isinstance(result, dict): + # Handle case where result is a dictionary + if "version" in result: + version_info = result["version"] + if isinstance(version_info, dict) and "schema" in version_info: + schema_version = version_info["schema"] + try: + schema_version_int = int(schema_version) + if logger.level == logging.DEBUG: + logger.debug("return: " + str(schema_version_int)) + logger.info("exit: getSchemaVer") + return schema_version_int + except (ValueError, TypeError): + logger.warning(f"Schema version '{schema_version}' could not be converted to integer") + return None + elif "schema" in result: + schema_version = result["schema"] + try: + schema_version_int = int(schema_version) + if logger.level == logging.DEBUG: + logger.debug("return: " + str(schema_version_int)) + logger.info("exit: getSchemaVer") + return schema_version_int + except (ValueError, TypeError): + logger.warning(f"Schema version '{schema_version}' could not be converted to integer") + return None + + # If schema version not found in the expected format, return a default or raise exception + logger.warning("Schema version not found in query result") + if logger.level == logging.DEBUG: + logger.debug("return: None") + logger.info("exit: getSchemaVer") + return None + + except Exception as e: + logger.error(f"Error getting schema version: {str(e)}") + raise TigerGraphException(f"Failed to get schema version: {str(e)}") + def upsertData(self, data: Union[str, object], atomic: bool = False, ackAll: bool = False, newVertexOnly: bool = False, vertexMustExist: bool = False, updateVertexOnly: bool = False) -> dict: diff --git a/pyTigerGraph/pytgasync/pyTigerGraphSchema.py b/pyTigerGraph/pytgasync/pyTigerGraphSchema.py index 35f2f1f6..da34f9a6 100644 --- a/pyTigerGraph/pytgasync/pyTigerGraphSchema.py +++ b/pyTigerGraph/pytgasync/pyTigerGraphSchema.py @@ -14,6 +14,7 @@ _prep_upsert_data, _prep_get_endpoints ) +from pyTigerGraph.common.exception import TigerGraphException logger = logging.getLogger(__name__) @@ -84,6 +85,97 @@ async def getSchema(self, udts: bool = True, force: bool = False) -> dict: return self.schema + async def getSchemaVer(self) -> int: + """Retrieves the schema version of the graph by running an interpreted query. + + Returns: + The schema version as an integer. + + Endpoint: + - `POST /gsqlserver/interpreted_query` (In TigerGraph versions 3.x) + - `POST /gsql/v1/queries/interpret` (In TigerGraph versions 4.x) + """ + logger.info("entry: getSchemaVer") + if logger.level == logging.DEBUG: + logger.debug("params: " + self._locals(locals())) + + # Create the interpreted query to get schema version + query_text = f'INTERPRET QUERY () FOR GRAPH {self.graphname} {{ PRINT "OK"; }}' + + try: + # Run the interpreted query + result = await self.runInterpretedQuery(query_text) + + # Parse the JSON result to extract schema version + if isinstance(result, list) and len(result) > 0: + # Look for version information in the result + for item in result: + if isinstance(item, dict): + # Check if this item contains version information + if "version" in item: + version_info = item["version"] + if isinstance(version_info, dict) and "schema" in version_info: + schema_version = version_info["schema"] + # Convert to integer + try: + schema_version_int = int(schema_version) + if logger.level == logging.DEBUG: + logger.debug("return: " + str(schema_version_int)) + logger.info("exit: getSchemaVer") + return schema_version_int + except (ValueError, TypeError): + logger.warning(f"Schema version '{schema_version}' could not be converted to integer") + return None + # Also check if the item itself contains schema version directly + elif "schema" in item: + schema_version = item["schema"] + try: + schema_version_int = int(schema_version) + if logger.level == logging.DEBUG: + logger.debug("return: " + str(schema_version_int)) + logger.info("exit: getSchemaVer") + return schema_version_int + except (ValueError, TypeError): + logger.warning(f"Schema version '{schema_version}' could not be converted to integer") + return None + elif isinstance(result, dict): + # Handle case where result is a dictionary + if "version" in result: + version_info = result["version"] + if isinstance(version_info, dict) and "schema" in version_info: + schema_version = version_info["schema"] + try: + schema_version_int = int(schema_version) + if logger.level == logging.DEBUG: + logger.debug("return: " + str(schema_version_int)) + logger.info("exit: getSchemaVer") + return schema_version_int + except (ValueError, TypeError): + logger.warning(f"Schema version '{schema_version}' could not be converted to integer") + return None + elif "schema" in result: + schema_version = result["schema"] + try: + schema_version_int = int(schema_version) + if logger.level == logging.DEBUG: + logger.debug("return: " + str(schema_version_int)) + logger.info("exit: getSchemaVer") + return schema_version_int + except (ValueError, TypeError): + logger.warning(f"Schema version '{schema_version}' could not be converted to integer") + return None + + # If schema version not found in the expected format, return a default or raise exception + logger.warning("Schema version not found in query result") + if logger.level == logging.DEBUG: + logger.debug("return: None") + logger.info("exit: getSchemaVer") + return None + + except Exception as e: + logger.error(f"Error getting schema version: {str(e)}") + raise TigerGraphException(f"Failed to get schema version: {str(e)}") + async def upsertData(self, data: Union[str, object], atomic: bool = False, ackAll: bool = False, newVertexOnly: bool = False, vertexMustExist: bool = False, updateVertexOnly: bool = False) -> dict: From e57c480eacb43fe87532e7e66b468d902223dbd3 Mon Sep 17 00:00:00 2001 From: Chengbiao Jin Date: Tue, 8 Jul 2025 15:41:07 -0700 Subject: [PATCH 02/10] Deprecate AuthMode and make default graph name empty --- pyTigerGraph/common/auth.py | 2 +- pyTigerGraph/common/base.py | 56 +++---- pyTigerGraph/pyTigerGraph.py | 2 +- pyTigerGraph/pyTigerGraphAuth.py | 1 + pyTigerGraph/pyTigerGraphBase.py | 162 +++---------------- pyTigerGraph/pyTigerGraphSchema.py | 2 +- pyTigerGraph/pytgasync/pyTigerGraph.py | 2 +- pyTigerGraph/pytgasync/pyTigerGraphAuth.py | 1 + pyTigerGraph/pytgasync/pyTigerGraphBase.py | 8 +- pyTigerGraph/pytgasync/pyTigerGraphSchema.py | 2 +- 10 files changed, 58 insertions(+), 180 deletions(-) diff --git a/pyTigerGraph/common/auth.py b/pyTigerGraph/common/auth.py index fca1d50c..0b0079ef 100644 --- a/pyTigerGraph/common/auth.py +++ b/pyTigerGraph/common/auth.py @@ -83,7 +83,7 @@ def _prep_token_request(restppUrl: str, else: method = "POST" url = gsUrl + "/gsql/v1/tokens" # used for TG 4.x - data = {"graph": graphname} + data = {"graph": graphname} if graphname else {} # alt_url and alt_data used to construct the method and url for functions run in TG version 3.x alt_url = restppUrl+"/requesttoken" # used for TG 3.x diff --git a/pyTigerGraph/common/base.py b/pyTigerGraph/common/base.py index f90383c4..1dd95578 100644 --- a/pyTigerGraph/common/base.py +++ b/pyTigerGraph/common/base.py @@ -33,7 +33,7 @@ def excepthook(type, value, traceback): class PyTigerGraphCore(object): - def __init__(self, host: str = "http://127.0.0.1", graphname: str = "MyGraph", + def __init__(self, host: str = "http://127.0.0.1", graphname: str = "", gsqlSecret: str = "", username: str = "tigergraph", password: str = "tigergraph", tgCloud: bool = False, restppPort: Union[int, str] = "9000", gsPort: Union[int, str] = "14240", gsqlVersion: str = "", version: str = "", @@ -110,7 +110,8 @@ def __init__(self, host: str = "http://127.0.0.1", graphname: str = "MyGraph", self.base64_credential = base64.b64encode( "{0}:{1}".format(self.username, self.password).encode("utf-8")).decode("utf-8") - self.authHeader = self._set_auth_header() + # Detect auth mode automatically by checking if jwtToken or apiToken is provided + self.authHeader, self.authMode = self._set_auth_header() # TODO Eliminate version and use gsqlVersion only, meaning TigerGraph server version if gsqlVersion: @@ -179,7 +180,7 @@ def __init__(self, host: str = "http://127.0.0.1", graphname: str = "MyGraph", self.restppPort = restppPort self.restppUrl = self.host + ":" + self.restppPort - self.gsPort = "" + self.gsPort = gsPort if self.tgCloud and (gsPort == "14240" or gsPort == "443"): self.gsPort = sslPort self.gsUrl = self.host + ":" + sslPort @@ -216,11 +217,11 @@ def __init__(self, host: str = "http://127.0.0.1", graphname: str = "MyGraph", def _set_auth_header(self): """Set the authentication header based on available tokens or credentials.""" if self.jwtToken: - return {"Authorization": "Bearer " + self.jwtToken} + return {"Authorization": "Bearer " + self.jwtToken}, "token" elif self.apiToken: - return {"Authorization": "Bearer " + self.apiToken} + return {"Authorization": "Bearer " + self.apiToken}, "token" else: - return {"Authorization": "Basic {0}".format(self.base64_credential)} + return {"Authorization": "Basic {0}".format(self.base64_credential)}, "pwd" def _verify_jwt_token_support(self): try: @@ -275,7 +276,7 @@ def _error_check(self, res: dict) -> bool: ) return False - def _prep_req(self, authMode, headers, url, method, data): + def _prep_req(self, headers, url, method, data): logger.info("entry: _req") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -283,31 +284,24 @@ def _prep_req(self, authMode, headers, url, method, data): _headers = {} # If JWT token is provided, always use jwtToken as token - if authMode == "token": - if isinstance(self.jwtToken, str) and self.jwtToken.strip() != "": - token = self.jwtToken - elif isinstance(self.apiToken, tuple): - token = self.apiToken[0] - elif isinstance(self.apiToken, str) and self.apiToken.strip() != "": - token = self.apiToken - else: - token = None + if isinstance(self.jwtToken, str) and self.jwtToken.strip() != "": + token = self.jwtToken + elif isinstance(self.apiToken, tuple): + token = self.apiToken[0] + elif isinstance(self.apiToken, str) and self.apiToken.strip() != "": + token = self.apiToken + else: + token = None - if token: - self.authHeader = {'Authorization': "Bearer " + token} - _headers = self.authHeader - else: - self.authHeader = { - 'Authorization': 'Basic {0}'.format(self.base64_credential)} - _headers = self.authHeader - authMode = 'pwd' - - if authMode == "pwd": - if self.jwtToken: - _headers = {'Authorization': "Bearer " + self.jwtToken} - else: - _headers = {'Authorization': 'Basic {0}'.format( - self.base64_credential)} + if token: + self.authHeader = {'Authorization': "Bearer " + token} + _headers = self.authHeader + self.authMode = "token" + else: + self.authHeader = { + 'Authorization': 'Basic {0}'.format(self.base64_credential)} + _headers = self.authHeader + self.authMode = 'pwd' if headers: _headers.update(headers) diff --git a/pyTigerGraph/pyTigerGraph.py b/pyTigerGraph/pyTigerGraph.py index c6583be7..0da90d9d 100644 --- a/pyTigerGraph/pyTigerGraph.py +++ b/pyTigerGraph/pyTigerGraph.py @@ -26,7 +26,7 @@ class TigerGraphConnection(pyTigerGraphVertex, pyTigerGraphEdge, pyTigerGraphUDT pyTigerGraphLoading, pyTigerGraphPath, pyTigerGraphDataset, object): """Python wrapper for TigerGraph's REST++ and GSQL APIs""" - def __init__(self, host: str = "http://127.0.0.1", graphname: str = "MyGraph", + def __init__(self, host: str = "http://127.0.0.1", graphname: str = "", gsqlSecret: str = "", username: str = "tigergraph", password: str = "tigergraph", tgCloud: bool = False, restppPort: Union[int, str] = "9000", gsPort: Union[int, str] = "14240", gsqlVersion: str = "", version: str = "", diff --git a/pyTigerGraph/pyTigerGraphAuth.py b/pyTigerGraph/pyTigerGraphAuth.py index 3396bec6..fa896f01 100644 --- a/pyTigerGraph/pyTigerGraphAuth.py +++ b/pyTigerGraph/pyTigerGraphAuth.py @@ -239,6 +239,7 @@ def getToken(self, ) self.apiToken = token self.authHeader = auth_header + self.authMode = "token" logger.info("exit: getToken") return token diff --git a/pyTigerGraph/pyTigerGraphBase.py b/pyTigerGraph/pyTigerGraphBase.py index 624c082f..7bcbe3a6 100644 --- a/pyTigerGraph/pyTigerGraphBase.py +++ b/pyTigerGraph/pyTigerGraphBase.py @@ -13,7 +13,7 @@ conn = TigerGraphConnection( host="http://localhost", - graphname="MyGraph", + graphname="your_graph_name", username="tigergraph", password="tigergraph") @@ -64,7 +64,7 @@ def __init__(self, host: str = "http://127.0.0.1", graphname: str = "MyGraph", protocol (http:// or https://). If `certPath` is `None` and the protocol is https, a self-signed certificate will be used. graphname: - The default graph for running queries. + The graph name for running queries. **Required** - must be specified. gsqlSecret: The secret key for GSQL. See https://docs.tigergraph.com/tigergraph-server/current/user-access/managing-credentials#_secrets. username: @@ -102,144 +102,17 @@ def __init__(self, host: str = "http://127.0.0.1", graphname: str = "MyGraph", TigerGraphException: In case on invalid URL scheme. """ - logger.info("entry: __init__") - if logger.level == logging.DEBUG: - logger.debug("params: " + self._locals(locals())) + super().__init__(host=host, graphname=graphname, gsqlSecret=gsqlSecret, + username=username, password=password, tgCloud=tgCloud, + restppPort=restppPort, gsPort=gsPort, gsqlVersion=gsqlVersion, + version=version, apiToken=apiToken, useCert=useCert, certPath=certPath, + debug=debug, sslPort=sslPort, gcp=gcp, jwtToken=jwtToken) - inputHost = urlparse(host) - if inputHost.scheme not in ["http", "https"]: - raise TigerGraphException("Invalid URL scheme. Supported schemes are http and https.", - "E-0003") - self.netloc = inputHost.netloc - self.host = "{0}://{1}".format(inputHost.scheme, self.netloc) - if gsqlSecret != "": - self.username = "__GSQL__secret" - self.password = gsqlSecret - else: - self.username = username - self.password = password - self.graphname = graphname - self.responseConfigHeader = {} - self.awsIamHeaders = {} - - self.jwtToken = jwtToken - self.apiToken = apiToken - self.base64_credential = base64.b64encode( - "{0}:{1}".format(self.username, self.password).encode("utf-8")).decode("utf-8") - - self.authHeader = self._set_auth_header() - - # TODO Eliminate version and use gsqlVersion only, meaning TigerGraph server version - if gsqlVersion: - self.version = gsqlVersion - elif version: + if graphname == "MyGraph": warnings.warn( - "The `version` parameter is deprecated; use the `gsqlVersion` parameter instead.", - DeprecationWarning) - self.version = version - else: - self.version = "" - - if debug is not None: - warnings.warn( - "The `debug` parameter is deprecated; configure standard logging in your app.", - DeprecationWarning) - if not debug: - sys.excepthook = excepthook # TODO Why was this necessary? Can it be removed? - sys.tracebacklimit = None - - self.schema = None - - # TODO Remove useCert parameter - if useCert is not None: - warnings.warn( - "The `useCert` parameter is deprecated; the need for a CA certificate is now determined by URL scheme.", - DeprecationWarning) - if inputHost.scheme == "http": - self.downloadCert = False - self.useCert = False - self.certPath = "" - elif inputHost.scheme == "https": - if not certPath: - self.downloadCert = True - else: - self.downloadCert = False - self.useCert = True - self.certPath = certPath - self.sslPort = str(sslPort) - - # TODO Remove gcp parameter - if gcp: - warnings.warn("The `gcp` parameter is deprecated.", - DeprecationWarning) - self.tgCloud = tgCloud or gcp - if "tgcloud" in self.netloc.lower(): - try: # If get request succeeds, using TG Cloud instance provisioned after 6/20/2022 - self._get(self.host + "/api/ping", resKey="message") - self.tgCloud = True - # If get request fails, using TG Cloud instance provisioned before 6/20/2022, before new firewall config - except requests.exceptions.RequestException: - self.tgCloud = False - except TigerGraphException: - raise (TigerGraphException("Incorrect graphname.")) - - restppPort = str(restppPort) - gsPort = str(gsPort) - sslPort = str(sslPort) - if restppPort == gsPort: - self.restppPort = restppPort - self.restppUrl = self.host + ":" + restppPort + "/restpp" - elif (self.tgCloud and (restppPort == "9000" or restppPort == "443")): - if restppPort == gsPort: - sslPort = gsPort - self.restppPort = sslPort - self.restppUrl = self.host + ":" + sslPort + "/restpp" - else: - self.restppPort = restppPort - self.restppUrl = self.host + ":" + self.restppPort - - self.gsPort = gsPort - if self.tgCloud and (gsPort == "14240" or gsPort == "443"): - self.gsPort = sslPort - self.gsUrl = self.host + ":" + sslPort - else: - self.gsPort = gsPort - self.gsUrl = self.host + ":" + self.gsPort - self.url = "" - - if self.username.startswith("arn:aws:iam::"): - import boto3 - from botocore.awsrequest import AWSRequest - from botocore.auth import SigV4Auth - # Prepare a GetCallerIdentity request. - request = AWSRequest( - method="POST", - url="https://sts.amazonaws.com/?Action=GetCallerIdentity&Version=2011-06-15", - headers={ - 'Host': 'sts.amazonaws.com' - }) - # Get headers - SigV4Auth(boto3.Session().get_credentials(), - "sts", "us-east-1").add_auth(request) - self.awsIamHeaders["X-Amz-Date"] = request.headers["X-Amz-Date"] - self.awsIamHeaders["X-Amz-Security-Token"] = request.headers["X-Amz-Security-Token"] - self.awsIamHeaders["Authorization"] = request.headers["Authorization"] - - if self.jwtToken: - self._verify_jwt_token_support() - - self.asynchronous = False - - logger.info("exit: __init__") - - def _set_auth_header(self): - """Set the authentication header based on available tokens or credentials.""" - if self.jwtToken: - return {"Authorization": "Bearer " + self.jwtToken} - elif self.apiToken: - return {"Authorization": "Bearer " + self.apiToken} - else: - return {"Authorization": "Basic {0}".format(self.base64_credential)} + "The default graphname 'MyGraph' is deprecated. Please explicitly specify your graph name.", + DeprecationWarning + ) def _verify_jwt_token_support(self): try: @@ -305,8 +178,8 @@ def _req(self, method: str, url: str, authMode: str = "token", headers: dict = N Returns: The (relevant part of the) response from the request (as a dictionary). """ - _headers, _data, verify = self._prep_req( - authMode, headers, url, method, data) + # Deprecated: authMode + _headers, _data, verify = self._prep_req(headers, url, method, data) if "GSQL-TIMEOUT" in _headers: http_timeout = (10, int(int(_headers["GSQL-TIMEOUT"])/1000) + 10) @@ -361,6 +234,7 @@ def _req(self, method: str, url: str, authMode: str = "token", headers: dict = N self.restppUrl = newRestppUrl self.restppPort = self.gsPort else: + e.add_note(f"headers: {_headers}") raise e return self._parse_req(res, jsonResponse, strictJson, skipCheck, resKey) @@ -569,3 +443,11 @@ def _version_greater_than_4_0(self) -> bool: if version[0] >= "4" and version[1] > "0": return True return False + + def _validate_graphname(self, operation_name=""): + """Validate that graphname is set for operations that require it.""" + if not self.graphname: + raise TigerGraphException( + f"Graph name is required for {operation_name}. Please specify graphname when creating the connection.", + "E-0004" + ) diff --git a/pyTigerGraph/pyTigerGraphSchema.py b/pyTigerGraph/pyTigerGraphSchema.py index d56759c7..ea188a75 100644 --- a/pyTigerGraph/pyTigerGraphSchema.py +++ b/pyTigerGraph/pyTigerGraphSchema.py @@ -222,7 +222,7 @@ def upsertData(self, data: Union[str, object], atomic: bool = False, ackAll: boo if logger.level == logging.DEBUG: logger.debug("return: " + str(res)) - logger.info("exit: getSchema") + logger.info("exit: upsertData") return res diff --git a/pyTigerGraph/pytgasync/pyTigerGraph.py b/pyTigerGraph/pytgasync/pyTigerGraph.py index 357e775c..1f5a7cd2 100644 --- a/pyTigerGraph/pytgasync/pyTigerGraph.py +++ b/pyTigerGraph/pytgasync/pyTigerGraph.py @@ -26,7 +26,7 @@ class AsyncTigerGraphConnection(AsyncPyTigerGraphVertex, AsyncPyTigerGraphEdge, AsyncPyTigerGraphLoading, AsyncPyTigerGraphPath, AsyncPyTigerGraphDataset, object): """Python wrapper for TigerGraph's REST++ and GSQL APIs""" - def __init__(self, host: str = "http://127.0.0.1", graphname: str = "MyGraph", + def __init__(self, host: str = "http://127.0.0.1", graphname: str = "", gsqlSecret: str = "", username: str = "tigergraph", password: str = "tigergraph", tgCloud: bool = False, restppPort: Union[int, str] = "9000", gsPort: Union[int, str] = "14240", gsqlVersion: str = "", version: str = "", diff --git a/pyTigerGraph/pytgasync/pyTigerGraphAuth.py b/pyTigerGraph/pytgasync/pyTigerGraphAuth.py index 4849b1d7..948fd5ab 100644 --- a/pyTigerGraph/pytgasync/pyTigerGraphAuth.py +++ b/pyTigerGraph/pytgasync/pyTigerGraphAuth.py @@ -192,6 +192,7 @@ async def getToken(self, secret: str = None, setToken: bool = True, lifetime: in self.apiToken = token self.authHeader = auth_header + self.authMode = "token" logger.info("exit: getToken") return token diff --git a/pyTigerGraph/pytgasync/pyTigerGraphBase.py b/pyTigerGraph/pytgasync/pyTigerGraphBase.py index 3da08e2d..9edaf5de 100644 --- a/pyTigerGraph/pytgasync/pyTigerGraphBase.py +++ b/pyTigerGraph/pytgasync/pyTigerGraphBase.py @@ -16,7 +16,7 @@ conn = AsyncTigerGraphConnection( host="http://localhost", - graphname="MyGraph", + graphname="", username="tigergraph", password="tigergraph") @@ -39,7 +39,7 @@ class AsyncPyTigerGraphBase(PyTigerGraphCore): - def __init__(self, host: str = "http://127.0.0.1", graphname: str = "MyGraph", + def __init__(self, host: str = "http://127.0.0.1", graphname: str = "", gsqlSecret: str = "", username: str = "tigergraph", password: str = "tigergraph", tgCloud: bool = False, restppPort: Union[int, str] = "9000", gsPort: Union[int, str] = "14240", gsqlVersion: str = "", version: str = "", @@ -130,8 +130,8 @@ async def _req(self, method: str, url: str, authMode: str = "token", headers: di Returns: The (relevant part of the) response from the request (as a dictionary). """ - _headers, _data, verify = self._prep_req( - authMode, headers, url, method, data) + # Deprecated: authMode + _headers, _data, verify = self._prep_req(headers, url, method, data) if "GSQL-TIMEOUT" in _headers: http_timeout = (10, int(int(_headers["GSQL-TIMEOUT"])/1000) + 10) diff --git a/pyTigerGraph/pytgasync/pyTigerGraphSchema.py b/pyTigerGraph/pytgasync/pyTigerGraphSchema.py index da34f9a6..e1265b75 100644 --- a/pyTigerGraph/pytgasync/pyTigerGraphSchema.py +++ b/pyTigerGraph/pytgasync/pyTigerGraphSchema.py @@ -223,7 +223,7 @@ async def upsertData(self, data: Union[str, object], atomic: bool = False, ackAl if logger.level == logging.DEBUG: logger.debug("return: " + str(res)) - logger.info("exit: getSchema") + logger.info("exit: upsertData") return res From 914686fb321c89a322536f59c9b66a8528a7c9f3 Mon Sep 17 00:00:00 2001 From: Chengbiao Jin Date: Wed, 9 Jul 2025 10:36:42 -0700 Subject: [PATCH 03/10] Revise getSchemaVer() --- pyTigerGraph/pyTigerGraphSchema.py | 88 +++++--------------- pyTigerGraph/pytgasync/pyTigerGraphQuery.py | 2 +- pyTigerGraph/pytgasync/pyTigerGraphSchema.py | 88 +++++--------------- 3 files changed, 41 insertions(+), 137 deletions(-) diff --git a/pyTigerGraph/pyTigerGraphSchema.py b/pyTigerGraph/pyTigerGraphSchema.py index ea188a75..d55496da 100644 --- a/pyTigerGraph/pyTigerGraphSchema.py +++ b/pyTigerGraph/pyTigerGraphSchema.py @@ -104,77 +104,29 @@ def getSchemaVer(self) -> int: try: # Run the interpreted query - result = self.runInterpretedQuery(query_text) - - # Parse the JSON result to extract schema version - if isinstance(result, list) and len(result) > 0: - # Look for version information in the result - for item in result: - if isinstance(item, dict): - # Check if this item contains version information - if "version" in item: - version_info = item["version"] - if isinstance(version_info, dict) and "schema" in version_info: - schema_version = version_info["schema"] - # Convert to integer - try: - schema_version_int = int(schema_version) - if logger.level == logging.DEBUG: - logger.debug("return: " + str(schema_version_int)) - logger.info("exit: getSchemaVer") - return schema_version_int - except (ValueError, TypeError): - logger.warning(f"Schema version '{schema_version}' could not be converted to integer") - return None - # Also check if the item itself contains schema version directly - elif "schema" in item: - schema_version = item["schema"] - try: - schema_version_int = int(schema_version) - if logger.level == logging.DEBUG: - logger.debug("return: " + str(schema_version_int)) - logger.info("exit: getSchemaVer") - return schema_version_int - except (ValueError, TypeError): - logger.warning(f"Schema version '{schema_version}' could not be converted to integer") - return None - elif isinstance(result, dict): - # Handle case where result is a dictionary - if "version" in result: - version_info = result["version"] - if isinstance(version_info, dict) and "schema" in version_info: - schema_version = version_info["schema"] - try: - schema_version_int = int(schema_version) - if logger.level == logging.DEBUG: - logger.debug("return: " + str(schema_version_int)) - logger.info("exit: getSchemaVer") - return schema_version_int - except (ValueError, TypeError): - logger.warning(f"Schema version '{schema_version}' could not be converted to integer") - return None - elif "schema" in result: - schema_version = result["schema"] - try: - schema_version_int = int(schema_version) - if logger.level == logging.DEBUG: - logger.debug("return: " + str(schema_version_int)) - logger.info("exit: getSchemaVer") - return schema_version_int - except (ValueError, TypeError): - logger.warning(f"Schema version '{schema_version}' could not be converted to integer") - return None - - # If schema version not found in the expected format, return a default or raise exception - logger.warning("Schema version not found in query result") - if logger.level == logging.DEBUG: - logger.debug("return: None") - logger.info("exit: getSchemaVer") - return None + if self._version_greater_than_4_0(): + ret = self._req("POST", self.gsUrl + "/gsql/v1/queries/interpret", + params={}, data=query_text, authMode="pwd", resKey="version", + headers={'Content-Type': 'text/plain'}) + else: + ret = self._req("POST", self.gsUrl + "/gsqlserver/interpreted_query", data=query_text, + params={}, authMode="pwd", resKey="version") + + schema_version_int = None + if isinstance(ret, dict) and "schema" in ret: + schema_version = ret["schema"] + try: + schema_version_int = int(schema_version) + except (ValueError, TypeError): + logger.warning(f"Schema version '{schema_version}' could not be converted to integer") + if schema_version_int is None: + logger.warning("Schema version not found in query result") + logger.info("exit: _get_schema_ver") + return schema_version_int except Exception as e: logger.error(f"Error getting schema version: {str(e)}") - raise TigerGraphException(f"Failed to get schema version: {str(e)}") + raise Exception(f"Failed to get schema version: {str(e)}") def upsertData(self, data: Union[str, object], atomic: bool = False, ackAll: bool = False, newVertexOnly: bool = False, vertexMustExist: bool = False, diff --git a/pyTigerGraph/pytgasync/pyTigerGraphQuery.py b/pyTigerGraph/pytgasync/pyTigerGraphQuery.py index ac97d7e1..50d18c3e 100644 --- a/pyTigerGraph/pytgasync/pyTigerGraphQuery.py +++ b/pyTigerGraph/pytgasync/pyTigerGraphQuery.py @@ -4,7 +4,7 @@ All functions in this module are called as methods on a link:https://docs.tigergraph.com/pytigergraph/current/core-functions/base[`TigerGraphConnection` object]. """ import logging -import time +import asyncio from typing import TYPE_CHECKING, Union, Optional diff --git a/pyTigerGraph/pytgasync/pyTigerGraphSchema.py b/pyTigerGraph/pytgasync/pyTigerGraphSchema.py index e1265b75..4966ac99 100644 --- a/pyTigerGraph/pytgasync/pyTigerGraphSchema.py +++ b/pyTigerGraph/pytgasync/pyTigerGraphSchema.py @@ -104,77 +104,29 @@ async def getSchemaVer(self) -> int: try: # Run the interpreted query - result = await self.runInterpretedQuery(query_text) - - # Parse the JSON result to extract schema version - if isinstance(result, list) and len(result) > 0: - # Look for version information in the result - for item in result: - if isinstance(item, dict): - # Check if this item contains version information - if "version" in item: - version_info = item["version"] - if isinstance(version_info, dict) and "schema" in version_info: - schema_version = version_info["schema"] - # Convert to integer - try: - schema_version_int = int(schema_version) - if logger.level == logging.DEBUG: - logger.debug("return: " + str(schema_version_int)) - logger.info("exit: getSchemaVer") - return schema_version_int - except (ValueError, TypeError): - logger.warning(f"Schema version '{schema_version}' could not be converted to integer") - return None - # Also check if the item itself contains schema version directly - elif "schema" in item: - schema_version = item["schema"] - try: - schema_version_int = int(schema_version) - if logger.level == logging.DEBUG: - logger.debug("return: " + str(schema_version_int)) - logger.info("exit: getSchemaVer") - return schema_version_int - except (ValueError, TypeError): - logger.warning(f"Schema version '{schema_version}' could not be converted to integer") - return None - elif isinstance(result, dict): - # Handle case where result is a dictionary - if "version" in result: - version_info = result["version"] - if isinstance(version_info, dict) and "schema" in version_info: - schema_version = version_info["schema"] - try: - schema_version_int = int(schema_version) - if logger.level == logging.DEBUG: - logger.debug("return: " + str(schema_version_int)) - logger.info("exit: getSchemaVer") - return schema_version_int - except (ValueError, TypeError): - logger.warning(f"Schema version '{schema_version}' could not be converted to integer") - return None - elif "schema" in result: - schema_version = result["schema"] - try: - schema_version_int = int(schema_version) - if logger.level == logging.DEBUG: - logger.debug("return: " + str(schema_version_int)) - logger.info("exit: getSchemaVer") - return schema_version_int - except (ValueError, TypeError): - logger.warning(f"Schema version '{schema_version}' could not be converted to integer") - return None - - # If schema version not found in the expected format, return a default or raise exception - logger.warning("Schema version not found in query result") - if logger.level == logging.DEBUG: - logger.debug("return: None") - logger.info("exit: getSchemaVer") - return None + if await self._version_greater_than_4_0(): + ret = await self._req("POST", self.gsUrl + "/gsql/v1/queries/interpret", + params={}, data=query_text, authMode="pwd", resKey="version", + headers={'Content-Type': 'text/plain'}) + else: + ret = await self._req("POST", self.gsUrl + "/gsqlserver/interpreted_query", data=query_text, + params={}, authMode="pwd", resKey="version") + + schema_version_int = None + if isinstance(ret, dict) and "schema" in ret: + schema_version = ret["schema"] + try: + schema_version_int = int(schema_version) + except (ValueError, TypeError): + logger.warning(f"Schema version '{schema_version}' could not be converted to integer") + if schema_version_int is None: + logger.warning("Schema version not found in query result") + logger.info("exit: _get_schema_ver") + return schema_version_int except Exception as e: logger.error(f"Error getting schema version: {str(e)}") - raise TigerGraphException(f"Failed to get schema version: {str(e)}") + raise Exception(f"Failed to get schema version: {str(e)}") async def upsertData(self, data: Union[str, object], atomic: bool = False, ackAll: bool = False, newVertexOnly: bool = False, vertexMustExist: bool = False, From 5768890d3cda3060ff7a4211559aaa75e8f55244 Mon Sep 17 00:00:00 2001 From: James Myatt Date: Mon, 21 Jul 2025 13:46:17 +0100 Subject: [PATCH 04/10] /requesttoken has sightly different response using username-password pair --- pyTigerGraph/common/auth.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pyTigerGraph/common/auth.py b/pyTigerGraph/common/auth.py index fca1d50c..709d1dd1 100644 --- a/pyTigerGraph/common/auth.py +++ b/pyTigerGraph/common/auth.py @@ -113,7 +113,9 @@ def _parse_token_response(response: dict, mainVer: int, base64_credential: str) -> Tuple[Union[Tuple[str, str], str], dict]: if not response.get("error"): - token = response["token"] + # Note that /requesttoken has sightly different response using username-password pair. + # See https://docs.tigergraph.com/tigergraph-server/3.10/api/built-in-endpoints#_request_a_token + token = response.get("results", response)["token"] if setToken: apiToken = token authHeader = {'Authorization': "Bearer " + apiToken} From 14d73d97cfdd37bbb2adaff45a357fab0efd5f5f Mon Sep 17 00:00:00 2001 From: Chengbiao Jin Date: Thu, 16 Oct 2025 15:53:57 -0700 Subject: [PATCH 05/10] Revise default logs to debug level --- pyTigerGraph/common/auth.py | 4 +- pyTigerGraph/common/base.py | 10 +-- pyTigerGraph/common/edge.py | 14 +-- pyTigerGraph/common/gsql.py | 2 +- pyTigerGraph/common/loading.py | 2 +- pyTigerGraph/common/path.py | 12 +-- pyTigerGraph/common/query.py | 11 +-- pyTigerGraph/common/schema.py | 4 +- pyTigerGraph/common/vertex.py | 4 +- pyTigerGraph/pyTigerGraphAuth.py | 24 +++--- pyTigerGraph/pyTigerGraphBase.py | 26 +++--- pyTigerGraph/pyTigerGraphDataset.py | 4 +- pyTigerGraph/pyTigerGraphEdge.py | 86 +++++++++---------- pyTigerGraph/pyTigerGraphGSQL.py | 6 +- pyTigerGraph/pyTigerGraphLoading.py | 58 ++++++------- pyTigerGraph/pyTigerGraphPath.py | 8 +- pyTigerGraph/pyTigerGraphQuery.py | 50 +++++------ pyTigerGraph/pyTigerGraphSchema.py | 20 ++--- pyTigerGraph/pyTigerGraphUDT.py | 10 +-- pyTigerGraph/pyTigerGraphUtils.py | 10 +-- pyTigerGraph/pyTigerGraphVertex.py | 76 ++++++++-------- pyTigerGraph/pytgasync/pyTigerGraphAuth.py | 24 +++--- pyTigerGraph/pytgasync/pyTigerGraphBase.py | 24 +++--- pyTigerGraph/pytgasync/pyTigerGraphDataset.py | 4 +- pyTigerGraph/pytgasync/pyTigerGraphEdge.py | 86 +++++++++---------- pyTigerGraph/pytgasync/pyTigerGraphGSQL.py | 2 +- pyTigerGraph/pytgasync/pyTigerGraphLoading.py | 58 ++++++------- pyTigerGraph/pytgasync/pyTigerGraphPath.py | 8 +- pyTigerGraph/pytgasync/pyTigerGraphQuery.py | 46 +++++----- pyTigerGraph/pytgasync/pyTigerGraphSchema.py | 20 ++--- pyTigerGraph/pytgasync/pyTigerGraphUDT.py | 10 +-- pyTigerGraph/pytgasync/pyTigerGraphUtils.py | 10 +-- pyTigerGraph/pytgasync/pyTigerGraphVertex.py | 76 ++++++++-------- 33 files changed, 405 insertions(+), 404 deletions(-) diff --git a/pyTigerGraph/common/auth.py b/pyTigerGraph/common/auth.py index 0b0079ef..1c5f8379 100644 --- a/pyTigerGraph/common/auth.py +++ b/pyTigerGraph/common/auth.py @@ -40,7 +40,7 @@ def _parse_create_secret(response: str, alias: str = "", withAlias: bool = False if not withAlias: if logger.level == logging.DEBUG: logger.debug("return: " + str(secret)) - logger.info("exit: createSecret (withAlias") + logger.debug("exit: createSecret (withAlias") return secret @@ -49,7 +49,7 @@ def _parse_create_secret(response: str, alias: str = "", withAlias: bool = False if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: createSecret (alias)") + logger.debug("exit: createSecret (alias)") return ret diff --git a/pyTigerGraph/common/base.py b/pyTigerGraph/common/base.py index 1dd95578..6779fbe7 100644 --- a/pyTigerGraph/common/base.py +++ b/pyTigerGraph/common/base.py @@ -85,7 +85,7 @@ def __init__(self, host: str = "http://127.0.0.1", graphname: str = "", TigerGraphException: In case on invalid URL scheme. """ - logger.info("entry: __init__") + logger.debug("entry: __init__") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -212,7 +212,7 @@ def __init__(self, host: str = "http://127.0.0.1", graphname: str = "", self.asynchronous = False - logger.info("exit: __init__") + logger.debug("exit: __init__") def _set_auth_header(self): """Set the authentication header based on available tokens or credentials.""" @@ -277,7 +277,7 @@ def _error_check(self, res: dict) -> bool: return False def _prep_req(self, headers, url, method, data): - logger.info("entry: _req") + logger.debug("entry: _req") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -339,7 +339,7 @@ def _parse_req(self, res, jsonResponse, strictJson, skipCheck, resKey): if not resKey: if logger.level == logging.DEBUG: logger.debug("return: " + str(res)) - logger.info("exit: _req (no resKey)") + logger.debug("exit: _req (no resKey)") return res @@ -348,7 +348,7 @@ def _parse_req(self, res, jsonResponse, strictJson, skipCheck, resKey): logger.info("Removed _ from resKey") if logger.level == logging.DEBUG: logger.debug("return: " + str(res[resKey])) - logger.info("exit: _req (resKey)") + logger.debug("exit: _req (resKey)") return res[resKey] diff --git a/pyTigerGraph/common/edge.py b/pyTigerGraph/common/edge.py index 5cf9c1b5..71e3ec10 100644 --- a/pyTigerGraph/common/edge.py +++ b/pyTigerGraph/common/edge.py @@ -25,7 +25,7 @@ def _parse_get_edge_source_vertex_type(edgeTypeDetails): if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getEdgeSourceVertexType (single source)") + logger.debug("exit: getEdgeSourceVertexType (single source)") return ret @@ -38,7 +38,7 @@ def _parse_get_edge_source_vertex_type(edgeTypeDetails): if logger.level == logging.DEBUG: logger.debug("return: " + str(vts)) - logger.info("exit: getEdgeSourceVertexType (multi source)") + logger.debug("exit: getEdgeSourceVertexType (multi source)") return vts else: @@ -57,7 +57,7 @@ def _parse_get_edge_target_vertex_type(edgeTypeDetails): if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getEdgeTargetVertexType (single target)") + logger.debug("exit: getEdgeTargetVertexType (single target)") return ret @@ -70,7 +70,7 @@ def _parse_get_edge_target_vertex_type(edgeTypeDetails): if logger.level == logging.DEBUG: logger.debug("return: " + str(vts)) - logger.info("exit: getEdgeTargetVertexType (multi target)") + logger.debug("exit: getEdgeTargetVertexType (multi target)") return vts else: @@ -126,7 +126,7 @@ def _parse_get_edge_count_from(res, edgeType): if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getEdgeCountFrom (single edge type)") + logger.debug("exit: getEdgeCountFrom (single edge type)") return ret @@ -447,7 +447,7 @@ def edgeSetToDataFrame(edgeSet: list, ID or source and target vertices, and the edge type. """ - logger.info("entry: edgeSetToDataFrame") + logger.debug("entry: edgeSetToDataFrame") logger.debug("params: " + str(locals())) try: @@ -469,6 +469,6 @@ def edgeSetToDataFrame(edgeSet: list, if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: edgeSetToDataFrame") + logger.debug("exit: edgeSetToDataFrame") return ret diff --git a/pyTigerGraph/common/gsql.py b/pyTigerGraph/common/gsql.py index 6ea67efb..2b179e2e 100644 --- a/pyTigerGraph/common/gsql.py +++ b/pyTigerGraph/common/gsql.py @@ -56,7 +56,7 @@ def clean_res(resp: list) -> str: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: gsql (success)") + logger.debug("exit: gsql (success)") return string_without_ansi diff --git a/pyTigerGraph/common/loading.py b/pyTigerGraph/common/loading.py index f1995ecc..4ca48114 100644 --- a/pyTigerGraph/common/loading.py +++ b/pyTigerGraph/common/loading.py @@ -15,7 +15,7 @@ def _prep_run_loading_job_with_file(filePath): return data except OSError as ose: logger.error(ose.strerror) - logger.info("exit: runLoadingJobWithFile") + logger.debug("exit: runLoadingJobWithFile") return None # TODO Should throw exception instead? diff --git a/pyTigerGraph/common/path.py b/pyTigerGraph/common/path.py index 66a7f145..3ec27313 100644 --- a/pyTigerGraph/common/path.py +++ b/pyTigerGraph/common/path.py @@ -60,7 +60,7 @@ def parse_vertices(vertices: Union[dict, tuple, list]) -> list: Returns: A list of vertices in the format required by the path finding endpoints. """ - logger.info("entry: parseVertices") + logger.debug("entry: parseVertices") logger.debug("params: " + str(locals)) ret = [] @@ -78,7 +78,7 @@ def parse_vertices(vertices: Union[dict, tuple, list]) -> list: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: parseVertices") + logger.debug("exit: parseVertices") return ret @@ -94,7 +94,7 @@ def parse_filters(filters: Union[dict, tuple, list]) -> list: Returns: A list of filters in the format required by the path finding endpoints. """ - logger.info("entry: parseFilters") + logger.debug("entry: parseFilters") logger.debug("params: " + str(locals())) ret = [] @@ -111,11 +111,11 @@ def parse_filters(filters: Union[dict, tuple, list]) -> list: logger.warning("Invalid filter type or value: " + str(f)) logger.debug("return: " + str(ret)) - logger.info("exit: parseFilters") + logger.debug("exit: parseFilters") return ret - logger.info("entry: _preparePathParams") + logger.debug("entry: _preparePathParams") logger.debug("params: " + str(locals())) # Assembling the input payload @@ -136,6 +136,6 @@ def parse_filters(filters: Union[dict, tuple, list]) -> list: ret = json.dumps(data) logger.debug("return: " + str(ret)) - logger.info("exit: _preparePathParams") + logger.debug("exit: _preparePathParams") return ret diff --git a/pyTigerGraph/common/query.py b/pyTigerGraph/common/query.py index d5b0a5a4..6d46dfe7 100644 --- a/pyTigerGraph/common/query.py +++ b/pyTigerGraph/common/query.py @@ -54,7 +54,7 @@ def _parse_query_parameters(params: dict) -> str: "key": [([p_id1, p_id2, ...], "vtype"), ...] I.e. multiple primary IDs of the same vertex type """ - logger.info("entry: _parseQueryParameters") + logger.debug("entry: _parseQueryParameters") logger.debug("params: " + str(params)) ret = "" @@ -73,10 +73,10 @@ def _parse_query_parameters(params: dict) -> str: if isinstance(vv, tuple): if len(vv) == 2 and isinstance(vv[1], str): ret += k + "[" + str(i) + "]=" + _safe_char(vv[0]) + "&" + \ - k + "[" + str(i) + "].type=" + vv[1] + "&" + k + "[" + str(i) + "].type=" + _safe_char(vv[1]) + "&" else: raise TigerGraphException( - "Invalid parameter value: (vertex_primary_id , vertex_type)" + "Invalid parameter value: (vertex_primary_id, vertex_type)" " was expected.") else: ret += k + "=" + _safe_char(vv) + "&" @@ -86,11 +86,12 @@ def _parse_query_parameters(params: dict) -> str: _safe_char(v.strftime("%Y-%m-%d %H:%M:%S")) + "&" else: ret += k + "=" + _safe_char(v) + "&" - ret = ret[:-1] + if not ret: + ret = ret[:-1] if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: _parseQueryParameters") + logger.debug("exit: _parseQueryParameters") return ret diff --git a/pyTigerGraph/common/schema.py b/pyTigerGraph/common/schema.py index 0202a7b9..7537e3ab 100644 --- a/pyTigerGraph/common/schema.py +++ b/pyTigerGraph/common/schema.py @@ -49,7 +49,7 @@ def _upsert_attrs(attributes: dict) -> dict: Documentation: xref:tigergraph-server:API:built-in-endpoints.adoc#operation-codes[Operation codes] """ - logger.info("entry: _upsertAttrs") + logger.debug("entry: _upsertAttrs") logger.debug("params: " + str(locals())) if not isinstance(attributes, dict): @@ -68,7 +68,7 @@ def _upsert_attrs(attributes: dict) -> dict: if logger.level == logging.DEBUG: logger.debug("return: " + str(vals)) - logger.info("exit: _upsertAttrs") + logger.debug("exit: _upsertAttrs") return vals diff --git a/pyTigerGraph/common/vertex.py b/pyTigerGraph/common/vertex.py index 4db34e55..cdbd1f17 100644 --- a/pyTigerGraph/common/vertex.py +++ b/pyTigerGraph/common/vertex.py @@ -191,7 +191,7 @@ def vertexSetToDataFrame(vertexSet: list, withId: bool = True, A pandas DataFrame containing the vertex attributes (and optionally the vertex primary ID and type). """ - logger.info("entry: vertexSetToDataFrame") + logger.debug("entry: vertexSetToDataFrame") logger.debug("params: " + str(locals())) try: @@ -212,6 +212,6 @@ def vertexSetToDataFrame(vertexSet: list, withId: bool = True, if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: vertexSetToDataFrame") + logger.debug("exit: vertexSetToDataFrame") return ret diff --git a/pyTigerGraph/pyTigerGraphAuth.py b/pyTigerGraph/pyTigerGraphAuth.py index fa896f01..27d6a2ce 100644 --- a/pyTigerGraph/pyTigerGraphAuth.py +++ b/pyTigerGraph/pyTigerGraphAuth.py @@ -37,7 +37,7 @@ def getSecrets(self) -> Dict[str, str]: This function returns the masked version of the secret. The original value of the secret cannot be retrieved after creation. """ - logger.info("entry: getSecrets") + logger.debug("entry: getSecrets") res = self.gsql(""" USE GRAPH {} @@ -46,7 +46,7 @@ def getSecrets(self) -> Dict[str, str]: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getSecrets") + logger.debug("exit: getSecrets") return ret @@ -83,7 +83,7 @@ def createSecret(self, alias: str = "", withAlias: bool = False) -> Union[str, D internal processes of granting access to TigerGraph instances. Normally, this function should not be necessary and should not be executable by generic users. """ - logger.info("entry: createSecret") + logger.debug("entry: createSecret") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -104,7 +104,7 @@ def createSecret(self, alias: str = "", withAlias: bool = False) -> Union[str, D if logger.level == logging.DEBUG: logger.debug("return: " + str(secret)) - logger.info("exit: createSecret") + logger.debug("exit: createSecret") return secret @@ -122,7 +122,7 @@ def dropSecret(self, alias: Union[str, list], ignoreErrors: bool = True) -> str: `TigerGraphException` if a non-existent secret is attempted to be dropped (unless `ignoreErrors` is `True`). Re-raises other exceptions. """ - logger.info("entry: dropSecret") + logger.debug("entry: dropSecret") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -139,7 +139,7 @@ def dropSecret(self, alias: Union[str, list], ignoreErrors: bool = True) -> str: if logger.level == logging.DEBUG: logger.debug("return: " + str(res)) - logger.info("exit: dropSecret") + logger.debug("exit: dropSecret") return res @@ -227,7 +227,7 @@ def getToken(self, See https://docs.tigergraph.com/tigergraph-server/current/api/built-in-endpoints#_request_a_token - `POST /gsql/v1/tokens` (In TigerGraph versions 4.x) """ - logger.info("entry: getToken") + logger.debug("entry: getToken") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -241,7 +241,7 @@ def getToken(self, self.authHeader = auth_header self.authMode = "token" - logger.info("exit: getToken") + logger.debug("exit: getToken") return token def refreshToken(self, secret: str = None, setToken: bool = True, lifetime: int = None, token: str = None) -> Union[Tuple[str, str], str]: @@ -283,12 +283,12 @@ def refreshToken(self, secret: str = None, setToken: bool = True, lifetime: int - `PUT /requesttoken` See https://docs.tigergraph.com/tigergraph-server/current/api/built-in-endpoints#_refresh_a_token """ - logger.info("entry: refreshToken") + logger.debug("entry: refreshToken") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) if self._version_greater_than_4_0(): - logger.info("exit: refreshToken") + logger.debug("exit: refreshToken") raise TigerGraphException( "Refreshing tokens is only supported on versions of TigerGraph <= 4.0.0.", 0) @@ -298,7 +298,7 @@ def refreshToken(self, secret: str = None, setToken: bool = True, lifetime: int newToken = _parse_token_response(res, setToken, mainVer, self.base64_credential) - logger.info("exit: refreshToken") + logger.debug("exit: refreshToken") return newToken @@ -339,7 +339,7 @@ def deleteToken(self, secret: str, token: str = None, skipNA: bool = False) -> b if not res["error"] or (res["code"] == "REST-3300" and skipNA): if logger.level == logging.DEBUG: logger.debug("return: " + str(True)) - logger.info("exit: deleteToken") + logger.debug("exit: deleteToken") return True diff --git a/pyTigerGraph/pyTigerGraphBase.py b/pyTigerGraph/pyTigerGraphBase.py index 7bcbe3a6..c75ab4a6 100644 --- a/pyTigerGraph/pyTigerGraphBase.py +++ b/pyTigerGraph/pyTigerGraphBase.py @@ -144,7 +144,7 @@ def _locals(self, _locals: dict) -> str: del _locals["self"] return str(_locals) - logger.info("exit: __init__") + logger.debug("exit: __init__") def _req(self, method: str, url: str, authMode: str = "token", headers: dict = None, data: Union[dict, list, str] = None, resKey: str = "results", skipCheck: bool = False, @@ -261,7 +261,7 @@ def _get(self, url: str, authMode: str = "token", headers: dict = None, resKey: Returns: The (relevant part of the) response from the request (as a dictionary). """ - logger.info("entry: _get") + logger.debug("entry: _get") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -270,7 +270,7 @@ def _get(self, url: str, authMode: str = "token", headers: dict = None, resKey: if logger.level == logging.DEBUG: logger.debug("return: " + str(res)) - logger.info("exit: _get") + logger.debug("exit: _get") return res @@ -299,7 +299,7 @@ def _post(self, url: str, authMode: str = "token", headers: dict = None, Returns: The (relevant part of the) response from the request (as a dictionary). """ - logger.info("entry: _post") + logger.debug("entry: _post") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -308,7 +308,7 @@ def _post(self, url: str, authMode: str = "token", headers: dict = None, if logger.level == logging.DEBUG: logger.debug("return: " + str(res)) - logger.info("exit: _post") + logger.debug("exit: _post") return res @@ -324,7 +324,7 @@ def _put(self, url: str, authMode: str = "token", data=None, resKey=None, jsonDa Returns: The response from the request (as a dictionary). """ - logger.info("entry: _put") + logger.debug("entry: _put") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -333,7 +333,7 @@ def _put(self, url: str, authMode: str = "token", data=None, resKey=None, jsonDa if logger.level == logging.DEBUG: logger.debug("return: " + str(res)) - logger.info("exit: _put") + logger.debug("exit: _put") return res @@ -349,7 +349,7 @@ def _delete(self, url: str, authMode: str = "token", data: dict = None, resKey=" Returns: The response from the request (as a dictionary). """ - logger.info("entry: _delete") + logger.debug("entry: _delete") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -358,7 +358,7 @@ def _delete(self, url: str, authMode: str = "token", data: dict = None, resKey=" if logger.level == logging.DEBUG: logger.debug("return: " + str(res)) - logger.info("exit: _delete") + logger.debug("exit: _delete") return res @@ -378,7 +378,7 @@ def getVersion(self, raw: bool = False) -> Union[str, list]: - `GET /version` See xref:tigergraph-server:API:built-in-endpoints.adoc#_show_component_versions[Show component versions] """ - logger.info("entry: getVersion") + logger.debug("entry: getVersion") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) response = self._get(self.restppUrl+"/version", @@ -387,7 +387,7 @@ def getVersion(self, raw: bool = False) -> Union[str, list]: if logger.level == logging.DEBUG: logger.debug("return: " + str(components)) - logger.info("exit: getVersion") + logger.debug("exit: getVersion") return components def getVer(self, component: str = "product", full: bool = False) -> str: @@ -407,7 +407,7 @@ def getVer(self, component: str = "product", full: bool = False) -> str: Raises: `TigerGraphException` if invalid/non-existent component is specified. """ - logger.info("entry: getVer") + logger.debug("entry: getVer") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) version = self.getVersion() @@ -415,7 +415,7 @@ def getVer(self, component: str = "product", full: bool = False) -> str: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getVer") + logger.debug("exit: getVer") return ret diff --git a/pyTigerGraph/pyTigerGraphDataset.py b/pyTigerGraph/pyTigerGraphDataset.py index 3fffb765..7400f134 100644 --- a/pyTigerGraph/pyTigerGraphDataset.py +++ b/pyTigerGraph/pyTigerGraphDataset.py @@ -31,7 +31,7 @@ def ingestDataset( Whether or not to get auth token from the database. This is required when auth token is enabled for the database. Defaults to False. """ - logger.info("entry: ingestDataset") + logger.debug("entry: ingestDataset") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -83,7 +83,7 @@ def ingestDataset( _parse_ingest_dataset(responses, cleanup, dataset) print("---- Finished ingestion ----", flush=True) - logger.info("exit: ingestDataset") + logger.debug("exit: ingestDataset") def check_exist_graphs(self, name: str) -> bool: "NO DOC" diff --git a/pyTigerGraph/pyTigerGraphEdge.py b/pyTigerGraph/pyTigerGraphEdge.py index 7296191e..be5b3039 100644 --- a/pyTigerGraph/pyTigerGraphEdge.py +++ b/pyTigerGraph/pyTigerGraphEdge.py @@ -55,7 +55,7 @@ def getEdgeTypes(self, force: bool = False) -> list: Returns: The list of edge types defined in the current graph. """ - logger.info("entry: getEdgeTypes") + logger.debug("entry: getEdgeTypes") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -65,7 +65,7 @@ def getEdgeTypes(self, force: bool = False) -> list: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getEdgeTypes") + logger.debug("exit: getEdgeTypes") return ret @@ -82,7 +82,7 @@ def getEdgeType(self, edgeType: str, force: bool = False) -> dict: Returns: The metadata of the edge type. """ - logger.info("entry: getEdgeType") + logger.debug("entry: getEdgeType") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -90,12 +90,12 @@ def getEdgeType(self, edgeType: str, force: bool = False) -> dict: if et["Name"] == edgeType: if logger.level == logging.DEBUG: logger.debug("return: " + str(et)) - logger.info("exit: getEdgeType (found)") + logger.debug("exit: getEdgeType (found)") return et logger.warning("Edge type `" + edgeType + "` was not found.") - logger.info("exit: getEdgeType (not found)") + logger.debug("exit: getEdgeType (not found)") return {} @@ -114,7 +114,7 @@ def getEdgeAttrs(self, edgeType: str) -> list: - "map_type(key_type,value_type)" and it is a string. """ - logger.info("entry: getAttributes") + logger.debug("entry: getAttributes") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -127,7 +127,7 @@ def getEdgeAttrs(self, edgeType: str) -> list: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getAttributes") + logger.debug("exit: getAttributes") return ret @@ -155,7 +155,7 @@ def getEdgeSourceVertexType(self, edgeType: str) -> Union[str, set]: at the individual source/target pairs to find out which combinations are valid/defined. """ - logger.info("entry: getEdgeSourceVertexType") + logger.debug("entry: getEdgeSourceVertexType") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -186,7 +186,7 @@ def getEdgeTargetVertexType(self, edgeType: str) -> Union[str, set]: edge is defined between all source and all target vertex types. You need to look at the individual source/target pairs to find out which combinations are valid/defined. """ - logger.info("entry: getEdgeTargetVertexType") + logger.debug("entry: getEdgeTargetVertexType") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -204,7 +204,7 @@ def isDirected(self, edgeType: str) -> bool: Returns: `True`, if the edge is directed. """ - logger.info("entry: isDirected") + logger.debug("entry: isDirected") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -212,7 +212,7 @@ def isDirected(self, edgeType: str) -> bool: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: isDirected") + logger.debug("exit: isDirected") return ret @@ -226,13 +226,13 @@ def getReverseEdge(self, edgeType: str) -> str: Returns: The name of the reverse edge, if it was defined. """ - logger.info("entry: getReverseEdge") + logger.debug("entry: getReverseEdge") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) if not self.isDirected(edgeType): logger.error(edgeType + " is not a directed edge") - logger.info("exit: getReverseEdge (not directed)") + logger.debug("exit: getReverseEdge (not directed)") return "" @@ -242,11 +242,11 @@ def getReverseEdge(self, edgeType: str) -> str: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getReverseEdge (reverse edge found)") + logger.debug("exit: getReverseEdge (reverse edge found)") return ret - logger.info("exit: getReverseEdge (reverse edge not found)") + logger.debug("exit: getReverseEdge (reverse edge not found)") return "" # TODO Should return some other value or raise exception? @@ -261,7 +261,7 @@ def isMultiEdge(self, edgeType: str) -> bool: Returns: `True`, if the edge can have multiple instances between the same pair of vertices. """ - logger.info("entry: isMultiEdge") + logger.debug("entry: isMultiEdge") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -270,7 +270,7 @@ def isMultiEdge(self, edgeType: str) -> bool: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: isMultiEdge") + logger.debug("exit: isMultiEdge") return ret @@ -284,7 +284,7 @@ def getDiscriminators(self, edgeType: str) -> list: Returns: A list of (attribute_name, attribute_type) tuples. """ - logger.info("entry: getDiscriminators") + logger.debug("entry: getDiscriminators") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -298,7 +298,7 @@ def getDiscriminators(self, edgeType: str) -> list: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getDiscriminators") + logger.debug("exit: getDiscriminators") return ret @@ -348,7 +348,7 @@ def getEdgeCountFrom(self, sourceVertexType: str = "", sourceVertexId: Union[str #_run_built_in_functions_on_graph See https://docs.tigergraph.com/tigergraph-server/current/api/built-in-endpoints """ - logger.info("entry: getEdgeCountFrom") + logger.debug("entry: getEdgeCountFrom") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -368,7 +368,7 @@ def getEdgeCountFrom(self, sourceVertexType: str = "", sourceVertexId: Union[str if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getEdgeCountFrom (multiple edge types)") + logger.debug("exit: getEdgeCountFrom (multiple edge types)") return ret @@ -391,7 +391,7 @@ def getEdgeCount(self, edgeType: str = "*", sourceVertexType: str = "", Returns: A dictionary of `edge_type: edge_count` pairs. """ - logger.info("entry: getEdgeCount") + logger.debug("entry: getEdgeCount") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -400,7 +400,7 @@ def getEdgeCount(self, edgeType: str = "*", sourceVertexType: str = "", if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getEdgeCount") + logger.debug("exit: getEdgeCount") return ret @@ -449,7 +449,7 @@ def upsertEdge(self, sourceVertexType: str, sourceVertexId: str, edgeType: str, TODO Add ack, new_vertex_only, vertex_must_exist, update_vertex_only and atomic_level parameters and functionality. """ - logger.info("entry: upsertEdge") + logger.debug("entry: upsertEdge") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -488,7 +488,7 @@ def upsertEdge(self, sourceVertexType: str, sourceVertexId: str, edgeType: str, if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: upsertEdge") + logger.debug("exit: upsertEdge") return ret @@ -540,7 +540,7 @@ def upsertEdges(self, sourceVertexType: str, edgeType: str, targetVertexType: st parameters and functionality. """ - logger.info("entry: upsertEdges") + logger.debug("entry: upsertEdges") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -603,7 +603,7 @@ def upsertEdges(self, sourceVertexType: str, edgeType: str, targetVertexType: st if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: upsertEdges") + logger.debug("exit: upsertEdges") return ret @@ -642,7 +642,7 @@ def upsertEdgeDataFrame(self, df: 'pd.DataFrame', sourceVertexType: str, edgeTyp Returns: The number of edges upserted. """ - logger.info("entry: upsertEdgeDataFrame") + logger.debug("entry: upsertEdgeDataFrame") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -675,7 +675,7 @@ def upsertEdgeDataFrame(self, df: 'pd.DataFrame', sourceVertexType: str, edgeTyp if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: upsertEdgeDataFrame") + logger.debug("exit: upsertEdgeDataFrame") return ret @@ -730,7 +730,7 @@ def getEdges(self, sourceVertexType: str, sourceVertexId: str, edgeType: str = " - `GET /graph/{graph_name}/edges/{source_vertex_type}/{source_vertex_id}` See https://docs.tigergraph.com/dev/restpp-api/built-in-endpoints#list-edges-of-a-vertex """ - logger.info("entry: getEdges") + logger.debug("entry: getEdges") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -757,7 +757,7 @@ def getEdges(self, sourceVertexType: str, sourceVertexId: str, edgeType: str = " if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getEdges") + logger.debug("exit: getEdges") return ret @@ -798,7 +798,7 @@ def getEdgesDataFrame(self, sourceVertexType: str, sourceVertexId: str, edgeType The (selected) details of the (matching) edge instances (sorted, limited) as dictionary, JSON or pandas DataFrame. """ - logger.info("entry: getEdgesDataFrame") + logger.debug("entry: getEdgesDataFrame") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -807,7 +807,7 @@ def getEdgesDataFrame(self, sourceVertexType: str, sourceVertexId: str, edgeType if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getEdgesDataFrame") + logger.debug("exit: getEdgesDataFrame") return ret @@ -850,13 +850,13 @@ def getEdgesByType(self, edgeType: str, fmt: str = "py", withId: bool = True, The details of the edge instances of the given edge type as dictionary, JSON or pandas DataFrame. """ - logger.info("entry: getEdgesByType") + logger.debug("entry: getEdgesByType") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) if not edgeType: logger.warning("Edge type is not specified") - logger.info("exit: getEdgesByType") + logger.debug("exit: getEdgesByType") return {} @@ -875,7 +875,7 @@ def getEdgesByType(self, edgeType: str, fmt: str = "py", withId: bool = True, if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: _upsertAttrs") + logger.debug("exit: _upsertAttrs") return ret @@ -898,7 +898,7 @@ def getEdgeStats(self, edgeTypes: Union[str, list], skipNA: bool = False) -> dic - `POST /builtins/{graph_name}` See https://docs.tigergraph.com/dev/restpp-api/built-in-endpoints#run-built-in-functions-on-graph """ - logger.info("entry: getEdgeStats") + logger.debug("entry: getEdgeStats") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -911,7 +911,7 @@ def getEdgeStats(self, edgeTypes: Union[str, list], skipNA: bool = False) -> dic ets = edgeTypes else: logger.warning("The `edgeTypes` parameter is invalid.") - logger.info("exit: getEdgeStats") + logger.debug("exit: getEdgeStats") return {} @@ -926,7 +926,7 @@ def getEdgeStats(self, edgeTypes: Union[str, list], skipNA: bool = False) -> dic if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getEdgeStats") + logger.debug("exit: getEdgeStats") return ret @@ -967,7 +967,7 @@ def delEdges(self, sourceVertexType: str, sourceVertexId: str, edgeType: str = " - `DELETE /graph/{graph_name}/edges/{source_vertex_type}/{source_vertex_id}/{edge_type}/{target_vertex_type}/{target_vertex_id}` See https://docs.tigergraph.com/dev/restpp-api/built-in-endpoints#delete-an-edge """ - logger.info("entry: delEdges") + logger.debug("entry: delEdges") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -989,7 +989,7 @@ def delEdges(self, sourceVertexType: str, sourceVertexId: str, edgeType: str = " if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: delEdges") + logger.debug("exit: delEdges") return ret @@ -1007,7 +1007,7 @@ def edgeSetToDataFrame(self, edgeSet: list, withId: bool = True, withType: bool Returns: The edge set as a pandas DataFrame. """ - logger.info("entry: edgeSetToDataFrame") + logger.debug("entry: edgeSetToDataFrame") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -1015,6 +1015,6 @@ def edgeSetToDataFrame(self, edgeSet: list, withId: bool = True, withType: bool if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: edgeSetToDataFrame") + logger.debug("exit: edgeSetToDataFrame") return ret \ No newline at end of file diff --git a/pyTigerGraph/pyTigerGraphGSQL.py b/pyTigerGraph/pyTigerGraphGSQL.py index 9ff67bd9..ac4c60f2 100644 --- a/pyTigerGraph/pyTigerGraphGSQL.py +++ b/pyTigerGraph/pyTigerGraphGSQL.py @@ -83,7 +83,7 @@ def installUDF(self, ExprFunctions: str = "", ExprUtil: str = "") -> None: Endpoints: - `PUT /gsqlserver/gsql/userdefinedfunction?filename={ExprFunctions or ExprUtil}"` (In TigerGraph versions 3.x) """ - logger.info("entry: installUDF") + logger.debug("entry: installUDF") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -136,7 +136,7 @@ def installUDF(self, ExprFunctions: str = "", ExprUtil: str = "") -> None: if logger.level == logging.DEBUG: logger.debug("return: 0") - logger.info("exit: installUDF") + logger.debug("exit: installUDF") return 0 @@ -161,7 +161,7 @@ def getUDF(self, ExprFunctions: bool = True, ExprUtil: bool = True, json_out=Fal - `GET /gsqlserver/gsql/userdefinedfunction?filename={ExprFunctions or ExprUtil}` (In TigerGraph versions 3.x) - `GET /gsql/v1/udt/files/{ExprFunctions or ExprUtil}` (In TigerGraph versions 4.x) """ - logger.info("entry: getUDF") + logger.debug("entry: getUDF") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) diff --git a/pyTigerGraph/pyTigerGraphLoading.py b/pyTigerGraph/pyTigerGraphLoading.py index 49edb355..bac12b1f 100644 --- a/pyTigerGraph/pyTigerGraphLoading.py +++ b/pyTigerGraph/pyTigerGraphLoading.py @@ -63,7 +63,7 @@ def runLoadingJobWithDataFrame(self, df: 'pd.DataFrame', fileTag: str, jobName: - `POST /ddl/{graph_name}` See xref:tigergraph-server:API:built-in-endpoints.adoc#_run_a_loading_job[Run a loading job] """ - logger.info("entry: runLoadingJobWithDataFrame") + logger.debug("entry: runLoadingJobWithDataFrame") logger.debug("params: " + self._locals(locals())) @@ -74,7 +74,7 @@ def runLoadingJobWithDataFrame(self, df: 'pd.DataFrame', fileTag: str, jobName: res = self.runLoadingJobWithData(data, fileTag, jobName, sep, eol, timeout, sizeLimit) - logger.info("exit: runLoadingJobWithDataFrame") + logger.debug("exit: runLoadingJobWithDataFrame") return res @@ -110,14 +110,14 @@ def runLoadingJobWithFile(self, filePath: str, fileTag: str, jobName: str, sep: - `POST /ddl/{graph_name}` See xref:tigergraph-server:API:built-in-endpoints.adoc#_run_a_loading_job[Run a loading job] """ - logger.info("entry: runLoadingJobWithFile") + logger.debug("entry: runLoadingJobWithFile") logger.debug("params: " + self._locals(locals())) data = _prep_run_loading_job_with_file(filePath) res = self.runLoadingJobWithData(data, fileTag, jobName, sep, eol, timeout, sizeLimit) - logger.info("exit: runLoadingJobWithFile") + logger.debug("exit: runLoadingJobWithFile") return res @@ -153,14 +153,14 @@ def runLoadingJobWithData(self, data: str, fileTag: str, jobName: str, sep: str - `POST /ddl/{graph_name}` See xref:tigergraph-server:API:built-in-endpoints.adoc#_run_a_loading_job[Run a loading job] """ - logger.info("entry: runLoadingJobWithData") + logger.debug("entry: runLoadingJobWithData") logger.debug("params: " + self._locals(locals())) if not data or not jobName or not fileTag: # invalid inputs logger.error("Invalid data or params") - logger.info("exit: runLoadingJobWithData") + logger.debug("exit: runLoadingJobWithData") return None params = { @@ -181,7 +181,7 @@ def runLoadingJobWithData(self, data: str, fileTag: str, jobName: str, sep: str headers={"RESPONSE-LIMIT": str(sizeLimit), "GSQL-TIMEOUT": str(timeout)}) logger.debug("return: " + str(res)) - logger.info("exit: runLoadingJobWithData") + logger.debug("exit: runLoadingJobWithData") return res @@ -206,7 +206,7 @@ def getLoadingJobs(self) -> dict: - `GET /gsql/v1/loading-jobs?graph=` See xref:tigergraph-server:API:gsql-endpoints.adoc#_get_loading_job_names[Get loading jobs] """ - logger.info("entry: getLoadingJobs") + logger.debug("entry: getLoadingJobs") logger.debug("params: " + self._locals(locals())) @@ -215,7 +215,7 @@ def getLoadingJobs(self) -> dict: res = self._req("GET", url) logger.debug("return: " + str(res)) - logger.info("exit: getLoadingJobs") + logger.debug("exit: getLoadingJobs") return res @@ -230,7 +230,7 @@ def createLoadingJob(self, job_definition: str) -> dict: - `POST /gsql/v1/loading-jobs?graph=` See xref:tigergraph-server:API:gsql-endpoints.adoc#_create_loading_job[Create a loading job] """ - logger.info("entry: createLoadingJob") + logger.debug("entry: createLoadingJob") logger.debug("params: " + self._locals(locals())) @@ -239,7 +239,7 @@ def createLoadingJob(self, job_definition: str) -> dict: res = self._req("POST", url, data=job_definition) logger.debug("return: " + str(res)) - logger.info("exit: createLoadingJob") + logger.debug("exit: createLoadingJob") return res @@ -254,7 +254,7 @@ def updateLoadingJob(self, job_definition: str) -> dict: - `PUT /gsql/v1/loading-jobs/?graph=` See xref:tigergraph-server:API:gsql-endpoints.adoc#_upload_a_loading_job[Upload a loading job] """ - logger.info("entry: updateLoadingJob") + logger.debug("entry: updateLoadingJob") logger.debug("params: " + self._locals(locals())) @@ -263,7 +263,7 @@ def updateLoadingJob(self, job_definition: str) -> dict: res = self._req("PUT", url, data=job_definition) logger.debug("return: " + str(res)) - logger.info("exit: updateLoadingJob") + logger.debug("exit: updateLoadingJob") return res @@ -280,7 +280,7 @@ def getLoadingJobInfo(self, jobName: str, verbose: bool = False) -> dict: - `GET /gsql/v1/loading-jobs/?graph=` See xref:tigergraph-server:API:gsql-endpoints.adoc#_get_loading_job_info[Get loading job info] """ - logger.info("entry: getLoadingJobInfo") + logger.debug("entry: getLoadingJobInfo") logger.debug("params: " + self._locals(locals())) @@ -289,7 +289,7 @@ def getLoadingJobInfo(self, jobName: str, verbose: bool = False) -> dict: res = self._req("GET", url) logger.debug("return: " + str(res)) - logger.info("exit: getLoadingJobInfo") + logger.debug("exit: getLoadingJobInfo") return res @@ -320,7 +320,7 @@ def runLoadingJob(self, jobName: str, data_source_config: dict, sys_data_root: s - `POST /gsql/v1/loading-jobs/run?graph=` See xref:tigergraph-server:API:gsql-endpoints.adoc#_run_loading_job[Run a loading job] """ - logger.info("entry: runLoadingJob") + logger.debug("entry: runLoadingJob") logger.debug("params: " + self._locals(locals())) url, data = _prep_run_loading_job(self.gsUrl, self.graphname, jobName, data_source_config, sys_data_root, verbose, dryrun, interval, maxNumError, maxPercentError) @@ -328,7 +328,7 @@ def runLoadingJob(self, jobName: str, data_source_config: dict, sys_data_root: s res = self._req("POST", url, data=data) logger.debug("return: " + str(res)) - logger.info("exit: runLoadingJob") + logger.debug("exit: runLoadingJob") return res @@ -343,7 +343,7 @@ def dropLoadingJob(self, jobName: str) -> dict: - `DELETE /gsql/v1/loading-jobs/?graph=` See xref:tigergraph-server:API:gsql-endpoints.adoc#_drop_a_loading_job[Drop a loading job] """ - logger.info("entry: dropLoadingJob") + logger.debug("entry: dropLoadingJob") logger.debug("params: " + self._locals(locals())) @@ -352,7 +352,7 @@ def dropLoadingJob(self, jobName: str) -> dict: res = self._req("DELETE", url) logger.debug("return: " + str(res)) - logger.info("exit: dropLoadingJob") + logger.debug("exit: dropLoadingJob") return res @@ -369,7 +369,7 @@ def abortLoadingJobs(self, jobIds: list[str], pauseJob: bool = False) -> dict: - `POST /gsql/v1/loading-jobs/abort?graph=` See xref:tigergraph-server:API:gsql-endpoints.adoc#_abort_loading_jobs[Abort loading jobs] """ - logger.info("entry: abortLoadingJobs") + logger.debug("entry: abortLoadingJobs") logger.debug("params: " + self._locals(locals())) @@ -378,7 +378,7 @@ def abortLoadingJobs(self, jobIds: list[str], pauseJob: bool = False) -> dict: res = self._req("GET", url) logger.debug("return: " + str(res)) - logger.info("exit: abortLoadingJobs") + logger.debug("exit: abortLoadingJobs") return res @@ -395,7 +395,7 @@ def abortLoadingJob(self, jobId: str, pauseJob: bool = False) -> dict: - `POST /gsql/v1/loading-jobs/abort?graph=` See xref:tigergraph-server:API:gsql-endpoints.adoc#_abort_one_loading_job """ - logger.info("entry: abortLoadingJob") + logger.debug("entry: abortLoadingJob") logger.debug("params: " + self._locals(locals())) @@ -404,7 +404,7 @@ def abortLoadingJob(self, jobId: str, pauseJob: bool = False) -> dict: res = self._req("GET", url) logger.debug("return: " + str(res)) - logger.info("exit: abortLoadingJob") + logger.debug("exit: abortLoadingJob") return res @@ -419,7 +419,7 @@ def resumeLoadingJob(self, jobId: str) -> dict: - `POST /gsql/v1/loading-jobs/resume?graph=` See xref:tigergraph-server:API:gsql-endpoints.adoc#_resume_loading_job """ - logger.info("entry: resumeLoadingJob") + logger.debug("entry: resumeLoadingJob") logger.debug("params: " + self._locals(locals())) @@ -428,7 +428,7 @@ def resumeLoadingJob(self, jobId: str) -> dict: res = self._req("GET", url) logger.debug("return: " + str(res)) - logger.info("exit: resumeLoadingJob") + logger.debug("exit: resumeLoadingJob") return res @@ -443,7 +443,7 @@ def getLoadingJobsStatus(self, jobIds: list[str]) -> dict: - `GET /gsql/v1/loading-jobs/status?graph=` See xref:tigergraph-server:API:gsql-endpoints.adoc#_get_loading_job_status[Get loading job status] """ - logger.info("entry: getLoadingJobsStatus") + logger.debug("entry: getLoadingJobsStatus") logger.debug("params: " + self._locals(locals())) @@ -452,7 +452,7 @@ def getLoadingJobsStatus(self, jobIds: list[str]) -> dict: res = self._req("GET", url) logger.debug("return: " + str(res)) - logger.info("exit: getLoadingJobsStatus") + logger.debug("exit: getLoadingJobsStatus") return res @@ -467,7 +467,7 @@ def getLoadingJobStatus(self, jobId: str) -> dict: - `GET /gsql/v1/loading-jobs/status/?graph=` See xref:tigergraph-server:API:gsql-endpoints.adoc#_get_one_loading_job_status[Get one loading job status] """ - logger.info("entry: getLoadingJobStatus") + logger.debug("entry: getLoadingJobStatus") logger.debug("params: " + self._locals(locals())) @@ -476,6 +476,6 @@ def getLoadingJobStatus(self, jobId: str) -> dict: res = self._req("GET", url) logger.debug("return: " + str(res)) - logger.info("exit: getLoadingJobStatus") + logger.debug("exit: getLoadingJobStatus") return res \ No newline at end of file diff --git a/pyTigerGraph/pyTigerGraphPath.py b/pyTigerGraph/pyTigerGraphPath.py index 4df70713..5ed7d17d 100644 --- a/pyTigerGraph/pyTigerGraphPath.py +++ b/pyTigerGraph/pyTigerGraphPath.py @@ -66,7 +66,7 @@ def shortestPath(self, sourceVertices: Union[dict, tuple, list], - `POST /shortestpath/{graphName}` See xref:tigergraph-server:API:built-in-endpoints.adoc#_find_shortest_path[Find the shortest path]. """ - logger.info("entry: shortestPath") + logger.debug("entry: shortestPath") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -77,7 +77,7 @@ def shortestPath(self, sourceVertices: Union[dict, tuple, list], if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: shortestPath") + logger.debug("exit: shortestPath") return ret @@ -122,7 +122,7 @@ def allPaths(self, sourceVertices: Union[dict, tuple, list], - `POST /allpaths/{graphName}` See xref:tigergraph-server:API:built-in-endpoints.adoc#_find_all_paths[Find all paths] """ - logger.info("entry: allPaths") + logger.debug("entry: allPaths") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -133,6 +133,6 @@ def allPaths(self, sourceVertices: Union[dict, tuple, list], if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: allPaths") + logger.debug("exit: allPaths") return ret diff --git a/pyTigerGraph/pyTigerGraphQuery.py b/pyTigerGraph/pyTigerGraphQuery.py index 947bfaff..d0047621 100644 --- a/pyTigerGraph/pyTigerGraphQuery.py +++ b/pyTigerGraph/pyTigerGraphQuery.py @@ -89,7 +89,7 @@ def getInstalledQueries(self, fmt: str = "py") -> Union[dict, str, 'pd.DataFrame Modify to return only installed ones TODO Return with query name as key rather than REST endpoint as key? """ - logger.info("entry: getInstalledQueries") + logger.debug("entry: getInstalledQueries") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -98,7 +98,7 @@ def getInstalledQueries(self, fmt: str = "py") -> Union[dict, str, 'pd.DataFrame if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getInstalledQueries") + logger.debug("exit: getInstalledQueries") return ret @@ -123,13 +123,13 @@ def installQueries(self, queries: Union[str, list], flag: Union[str, list] = Non GET /gsql/v1/queries/install See https://docs.tigergraph.com/tigergraph-server/current/api/built-in-endpoints#_install_a_query """ - logger.info("entry: installQueries") + logger.debug("entry: installQueries") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) self.ver = self.getVer() major_ver, minor_ver, patch_ver = self.ver.split(".") if int(major_ver) < 4 or int(major_ver) == 4 and int(minor_ver) == 0: - logger.info("exit: installQueries") + logger.debug("exit: installQueries") raise TigerGraphException( "This function is only supported on versions of TigerGraph >= 4.1.0.", 0) @@ -148,7 +148,7 @@ def installQueries(self, queries: Union[str, list], flag: Union[str, list] = Non if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: installQueries") + logger.debug("exit: installQueries") return ret @@ -166,13 +166,13 @@ def getQueryInstallationStatus(self, requestId: str) -> dict: GET /gsql/queries/install/{request_id} See https://docs.tigergraph.com/tigergraph-server/current/api/built-in-endpoints#_check_query_installation_status """ - logger.info("entry: getQueryInstallationStatus") + logger.debug("entry: getQueryInstallationStatus") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) self.ver = self.getVer() major_ver, minor_ver, patch_ver = self.ver.split(".") if int(major_ver) < 4 or int(major_ver) == 4 and int(minor_ver) == 0: - logger.info("exit: getQueryInstallationStatus") + logger.debug("exit: getQueryInstallationStatus") raise TigerGraphException( "This function is only supported on versions of TigerGraph >= 4.1.0.", 0) @@ -180,7 +180,7 @@ def getQueryInstallationStatus(self, requestId: str) -> dict: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getQueryInstallationStatus") + logger.debug("exit: getQueryInstallationStatus") return ret @@ -249,7 +249,7 @@ def runInstalledQuery(self, queryName: str, params: Union[str, dict] = None, - `POST /query/{graph_name}/{query_name}` See xref:tigergraph-server:API:built-in-endpoints.adoc#_run_an_installed_query_post[Run an installed query (POST)] """ - logger.info("entry: runInstalledQuery") + logger.debug("entry: runInstalledQuery") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -261,7 +261,7 @@ def runInstalledQuery(self, queryName: str, params: Union[str, dict] = None, if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: runInstalledQuery (POST)") + logger.debug("exit: runInstalledQuery (POST)") return ret else: @@ -272,7 +272,7 @@ def runInstalledQuery(self, queryName: str, params: Union[str, dict] = None, if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: runInstalledQuery (GET)") + logger.debug("exit: runInstalledQuery (GET)") return ret @@ -353,7 +353,7 @@ def runInterpretedQuery(self, queryText: str, params: Union[str, dict] = None) - TODO Add "GSQL-TIMEOUT: " and "RESPONSE-LIMIT: " plus parameters if applicable to interpreted queries (see runInstalledQuery() above) """ - logger.info("entry: runInterpretedQuery") + logger.debug("entry: runInterpretedQuery") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -372,7 +372,7 @@ def runInterpretedQuery(self, queryText: str, params: Union[str, dict] = None) - if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: runInterpretedQuery") + logger.debug("exit: runInterpretedQuery") return ret @@ -481,7 +481,7 @@ def addOccurrences(obj: dict, src: str): else: obj["x_sources"] = [src] - logger.info("entry: parseQueryOutput") + logger.debug("entry: parseQueryOutput") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -573,7 +573,7 @@ def addOccurrences(obj: dict, src: str): if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: parseQueryOutput") + logger.debug("exit: parseQueryOutput") return ret @@ -594,7 +594,7 @@ def getStatistics(self, seconds: int = 10, segments: int = 10) -> dict: - `GET /statistics/{graph_name}` See xref:tigergraph-server:API:built-in-endpoints.adoc#_show_query_performance[Show query performance] """ - logger.info("entry: getStatistics") + logger.debug("entry: getStatistics") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -604,7 +604,7 @@ def getStatistics(self, seconds: int = 10, segments: int = 10) -> dict: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getStatistics") + logger.debug("exit: getStatistics") return ret @@ -626,11 +626,11 @@ def describeQuery(self, queryName: str, queryDescription: str, parameterDescript - `PUT /gsqlserver/gsql/description?graph={graph_name}` (In TigerGraph version 4.0) - `PUT /gsql/v1/description?graph={graph_name}` (In TigerGraph versions >4.0) """ - logger.info("entry: describeQuery") + logger.debug("entry: describeQuery") self.ver = self.getVer() major_ver, minor_ver, patch_ver = self.ver.split(".") if int(major_ver) < 4: - logger.info("exit: describeQuery") + logger.debug("exit: describeQuery") raise TigerGraphException( "This function is only supported on versions of TigerGraph >= 4.0.0.", 0) @@ -656,7 +656,7 @@ def describeQuery(self, queryName: str, queryDescription: str, parameterDescript if logger.level == logging.DEBUG: logger.debug("return: " + str(res)) - logger.info("exit: describeQuery") + logger.debug("exit: describeQuery") return res @@ -676,11 +676,11 @@ def getQueryDescription(self, queryName: Optional[Union[str, list]] = "all"): - `GET /gsqlserver/gsql/description?graph={graph_name}` (In TigerGraph version 4.0) - `GET /gsql/v1/description?graph={graph_name}` (In TigerGraph versions >4.0) """ - logger.info("entry: getQueryDescription") + logger.debug("entry: getQueryDescription") self.ver = self.getVer() major_ver, minor_ver, patch_ver = self.ver.split(".") if int(major_ver) < 4: - logger.info("exit: getQueryDescription") + logger.debug("exit: getQueryDescription") raise TigerGraphException( "This function is only supported on versions of TigerGraph >= 4.0.0.", 0) @@ -720,11 +720,11 @@ def dropQueryDescription(self, queryName: str, dropParamDescriptions: bool = Tru - `DELETE /gsqlserver/gsql/description?graph={graph_name}` (In TigerGraph version 4.0) - `DELETE /gsql/v1/description?graph={graph_name}` (In TigerGraph versions >4.0) """ - logger.info("entry: dropQueryDescription") + logger.debug("entry: dropQueryDescription") self.ver = self.getVer() major_ver, minor_ver, patch_ver = self.ver.split(".") if int(major_ver) < 4: - logger.info("exit: describeQuery") + logger.debug("exit: describeQuery") raise TigerGraphException( "This function is only supported on versions of TigerGraph >= 4.0.0.", 0) @@ -745,6 +745,6 @@ def dropQueryDescription(self, queryName: str, dropParamDescriptions: bool = Tru if logger.level == logging.DEBUG: logger.debug("return: " + str(res)) - logger.info("exit: dropQueryDescription") + logger.debug("exit: dropQueryDescription") return res diff --git a/pyTigerGraph/pyTigerGraphSchema.py b/pyTigerGraph/pyTigerGraphSchema.py index d55496da..a0901272 100644 --- a/pyTigerGraph/pyTigerGraphSchema.py +++ b/pyTigerGraph/pyTigerGraphSchema.py @@ -31,7 +31,7 @@ def _getUDTs(self) -> dict: GET /gsqlserver/gsql/udtlist (In TigerGraph versions 3.x) GET /gsql/v1/udt/tuples (In TigerGraph versions 4.x) """ - logger.info("entry: _getUDTs") + logger.debug("entry: _getUDTs") if self._version_greater_than_4_0(): res = self._get(self.gsUrl + "/gsql/v1/udt/tuples?graph=" + self.graphname, @@ -42,7 +42,7 @@ def _getUDTs(self) -> dict: if logger.level == logging.DEBUG: logger.debug("return: " + str(res)) - logger.info("exit: _getUDTs") + logger.debug("exit: _getUDTs") return res @@ -65,7 +65,7 @@ def getSchema(self, udts: bool = True, force: bool = False) -> dict: See xref:tigergraph-server:API:built-in-endpoints.adoc#_show_graph_schema_metadata[Show graph schema metadata] - `GET /gsql/v1/schema/graphs/{graph_name}` (In TigerGraph version 4.x) """ - logger.info("entry: getSchema") + logger.debug("entry: getSchema") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -81,7 +81,7 @@ def getSchema(self, udts: bool = True, force: bool = False) -> dict: if logger.level == logging.DEBUG: logger.debug("return: " + str(self.schema)) - logger.info("exit: getSchema") + logger.debug("exit: getSchema") return self.schema @@ -95,7 +95,7 @@ def getSchemaVer(self) -> int: - `POST /gsqlserver/interpreted_query` (In TigerGraph versions 3.x) - `POST /gsql/v1/queries/interpret` (In TigerGraph versions 4.x) """ - logger.info("entry: getSchemaVer") + logger.debug("entry: getSchemaVer") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -121,7 +121,7 @@ def getSchemaVer(self) -> int: logger.warning(f"Schema version '{schema_version}' could not be converted to integer") if schema_version_int is None: logger.warning("Schema version not found in query result") - logger.info("exit: _get_schema_ver") + logger.debug("exit: _get_schema_ver") return schema_version_int except Exception as e: @@ -162,7 +162,7 @@ def upsertData(self, data: Union[str, object], atomic: bool = False, ackAll: boo - `POST /graph/{graph_name}` See xref:tigergraph-server:API:built-in-endpoints.adoc#_upsert_data_to_graph[Upsert data to graph] """ - logger.info("entry: upsertData") + logger.debug("entry: upsertData") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -174,7 +174,7 @@ def upsertData(self, data: Union[str, object], atomic: bool = False, ackAll: boo if logger.level == logging.DEBUG: logger.debug("return: " + str(res)) - logger.info("exit: upsertData") + logger.debug("exit: upsertData") return res @@ -196,7 +196,7 @@ def getEndpoints(self, builtin: bool = False, dynamic: bool = False, - `GET /endpoints/{graph_name}` See xref:tigergraph-server:API:built-in-endpoints.adoc#_list_all_endpoints[List all endpoints] """ - logger.info("entry: getEndpoints") + logger.debug("entry: getEndpoints") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -226,7 +226,7 @@ def getEndpoints(self, builtin: bool = False, dynamic: bool = False, if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getEndpoints") + logger.debug("exit: getEndpoints") return ret diff --git a/pyTigerGraph/pyTigerGraphUDT.py b/pyTigerGraph/pyTigerGraphUDT.py index 31c78401..454f8d38 100644 --- a/pyTigerGraph/pyTigerGraphUDT.py +++ b/pyTigerGraph/pyTigerGraphUDT.py @@ -21,7 +21,7 @@ def getUDTs(self) -> list: Returns: The list of names of UDTs (defined in the global scope, i.e. not in queries). """ - logger.info("entry: getUDTs") + logger.debug("entry: getUDTs") ret = [] for udt in self._getUDTs(): @@ -29,7 +29,7 @@ def getUDTs(self) -> list: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getUDTs") + logger.debug("exit: getUDTs") return ret @@ -46,7 +46,7 @@ def getUDT(self, udtName: str) -> list: The metadata (the details of the fields) of the UDT. """ - logger.info("entry: getUDT") + logger.debug("entry: getUDT") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -56,12 +56,12 @@ def getUDT(self, udtName: str) -> list: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getUDT (found)") + logger.debug("exit: getUDT (found)") return ret if logger.level == logging.DEBUG: logger.warning("UDT `" + udtName + "` was not found") - logger.info("exit: getUDT (not found)") + logger.debug("exit: getUDT (not found)") return [] # UDT was not found diff --git a/pyTigerGraph/pyTigerGraphUtils.py b/pyTigerGraph/pyTigerGraphUtils.py index 849b0bed..98ad02e0 100644 --- a/pyTigerGraph/pyTigerGraphUtils.py +++ b/pyTigerGraph/pyTigerGraphUtils.py @@ -37,7 +37,7 @@ def echo(self, usePost: bool = False) -> str: - `POST /echo` See xref:tigergraph-server:API:built-in-endpoints.adoc#_echo[Echo] """ - logger.info("entry: echo") + logger.debug("entry: echo") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -46,7 +46,7 @@ def echo(self, usePost: bool = False) -> str: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: echo (POST)") + logger.debug("exit: echo (POST)") return ret @@ -54,7 +54,7 @@ def echo(self, usePost: bool = False) -> str: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: echo (GET)") + logger.debug("exit: echo (GET)") return ret @@ -65,7 +65,7 @@ def getLicenseInfo(self) -> dict: Returns license details. For an evaluation/trial deployment, returns an information message and -1 remaining days. """ - logger.info("entry: getLicenseInfo") + logger.debug("entry: getLicenseInfo") res = self._req("GET", self.restppUrl + "/showlicenseinfo", resKey="", skipCheck=True) @@ -73,7 +73,7 @@ def getLicenseInfo(self) -> dict: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getLicenseInfo") + logger.debug("exit: getLicenseInfo") return ret diff --git a/pyTigerGraph/pyTigerGraphVertex.py b/pyTigerGraph/pyTigerGraphVertex.py index 56e13916..98da6e6f 100644 --- a/pyTigerGraph/pyTigerGraphVertex.py +++ b/pyTigerGraph/pyTigerGraphVertex.py @@ -48,7 +48,7 @@ def getVertexTypes(self, force: bool = False) -> list: Returns: The list of vertex types defined in the current graph. """ - logger.info("entry: getVertexTypes") + logger.debug("entry: getVertexTypes") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -58,7 +58,7 @@ def getVertexTypes(self, force: bool = False) -> list: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getVertexTypes") + logger.debug("exit: getVertexTypes") return ret @@ -77,7 +77,7 @@ def getVertexAttrs(self, vertexType: str) -> list: - "map_type(key_type,value_type)" and it is a string. """ - logger.info("entry: getVertexAttrs") + logger.debug("entry: getVertexAttrs") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -91,7 +91,7 @@ def getVertexAttrs(self, vertexType: str) -> list: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getVertexAttrs") + logger.debug("exit: getVertexAttrs") return ret @@ -110,7 +110,7 @@ def getVertexVectors(self, vertexType: str) -> list: - "map_type(key_type,value_type)" and it is a string. """ - logger.info("entry: getVertexVectors") + logger.debug("entry: getVertexVectors") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -124,7 +124,7 @@ def getVertexVectors(self, vertexType: str) -> list: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getVertexVectors") + logger.debug("exit: getVertexVectors") return ret @@ -143,7 +143,7 @@ def getVectorStatus(self, vertexType: str, vectorName: str = "") -> bool: Endpoint: - `GET /vector/status/{graph_name}/{vertex_type}/[{vector_name}]` """ - logger.info("entry: getVectorStatus") + logger.debug("entry: getVectorStatus") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -152,7 +152,7 @@ def getVectorStatus(self, vertexType: str, vectorName: str = "") -> bool: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getVectorStatus") + logger.debug("exit: getVectorStatus") return len(ret["NeedRebuildServers"]) == 0 @@ -169,7 +169,7 @@ def getVertexType(self, vertexType: str, force: bool = False) -> dict: Returns: The metadata of the vertex type. """ - logger.info("entry: getVertexType") + logger.debug("entry: getVertexType") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -177,12 +177,12 @@ def getVertexType(self, vertexType: str, force: bool = False) -> dict: if vt["Name"] == vertexType: if logger.level == logging.DEBUG: logger.debug("return: " + str(vt)) - logger.info("exit: getVertexType (found)") + logger.debug("exit: getVertexType (found)") return vt logger.warning("Vertex type `" + vertexType + "` was not found.") - logger.info("exit: getVertexType (not found)") + logger.debug("exit: getVertexType (not found)") return {} # Vertex type was not found @@ -223,7 +223,7 @@ def getVertexCount(self, vertexType: Union[str, list] = "*", where: str = "", re - `POST /builtins` See xref:tigergraph-server:API:built-in-endpoints.adoc#_run_built_in_functions_on_graph[Run built-in functions] """ - logger.info("entry: getVertexCount") + logger.debug("entry: getVertexCount") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -240,7 +240,7 @@ def getVertexCount(self, vertexType: Union[str, list] = "*", where: str = "", re if logger.level == logging.DEBUG: logger.debug("return: " + str(res)) - logger.info("exit: getVertexCount (1)") + logger.debug("exit: getVertexCount (1)") return res @@ -252,7 +252,7 @@ def getVertexCount(self, vertexType: Union[str, list] = "*", where: str = "", re if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getVertexCount (2)") + logger.debug("exit: getVertexCount (2)") return ret @@ -288,7 +288,7 @@ def upsertVertex(self, vertexType: str, vertexId: str, attributes: dict = None) - `POST /graph/{graph_name}` See xref:tigergraph-server:API:built-in-endpoints.adoc#_upsert_data_to_graph[Upsert data to graph] """ - logger.info("entry: upsertVertex") + logger.debug("entry: upsertVertex") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -300,7 +300,7 @@ def upsertVertex(self, vertexType: str, vertexId: str, attributes: dict = None) if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: upsertVertex") + logger.debug("exit: upsertVertex") return ret @@ -349,7 +349,7 @@ def upsertVertices(self, vertexType: str, vertices: list, atomic: bool = False) - `POST /graph/{graph_name}` See xref:tigergraph-server:API:built-in-endpoints.adoc#_upsert_data_to_graph[Upsert data to graph] """ - logger.info("entry: upsertVertices") + logger.debug("entry: upsertVertices") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -368,7 +368,7 @@ def upsertVertices(self, vertexType: str, vertices: list, atomic: bool = False) if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: upsertVertices") + logger.debug("exit: upsertVertices") return ret @@ -398,7 +398,7 @@ def upsertVertexDataFrame(self, df: 'pd.DataFrame', vertexType: str, v_id: bool Returns: The number of vertices upserted. """ - logger.info("entry: upsertVertexDataFrame") + logger.debug("entry: upsertVertexDataFrame") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -408,7 +408,7 @@ def upsertVertexDataFrame(self, df: 'pd.DataFrame', vertexType: str, v_id: bool if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: upsertVertexDataFrame") + logger.debug("exit: upsertVertexDataFrame") return ret @@ -457,7 +457,7 @@ def getVertices(self, vertexType: str, select: str = "", where: str = "", - `GET /graph/{graph_name}/vertices/{vertex_type}` See xref:tigergraph-server:API:built-in-endpoints.adoc#_list_vertices[List vertices] """ - logger.info("entry: getVertices") + logger.debug("entry: getVertices") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -479,7 +479,7 @@ def getVertices(self, vertexType: str, select: str = "", where: str = "", if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getVertices") + logger.debug("exit: getVertices") return ret @@ -516,7 +516,7 @@ def getVertexDataFrame(self, vertexType: str, select: str = "", where: str = "", The (selected) details of the (matching) vertex instances (sorted, limited) as pandas DataFrame. """ - logger.info("entry: getVertexDataFrame") + logger.debug("entry: getVertexDataFrame") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -525,7 +525,7 @@ def getVertexDataFrame(self, vertexType: str, select: str = "", where: str = "", if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getVertexDataFrame") + logger.debug("exit: getVertexDataFrame") return ret @@ -576,7 +576,7 @@ def getVerticesById(self, vertexType: str, vertexIds: Union[int, str, list], sel TODO Find out how/if select and timeout can be specified """ - logger.info("entry: getVerticesById") + logger.debug("entry: getVerticesById") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -598,7 +598,7 @@ def getVerticesById(self, vertexType: str, vertexIds: Union[int, str, list], sel if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getVerticesById") + logger.debug("exit: getVerticesById") return ret @@ -619,7 +619,7 @@ def getVertexDataFrameById(self, vertexType: str, vertexIds: Union[int, str, lis Returns: The (selected) details of the (matching) vertex instances as pandas DataFrame. """ - logger.info("entry: getVertexDataFrameById") + logger.debug("entry: getVertexDataFrameById") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -628,7 +628,7 @@ def getVertexDataFrameById(self, vertexType: str, vertexIds: Union[int, str, lis if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getVertexDataFrameById") + logger.debug("exit: getVertexDataFrameById") return ret @@ -662,7 +662,7 @@ def getVertexStats(self, vertexTypes: Union[str, list], skipNA: bool = False) -> - `POST /builtins/{graph_name}` See xref:tigergraph-server:API:built-in-endpoints.adoc#_run_built_in_functions_on_graph[Run built-in functions] """ - logger.info("entry: getVertexStats") + logger.debug("entry: getVertexStats") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -685,7 +685,7 @@ def getVertexStats(self, vertexTypes: Union[str, list], skipNA: bool = False) -> if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getVertexStats") + logger.debug("exit: getVertexStats") return ret @@ -727,7 +727,7 @@ def delVertices(self, vertexType: str, where: str = "", limit: str = "", sort: s - `DELETE /graph/{graph_name}/vertices/{vertex_type}` See xref:tigergraph-server:API:built-in-endpoints.adoc#_delete_vertices[Delete vertices] """ - logger.info("entry: delVertices") + logger.debug("entry: delVertices") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -745,7 +745,7 @@ def delVertices(self, vertexType: str, where: str = "", limit: str = "", sort: s if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: delVertices") + logger.debug("exit: delVertices") return ret @@ -771,7 +771,7 @@ def delVerticesById(self, vertexType: str, vertexIds: Union[int, str, list], - `DELETE /graph/{graph_name}/vertices/{vertex_type}/{vertex_id}` See xref:tigergraph-server:API:built-in-endpoints.adoc#_delete_a_vertex[Delete a vertex] """ - logger.info("entry: delVerticesById") + logger.debug("entry: delVerticesById") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -790,7 +790,7 @@ def delVerticesById(self, vertexType: str, vertexIds: Union[int, str, list], if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: delVerticesById") + logger.debug("exit: delVerticesById") return ret @@ -817,7 +817,7 @@ def delVerticesByType(self, vertexType: str, permanent: bool = False, ack: str = ``` """ - logger.info("entry: delVerticesByType") + logger.debug("entry: delVerticesByType") logger.debug("params: " + str(locals())) if ack.lower() not in ["none", "all"]: raise TigerGraphException("Invalid value for ack parameter. Use 'none' or 'all'.", None) @@ -832,7 +832,7 @@ def delVerticesByType(self, vertexType: str, permanent: bool = False, ack: str = ret = self._delete(url)["deleted_vertices"] logger.debug("return: " + str(ret)) - logger.info("exit: delVerticesByType") + logger.debug("exit: delVerticesByType") return ret @@ -852,7 +852,7 @@ def vertexSetToDataFrame(self, vertexSet: dict, withId: bool = True, withType: b Returns: The vertex set as a pandas DataFrame. """ - logger.info("entry: vertexSetToDataFrame") + logger.debug("entry: vertexSetToDataFrame") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -860,6 +860,6 @@ def vertexSetToDataFrame(self, vertexSet: dict, withId: bool = True, withType: b if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: vertexSetToDataFrame") + logger.debug("exit: vertexSetToDataFrame") return ret diff --git a/pyTigerGraph/pytgasync/pyTigerGraphAuth.py b/pyTigerGraph/pytgasync/pyTigerGraphAuth.py index 948fd5ab..a319700a 100644 --- a/pyTigerGraph/pytgasync/pyTigerGraphAuth.py +++ b/pyTigerGraph/pytgasync/pyTigerGraphAuth.py @@ -35,7 +35,7 @@ async def getSecrets(self) -> Dict[str, str]: This function returns the masked version of the secret. The original value of the secret cannot be retrieved after creation. """ - logger.info("entry: getSecrets") + logger.debug("entry: getSecrets") res = await self.gsql(""" USE GRAPH {} @@ -44,7 +44,7 @@ async def getSecrets(self) -> Dict[str, str]: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getSecrets") + logger.debug("exit: getSecrets") return ret # TODO Process response, return a dictionary of alias/secret pairs @@ -83,7 +83,7 @@ async def createSecret(self, alias: str = "", withAlias: bool = False) -> Union[ internal processes of granting access to TigerGraph instances. Normally, this function should not be necessary and should not be executable by generic users. """ - logger.info("entry: createSecret") + logger.debug("entry: createSecret") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -104,7 +104,7 @@ async def createSecret(self, alias: str = "", withAlias: bool = False) -> Union[ if logger.level == logging.DEBUG: logger.debug("return: " + str(secret)) - logger.info("exit: createSecret") + logger.debug("exit: createSecret") return secret async def dropSecret(self, alias: Union[str, list], ignoreErrors: bool = True) -> str: @@ -121,7 +121,7 @@ async def dropSecret(self, alias: Union[str, list], ignoreErrors: bool = True) - `TigerGraphException` if a non-existent secret is attempted to be dropped (unless `ignoreErrors` is `True`). Re-raises other exceptions. """ - logger.info("entry: dropSecret") + logger.debug("entry: dropSecret") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -139,7 +139,7 @@ async def dropSecret(self, alias: Union[str, list], ignoreErrors: bool = True) - if logger.level == logging.DEBUG: logger.debug("return: " + str(res)) - logger.info("exit: dropSecret") + logger.debug("exit: dropSecret") return res @@ -179,7 +179,7 @@ async def _token(self, secret: str = None, lifetime: int = None, token=None, _me return res, mainVer async def getToken(self, secret: str = None, setToken: bool = True, lifetime: int = None) -> Union[tuple, str]: - logger.info("entry: getToken") + logger.debug("entry: getToken") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -194,16 +194,16 @@ async def getToken(self, secret: str = None, setToken: bool = True, lifetime: in self.authHeader = auth_header self.authMode = "token" - logger.info("exit: getToken") + logger.debug("exit: getToken") return token async def refreshToken(self, secret: str = None, setToken: bool = True, lifetime: int = None, token="") -> Union[tuple, str]: - logger.info("entry: refreshToken") + logger.debug("entry: refreshToken") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) if await self._version_greater_than_4_0(): - logger.info("exit: refreshToken") + logger.debug("exit: refreshToken") raise TigerGraphException( "Refreshing tokens is only supported on versions of TigerGraph <= 4.0.0.", 0) @@ -212,7 +212,7 @@ async def refreshToken(self, secret: str = None, setToken: bool = True, lifetime res, mainVer = await self._token(secret=secret, lifetime=lifetime, token=token, _method="PUT") newToken = _parse_token_response(res, setToken, mainVer) - logger.info("exit: refreshToken") + logger.debug("exit: refreshToken") return newToken async def deleteToken(self, secret: str, token=None, skipNA=True) -> bool: @@ -223,7 +223,7 @@ async def deleteToken(self, secret: str, token=None, skipNA=True) -> bool: if not res["error"] or (res["code"] == "REST-3300" and skipNA): if logger.level == logging.DEBUG: logger.debug("return: " + str(True)) - logger.info("exit: deleteToken") + logger.debug("exit: deleteToken") return True diff --git a/pyTigerGraph/pytgasync/pyTigerGraphBase.py b/pyTigerGraph/pytgasync/pyTigerGraphBase.py index 9edaf5de..0573cb90 100644 --- a/pyTigerGraph/pytgasync/pyTigerGraphBase.py +++ b/pyTigerGraph/pytgasync/pyTigerGraphBase.py @@ -207,7 +207,7 @@ async def _get(self, url: str, authMode: str = "token", headers: dict = None, re Returns: The (relevant part of the) response from the request (as a dictionary). """ - logger.info("entry: _get") + logger.debug("entry: _get") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -215,7 +215,7 @@ async def _get(self, url: str, authMode: str = "token", headers: dict = None, re if logger.level == logging.DEBUG: logger.debug("return: " + str(res)) - logger.info("exit: _get") + logger.debug("exit: _get") return res @@ -244,7 +244,7 @@ async def _post(self, url: str, authMode: str = "token", headers: dict = None, Returns: The (relevant part of the) response from the request (as a dictionary). """ - logger.info("entry: _post") + logger.debug("entry: _post") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -252,7 +252,7 @@ async def _post(self, url: str, authMode: str = "token", headers: dict = None, if logger.level == logging.DEBUG: logger.debug("return: " + str(res)) - logger.info("exit: _post") + logger.debug("exit: _post") return res @@ -268,7 +268,7 @@ async def _put(self, url: str, authMode: str = "token", data=None, resKey=None, Returns: The response from the request (as a dictionary). """ - logger.info("entry: _put") + logger.debug("entry: _put") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -276,7 +276,7 @@ async def _put(self, url: str, authMode: str = "token", data=None, resKey=None, if logger.level == logging.DEBUG: logger.debug("return: " + str(res)) - logger.info("exit: _put") + logger.debug("exit: _put") return res @@ -292,7 +292,7 @@ async def _delete(self, url: str, authMode: str = "token", data: dict = None, re Returns: The response from the request (as a dictionary). """ - logger.info("entry: _delete") + logger.debug("entry: _delete") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -300,7 +300,7 @@ async def _delete(self, url: str, authMode: str = "token", data: dict = None, re if logger.level == logging.DEBUG: logger.debug("return: " + str(res)) - logger.info("exit: _delete") + logger.debug("exit: _delete") return res @@ -320,7 +320,7 @@ async def getVersion(self, raw: bool = False) -> Union[str, list]: - `GET /version` See xref:tigergraph-server:API:built-in-endpoints.adoc#_show_component_versions[Show component versions] """ - logger.info("entry: getVersion") + logger.debug("entry: getVersion") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) response = await self._get(self.restppUrl+"/version", strictJson=False, resKey="message") @@ -328,7 +328,7 @@ async def getVersion(self, raw: bool = False) -> Union[str, list]: if logger.level == logging.DEBUG: logger.debug("return: " + str(components)) - logger.info("exit: getVersion") + logger.debug("exit: getVersion") return components async def getVer(self, component: str = "product", full: bool = False) -> str: @@ -348,7 +348,7 @@ async def getVer(self, component: str = "product", full: bool = False) -> str: Raises: `TigerGraphException` if invalid/non-existent component is specified. """ - logger.info("entry: getVer") + logger.debug("entry: getVer") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) version = await self.getVersion() @@ -356,7 +356,7 @@ async def getVer(self, component: str = "product", full: bool = False) -> str: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getVer") + logger.debug("exit: getVer") return ret diff --git a/pyTigerGraph/pytgasync/pyTigerGraphDataset.py b/pyTigerGraph/pytgasync/pyTigerGraphDataset.py index d47d4ae8..aef2f4cd 100644 --- a/pyTigerGraph/pytgasync/pyTigerGraphDataset.py +++ b/pyTigerGraph/pytgasync/pyTigerGraphDataset.py @@ -33,7 +33,7 @@ async def ingestDataset( Whether or not to get auth token from the database. This is required when auth token is enabled for the database. Defaults to False. """ - logger.info("entry: ingestDataset") + logger.debug("entry: ingestDataset") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -86,7 +86,7 @@ async def ingestDataset( _parse_ingest_dataset(responses, cleanup, dataset) print("---- Finished ingestion ----", flush=True) - logger.info("exit: ingestDataset") + logger.debug("exit: ingestDataset") async def check_exist_graphs(self, name: str) -> bool: "NO DOC" diff --git a/pyTigerGraph/pytgasync/pyTigerGraphEdge.py b/pyTigerGraph/pytgasync/pyTigerGraphEdge.py index 4395cb61..aa116840 100644 --- a/pyTigerGraph/pytgasync/pyTigerGraphEdge.py +++ b/pyTigerGraph/pytgasync/pyTigerGraphEdge.py @@ -54,7 +54,7 @@ async def getEdgeTypes(self, force: bool = False) -> list: Returns: The list of edge types defined in the current graph. """ - logger.info("entry: getEdgeTypes") + logger.debug("entry: getEdgeTypes") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -65,7 +65,7 @@ async def getEdgeTypes(self, force: bool = False) -> list: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getEdgeTypes") + logger.debug("exit: getEdgeTypes") return ret @@ -82,7 +82,7 @@ async def getEdgeType(self, edgeType: str, force: bool = False) -> dict: Returns: The metadata of the edge type. """ - logger.info("entry: getEdgeType") + logger.debug("entry: getEdgeType") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -91,12 +91,12 @@ async def getEdgeType(self, edgeType: str, force: bool = False) -> dict: if et["Name"] == edgeType: if logger.level == logging.DEBUG: logger.debug("return: " + str(et)) - logger.info("exit: getEdgeType (found)") + logger.debug("exit: getEdgeType (found)") return et logger.warning("Edge type `" + edgeType + "` was not found.") - logger.info("exit: getEdgeType (not found)") + logger.debug("exit: getEdgeType (not found)") return {} @@ -115,7 +115,7 @@ async def getEdgeAttrs(self, edgeType: str) -> list: - "map_type(key_type,value_type)" and it is a string. """ - logger.info("entry: getAttributes") + logger.debug("entry: getAttributes") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -128,7 +128,7 @@ async def getEdgeAttrs(self, edgeType: str) -> list: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getAttributes") + logger.debug("exit: getAttributes") return ret @@ -155,7 +155,7 @@ async def getEdgeSourceVertexType(self, edgeType: str) -> Union[str, set]: at the individual source/target pairs to find out which combinations are valid/defined. """ - logger.info("entry: getEdgeSourceVertexType") + logger.debug("entry: getEdgeSourceVertexType") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -185,7 +185,7 @@ async def getEdgeTargetVertexType(self, edgeType: str) -> Union[str, set]: edge is defined between all source and all target vertex types. You need to look at the individual source/target pairs to find out which combinations are valid/defined. """ - logger.info("entry: getEdgeTargetVertexType") + logger.debug("entry: getEdgeTargetVertexType") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -203,7 +203,7 @@ async def isDirected(self, edgeType: str) -> bool: Returns: `True`, if the edge is directed. """ - logger.info("entry: isDirected") + logger.debug("entry: isDirected") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -212,7 +212,7 @@ async def isDirected(self, edgeType: str) -> bool: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: isDirected") + logger.debug("exit: isDirected") return ret @@ -226,13 +226,13 @@ async def getReverseEdge(self, edgeType: str) -> str: Returns: The name of the reverse edge, if it was defined. """ - logger.info("entry: getReverseEdge") + logger.debug("entry: getReverseEdge") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) if not await self.isDirected(edgeType): logger.error(edgeType + " is not a directed edge") - logger.info("exit: getReverseEdge (not directed)") + logger.debug("exit: getReverseEdge (not directed)") return "" @@ -243,11 +243,11 @@ async def getReverseEdge(self, edgeType: str) -> str: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getReverseEdge (reverse edge found)") + logger.debug("exit: getReverseEdge (reverse edge found)") return ret - logger.info("exit: getReverseEdge (reverse edge not found)") + logger.debug("exit: getReverseEdge (reverse edge not found)") return "" # TODO Should return some other value or raise exception? @@ -262,7 +262,7 @@ async def isMultiEdge(self, edgeType: str) -> bool: Returns: `True`, if the edge can have multiple instances between the same pair of vertices. """ - logger.info("entry: isMultiEdge") + logger.debug("entry: isMultiEdge") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -271,7 +271,7 @@ async def isMultiEdge(self, edgeType: str) -> bool: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: isMultiEdge") + logger.debug("exit: isMultiEdge") return ret @@ -285,7 +285,7 @@ async def getDiscriminators(self, edgeType: str) -> list: Returns: A list of (attribute_name, attribute_type) tuples. """ - logger.info("entry: getDiscriminators") + logger.debug("entry: getDiscriminators") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -299,7 +299,7 @@ async def getDiscriminators(self, edgeType: str) -> list: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getDiscriminators") + logger.debug("exit: getDiscriminators") return ret @@ -347,7 +347,7 @@ async def getEdgeCountFrom(self, sourceVertexType: str = "", sourceVertexId: Uni - `POST /builtins/{graph_name}` See https://docs.tigergraph.com/tigergraph-server/current/api/built-in-endpoints#_run_built_in_functions_on_graph """ - logger.info("entry: getEdgeCountFrom") + logger.debug("entry: getEdgeCountFrom") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -367,7 +367,7 @@ async def getEdgeCountFrom(self, sourceVertexType: str = "", sourceVertexId: Uni if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getEdgeCountFrom (multiple edge types)") + logger.debug("exit: getEdgeCountFrom (multiple edge types)") return ret @@ -390,7 +390,7 @@ async def getEdgeCount(self, edgeType: str = "*", sourceVertexType: str = "", Returns: A dictionary of `edge_type: edge_count` pairs. """ - logger.info("entry: getEdgeCount") + logger.debug("entry: getEdgeCount") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -399,7 +399,7 @@ async def getEdgeCount(self, edgeType: str = "*", sourceVertexType: str = "", if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getEdgeCount") + logger.debug("exit: getEdgeCount") return ret @@ -447,7 +447,7 @@ async def upsertEdge(self, sourceVertexType: str, sourceVertexId: str, edgeType: TODO Add ack, new_vertex_only, vertex_must_exist, update_vertex_only and atomic_level parameters and functionality. """ - logger.info("entry: upsertEdge") + logger.debug("entry: upsertEdge") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -462,7 +462,7 @@ async def upsertEdge(self, sourceVertexType: str, sourceVertexId: str, edgeType: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: upsertEdge") + logger.debug("exit: upsertEdge") return ret @@ -511,7 +511,7 @@ async def upsertEdges(self, sourceVertexType: str, edgeType: str, targetVertexTy parameters and functionality. """ - logger.info("entry: upsertEdges") + logger.debug("entry: upsertEdges") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -539,7 +539,7 @@ async def upsertEdges(self, sourceVertexType: str, edgeType: str, targetVertexTy if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: upsertEdges") + logger.debug("exit: upsertEdges") return ret @@ -577,7 +577,7 @@ async def upsertEdgeDataFrame(self, df: 'pd.DataFrame', sourceVertexType: str, e Returns: The number of edges upserted. """ - logger.info("entry: upsertEdgeDataFrame") + logger.debug("entry: upsertEdgeDataFrame") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -586,7 +586,7 @@ async def upsertEdgeDataFrame(self, df: 'pd.DataFrame', sourceVertexType: str, e if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: upsertEdgeDataFrame") + logger.debug("exit: upsertEdgeDataFrame") return ret @@ -641,7 +641,7 @@ async def getEdges(self, sourceVertexType: str, sourceVertexId: str, edgeType: s - `GET /graph/{graph_name}/edges/{source_vertex_type}/{source_vertex_id}` See https://docs.tigergraph.com/dev/restpp-api/built-in-endpoints#list-edges-of-a-vertex """ - logger.info("entry: getEdges") + logger.debug("entry: getEdges") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -666,7 +666,7 @@ async def getEdges(self, sourceVertexType: str, sourceVertexId: str, edgeType: s if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getEdges") + logger.debug("exit: getEdges") return ret @@ -707,7 +707,7 @@ async def getEdgesDataFrame(self, sourceVertexType: str, sourceVertexId: str, ed The (selected) details of the (matching) edge instances (sorted, limited) as dictionary, JSON or pandas DataFrame. """ - logger.info("entry: getEdgesDataFrame") + logger.debug("entry: getEdgesDataFrame") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -716,7 +716,7 @@ async def getEdgesDataFrame(self, sourceVertexType: str, sourceVertexId: str, ed if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getEdgesDataFrame") + logger.debug("exit: getEdgesDataFrame") return ret @@ -759,13 +759,13 @@ async def getEdgesByType(self, edgeType: str, fmt: str = "py", withId: bool = Tr The details of the edge instances of the given edge type as dictionary, JSON or pandas DataFrame. """ - logger.info("entry: getEdgesByType") + logger.debug("entry: getEdgesByType") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) if not edgeType: logger.warning("Edge type is not specified") - logger.info("exit: getEdgesByType") + logger.debug("exit: getEdgesByType") return {} @@ -785,7 +785,7 @@ async def getEdgesByType(self, edgeType: str, fmt: str = "py", withId: bool = Tr if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: _upsertAttrs") + logger.debug("exit: _upsertAttrs") return ret @@ -808,7 +808,7 @@ async def getEdgeStats(self, edgeTypes: Union[str, list], skipNA: bool = False) - `POST /builtins/{graph_name}` See https://docs.tigergraph.com/dev/restpp-api/built-in-endpoints#run-built-in-functions-on-graph """ - logger.info("entry: getEdgeStats") + logger.debug("entry: getEdgeStats") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -821,7 +821,7 @@ async def getEdgeStats(self, edgeTypes: Union[str, list], skipNA: bool = False) ets = edgeTypes else: logger.warning("The `edgeTypes` parameter is invalid.") - logger.info("exit: getEdgeStats") + logger.debug("exit: getEdgeStats") return {} @@ -836,7 +836,7 @@ async def getEdgeStats(self, edgeTypes: Union[str, list], skipNA: bool = False) if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getEdgeStats") + logger.debug("exit: getEdgeStats") return ret @@ -877,7 +877,7 @@ async def delEdges(self, sourceVertexType: str, sourceVertexId: str, edgeType: s - `DELETE /graph/{graph_name}/edges/{source_vertex_type}/{source_vertex_id}/{edge_type}/{target_vertex_type}/{target_vertex_id}` See https://docs.tigergraph.com/dev/restpp-api/built-in-endpoints#delete-an-edge """ - logger.info("entry: delEdges") + logger.debug("entry: delEdges") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -899,7 +899,7 @@ async def delEdges(self, sourceVertexType: str, sourceVertexId: str, edgeType: s if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: delEdges") + logger.debug("exit: delEdges") return ret @@ -917,7 +917,7 @@ async def edgeSetToDataFrame(self, edgeSet: list, withId: bool = True, withType: Returns: The edge set as a pandas DataFrame. """ - logger.info("entry: edgeSetToDataFrame") + logger.debug("entry: edgeSetToDataFrame") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -925,6 +925,6 @@ async def edgeSetToDataFrame(self, edgeSet: list, withId: bool = True, withType: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: edgeSetToDataFrame") + logger.debug("exit: edgeSetToDataFrame") return ret \ No newline at end of file diff --git a/pyTigerGraph/pytgasync/pyTigerGraphGSQL.py b/pyTigerGraph/pytgasync/pyTigerGraphGSQL.py index 1a919199..80b49743 100644 --- a/pyTigerGraph/pytgasync/pyTigerGraphGSQL.py +++ b/pyTigerGraph/pytgasync/pyTigerGraphGSQL.py @@ -89,7 +89,7 @@ async def getUDF(self, ExprFunctions: bool = True, ExprUtil: bool = True, json_o - `GET /gsqlserver/gsql/userdefinedfunction?filename={ExprFunctions or ExprUtil}` (In TigerGraph versions 3.x) - `GET /gsql/v1/udt/files/{ExprFunctions or ExprUtil}` (In TigerGraph versions 4.x) """ - logger.info("entry: getUDF") + logger.debug("entry: getUDF") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) diff --git a/pyTigerGraph/pytgasync/pyTigerGraphLoading.py b/pyTigerGraph/pytgasync/pyTigerGraphLoading.py index ffa66d80..da06965f 100644 --- a/pyTigerGraph/pytgasync/pyTigerGraphLoading.py +++ b/pyTigerGraph/pytgasync/pyTigerGraphLoading.py @@ -62,7 +62,7 @@ async def runLoadingJobWithDataFrame(self, df: 'pd.DataFrame', fileTag: str, job - `POST /ddl/{graph_name}` See xref:tigergraph-server:API:built-in-endpoints.adoc#_run_a_loading_job[Run a loading job] """ - logger.info("entry: runLoadingJobWithDataFrame") + logger.debug("entry: runLoadingJobWithDataFrame") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -73,7 +73,7 @@ async def runLoadingJobWithDataFrame(self, df: 'pd.DataFrame', fileTag: str, job res = await self.runLoadingJobWithData(data, fileTag, jobName, sep, eol, timeout, sizeLimit) - logger.info("exit: runLoadingJobWithDataFrame") + logger.debug("exit: runLoadingJobWithDataFrame") return res @@ -109,14 +109,14 @@ async def runLoadingJobWithFile(self, filePath: str, fileTag: str, jobName: str, - `POST /ddl/{graph_name}` See xref:tigergraph-server:API:built-in-endpoints.adoc#_run_a_loading_job[Run a loading job] """ - logger.info("entry: runLoadingJobWithFile") + logger.debug("entry: runLoadingJobWithFile") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) data = _prep_run_loading_job_with_file(filePath) res = await self.runLoadingJobWithData(data, fileTag, jobName, sep, eol, timeout, sizeLimit) - logger.info("exit: runLoadingJobWithFile") + logger.debug("exit: runLoadingJobWithFile") return res @@ -152,14 +152,14 @@ async def runLoadingJobWithData(self, data: str, fileTag: str, jobName: str, sep - `POST /ddl/{graph_name}` See xref:tigergraph-server:API:built-in-endpoints.adoc#_run_a_loading_job[Run a loading job] """ - logger.info("entry: runLoadingJobWithData") + logger.debug("entry: runLoadingJobWithData") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) if not data or not jobName or not fileTag: # invalid inputs logger.error("Invalid data or params") - logger.info("exit: runLoadingJobWithData") + logger.debug("exit: runLoadingJobWithData") return None params = { @@ -181,7 +181,7 @@ async def runLoadingJobWithData(self, data: str, fileTag: str, jobName: str, sep if logger.level == logging.DEBUG: logger.debug("return: " + str(res)) - logger.info("exit: runLoadingJobWithData") + logger.debug("exit: runLoadingJobWithData") return res @@ -205,7 +205,7 @@ async def getLoadingJobs(self) -> dict: - `GET /gsql/v1/loading-jobs?graph=` See xref:tigergraph-server:API:gsql-endpoints.adoc#_get_loading_job_names[Get loading jobs] """ - logger.info("entry: getLoadingJobs") + logger.debug("entry: getLoadingJobs") logger.debug("params: " + self._locals(locals())) @@ -214,7 +214,7 @@ async def getLoadingJobs(self) -> dict: res = await self._req("GET", url) logger.debug("return: " + str(res)) - logger.info("exit: getLoadingJobs") + logger.debug("exit: getLoadingJobs") return res @@ -229,7 +229,7 @@ async def createLoadingJob(self, job_definition: str) -> dict: - `POST /gsql/v1/loading-jobs?graph=` See xref:tigergraph-server:API:gsql-endpoints.adoc#_create_loading_job[Create a loading job] """ - logger.info("entry: createLoadingJob") + logger.debug("entry: createLoadingJob") logger.debug("params: " + self._locals(locals())) @@ -238,7 +238,7 @@ async def createLoadingJob(self, job_definition: str) -> dict: res = self._req("POST", url, data=job_definition) logger.debug("return: " + str(res)) - logger.info("exit: createLoadingJob") + logger.debug("exit: createLoadingJob") return res @@ -253,7 +253,7 @@ async def updateLoadingJob(self, job_definition: str) -> dict: - `PUT /gsql/v1/loading-jobs/?graph=` See xref:tigergraph-server:API:gsql-endpoints.adoc#_upload_a_loading_job[Upload a loading job] """ - logger.info("entry: updateLoadingJob") + logger.debug("entry: updateLoadingJob") logger.debug("params: " + self._locals(locals())) @@ -262,7 +262,7 @@ async def updateLoadingJob(self, job_definition: str) -> dict: res = await self._req("PUT", url, data=job_definition) logger.debug("return: " + str(res)) - logger.info("exit: updateLoadingJob") + logger.debug("exit: updateLoadingJob") return res @@ -279,7 +279,7 @@ async def getLoadingJobInfo(self, jobName: str, verbose: bool = False) -> dict: - `GET /gsql/v1/loading-jobs/?graph=` See xref:tigergraph-server:API:gsql-endpoints.adoc#_get_loading_job_info[Get loading job info] """ - logger.info("entry: getLoadingJobInfo") + logger.debug("entry: getLoadingJobInfo") logger.debug("params: " + self._locals(locals())) @@ -288,7 +288,7 @@ async def getLoadingJobInfo(self, jobName: str, verbose: bool = False) -> dict: res = await self._req("GET", url) logger.debug("return: " + str(res)) - logger.info("exit: getLoadingJobInfo") + logger.debug("exit: getLoadingJobInfo") return res @@ -319,7 +319,7 @@ async def runLoadingJob(self, jobName: str, data_source_config: dict, sys_data_r - `POST /gsql/v1/loading-jobs/run?graph=` See xref:tigergraph-server:API:gsql-endpoints.adoc#_run_loading_job[Run a loading job] """ - logger.info("entry: runLoadingJob") + logger.debug("entry: runLoadingJob") logger.debug("params: " + self._locals(locals())) url, data = _prep_run_loading_job(self.gsUrl, self.graphname, jobName, data_source_config, sys_data_root, verbose, dryrun, interval, maxNumError, maxPercentError) @@ -327,7 +327,7 @@ async def runLoadingJob(self, jobName: str, data_source_config: dict, sys_data_r res = await self._req("POST", url, data=data) logger.debug("return: " + str(res)) - logger.info("exit: runLoadingJob") + logger.debug("exit: runLoadingJob") return res @@ -342,7 +342,7 @@ async def dropLoadingJob(self, jobName: str) -> dict: - `DELETE /gsql/v1/loading-jobs/?graph=` See xref:tigergraph-server:API:gsql-endpoints.adoc#_drop_a_loading_job[Drop a loading job] """ - logger.info("entry: dropLoadingJob") + logger.debug("entry: dropLoadingJob") logger.debug("params: " + self._locals(locals())) @@ -351,7 +351,7 @@ async def dropLoadingJob(self, jobName: str) -> dict: res = await self._req("DELETE", url) logger.debug("return: " + str(res)) - logger.info("exit: dropLoadingJob") + logger.debug("exit: dropLoadingJob") return res @@ -368,7 +368,7 @@ async def abortLoadingJobs(self, jobIds: list[str], pauseJob: bool = False) -> d - `POST /gsql/v1/loading-jobs/abort?graph=` See xref:tigergraph-server:API:gsql-endpoints.adoc#_abort_loading_jobs[Abort loading jobs] """ - logger.info("entry: abortLoadingJobs") + logger.debug("entry: abortLoadingJobs") logger.debug("params: " + self._locals(locals())) @@ -377,7 +377,7 @@ async def abortLoadingJobs(self, jobIds: list[str], pauseJob: bool = False) -> d res = await self._req("GET", url) logger.debug("return: " + str(res)) - logger.info("exit: abortLoadingJobs") + logger.debug("exit: abortLoadingJobs") return res @@ -394,7 +394,7 @@ async def abortLoadingJob(self, jobId: str, pauseJob: bool = False) -> dict: - `POST /gsql/v1/loading-jobs/abort?graph=` See xref:tigergraph-server:API:gsql-endpoints.adoc#_abort_one_loading_job """ - logger.info("entry: abortLoadingJob") + logger.debug("entry: abortLoadingJob") logger.debug("params: " + self._locals(locals())) @@ -403,7 +403,7 @@ async def abortLoadingJob(self, jobId: str, pauseJob: bool = False) -> dict: res = await self._req("GET", url) logger.debug("return: " + str(res)) - logger.info("exit: abortLoadingJob") + logger.debug("exit: abortLoadingJob") return res @@ -418,7 +418,7 @@ async def resumeLoadingJob(self, jobId: str) -> dict: - `POST /gsql/v1/loading-jobs/resume?graph=` See xref:tigergraph-server:API:gsql-endpoints.adoc#_resume_loading_job """ - logger.info("entry: resumeLoadingJob") + logger.debug("entry: resumeLoadingJob") logger.debug("params: " + self._locals(locals())) @@ -427,7 +427,7 @@ async def resumeLoadingJob(self, jobId: str) -> dict: res = await self._req("GET", url) logger.debug("return: " + str(res)) - logger.info("exit: resumeLoadingJob") + logger.debug("exit: resumeLoadingJob") return res @@ -442,7 +442,7 @@ async def getLoadingJobsStatus(self, jobIds: list[str]) -> dict: - `GET /gsql/v1/loading-jobs/status?graph=` See xref:tigergraph-server:API:gsql-endpoints.adoc#_get_loading_job_status[Get loading job status] """ - logger.info("entry: getLoadingJobsStatus") + logger.debug("entry: getLoadingJobsStatus") logger.debug("params: " + self._locals(locals())) @@ -451,7 +451,7 @@ async def getLoadingJobsStatus(self, jobIds: list[str]) -> dict: res = await self._req("GET", url) logger.debug("return: " + str(res)) - logger.info("exit: getLoadingJobsStatus") + logger.debug("exit: getLoadingJobsStatus") return res @@ -466,7 +466,7 @@ async def getLoadingJobStatus(self, jobId: str) -> dict: - `GET /gsql/v1/loading-jobs/status/?graph=` See xref:tigergraph-server:API:gsql-endpoints.adoc#_get_one_loading_job_status[Get one loading job status] """ - logger.info("entry: getLoadingJobStatus") + logger.debug("entry: getLoadingJobStatus") logger.debug("params: " + self._locals(locals())) @@ -475,6 +475,6 @@ async def getLoadingJobStatus(self, jobId: str) -> dict: res = await self._req("GET", url) logger.debug("return: " + str(res)) - logger.info("exit: getLoadingJobStatus") + logger.debug("exit: getLoadingJobStatus") return res diff --git a/pyTigerGraph/pytgasync/pyTigerGraphPath.py b/pyTigerGraph/pytgasync/pyTigerGraphPath.py index 2f357387..b4b69e71 100644 --- a/pyTigerGraph/pytgasync/pyTigerGraphPath.py +++ b/pyTigerGraph/pytgasync/pyTigerGraphPath.py @@ -62,7 +62,7 @@ async def shortestPath(self, sourceVertices: Union[dict, tuple, list], - `POST /shortestpath/{graphName}` See xref:tigergraph-server:API:built-in-endpoints.adoc#_find_shortest_path[Find the shortest path]. """ - logger.info("entry: shortestPath") + logger.debug("entry: shortestPath") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -72,7 +72,7 @@ async def shortestPath(self, sourceVertices: Union[dict, tuple, list], if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: shortestPath") + logger.debug("exit: shortestPath") return ret @@ -117,7 +117,7 @@ async def allPaths(self, sourceVertices: Union[dict, tuple, list], - `POST /allpaths/{graphName}` See xref:tigergraph-server:API:built-in-endpoints.adoc#_find_all_paths[Find all paths] """ - logger.info("entry: allPaths") + logger.debug("entry: allPaths") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -127,6 +127,6 @@ async def allPaths(self, sourceVertices: Union[dict, tuple, list], if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: allPaths") + logger.debug("exit: allPaths") return ret diff --git a/pyTigerGraph/pytgasync/pyTigerGraphQuery.py b/pyTigerGraph/pytgasync/pyTigerGraphQuery.py index 50d18c3e..6f7baee9 100644 --- a/pyTigerGraph/pytgasync/pyTigerGraphQuery.py +++ b/pyTigerGraph/pytgasync/pyTigerGraphQuery.py @@ -85,7 +85,7 @@ async def getInstalledQueries(self, fmt: str = "py") -> Union[dict, str, 'pd.Dat Modify to return only installed ones TODO Return with query name as key rather than REST endpoint as key? """ - logger.info("entry: getInstalledQueries") + logger.debug("entry: getInstalledQueries") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -94,7 +94,7 @@ async def getInstalledQueries(self, fmt: str = "py") -> Union[dict, str, 'pd.Dat if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getInstalledQueries") + logger.debug("exit: getInstalledQueries") return ret @@ -119,13 +119,13 @@ async def installQueries(self, queries: Union[str, list], flag: Union[str, list] GET /gsql/v1/queries/install See https://docs.tigergraph.com/tigergraph-server/current/api/built-in-endpoints#_install_a_query """ - logger.info("entry: installQueries") + logger.debug("entry: installQueries") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) self.ver = await self.getVer() major_ver, minor_ver, patch_ver = self.ver.split(".") if int(major_ver) < 4 or int(major_ver) == 4 and int(minor_ver) == 0: - logger.info("exit: installQueries") + logger.debug("exit: installQueries") raise TigerGraphException( "This function is only supported on versions of TigerGraph >= 4.1.0.", 0) @@ -153,7 +153,7 @@ async def installQueries(self, queries: Union[str, list], flag: Union[str, list] if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: installQueries") + logger.debug("exit: installQueries") return ret @@ -171,13 +171,13 @@ async def getQueryInstallationStatus(self, requestId: str) -> dict: GET /gsql/queries/install/{request_id} See https://docs.tigergraph.com/tigergraph-server/current/api/built-in-endpoints#_check_query_installation_status """ - logger.info("entry: getQueryInstallationStatus") + logger.debug("entry: getQueryInstallationStatus") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) self.ver = await self.getVer() major_ver, minor_ver, patch_ver = self.ver.split(".") if int(major_ver) < 4 or int(major_ver) == 4 and int(minor_ver) == 0: - logger.info("exit: getQueryInstallationStatus") + logger.debug("exit: getQueryInstallationStatus") raise TigerGraphException( "This function is only supported on versions of TigerGraph >= 4.1.0.", 0) @@ -185,7 +185,7 @@ async def getQueryInstallationStatus(self, requestId: str) -> dict: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getQueryInstallationStatus") + logger.debug("exit: getQueryInstallationStatus") return ret @@ -254,7 +254,7 @@ async def runInstalledQuery(self, queryName: str, params: Union[str, dict] = Non - `POST /query/{graph_name}/{query_name}` See xref:tigergraph-server:API:built-in-endpoints.adoc#_run_an_installed_query_post[Run an installed query (POST)] """ - logger.info("entry: runInstalledQuery") + logger.debug("entry: runInstalledQuery") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -267,7 +267,7 @@ async def runInstalledQuery(self, queryName: str, params: Union[str, dict] = Non if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: runInstalledQuery (POST)") + logger.debug("exit: runInstalledQuery (POST)") return ret else: @@ -278,7 +278,7 @@ async def runInstalledQuery(self, queryName: str, params: Union[str, dict] = Non if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: runInstalledQuery (GET)") + logger.debug("exit: runInstalledQuery (GET)") return ret @@ -359,7 +359,7 @@ async def runInterpretedQuery(self, queryText: str, params: Union[str, dict] = N TODO Add "GSQL-TIMEOUT: " and "RESPONSE-LIMIT: " plus parameters if applicable to interpreted queries (see runInstalledQuery() above) """ - logger.info("entry: runInterpretedQuery") + logger.debug("entry: runInterpretedQuery") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -378,7 +378,7 @@ async def runInterpretedQuery(self, queryText: str, params: Union[str, dict] = N if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: runInterpretedQuery") + logger.debug("exit: runInterpretedQuery") return ret @@ -436,7 +436,7 @@ async def getStatistics(self, seconds: int = 10, segments: int = 10) -> dict: - `GET /statistics/{graph_name}` See xref:tigergraph-server:API:built-in-endpoints.adoc#_show_query_performance[Show query performance] """ - logger.info("entry: getStatistics") + logger.debug("entry: getStatistics") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -446,7 +446,7 @@ async def getStatistics(self, seconds: int = 10, segments: int = 10) -> dict: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getStatistics") + logger.debug("exit: getStatistics") return ret @@ -468,11 +468,11 @@ async def describeQuery(self, queryName: str, queryDescription: str, parameterDe - `PUT /gsqlserver/gsql/description?graph={graph_name}` (In TigerGraph version 4.0) - `PUT /gsql/v1/description?graph={graph_name}` (In TigerGraph versions >4.0) """ - logger.info("entry: describeQuery") + logger.debug("entry: describeQuery") self.ver = await self.getVer() major_ver, minor_ver, patch_ver = self.ver.split(".") if int(major_ver) < 4: - logger.info("exit: describeQuery") + logger.debug("exit: describeQuery") raise TigerGraphException( "This function is only supported on versions of TigerGraph >= 4.0.0.", 0) @@ -496,7 +496,7 @@ async def describeQuery(self, queryName: str, queryDescription: str, parameterDe if logger.level == logging.DEBUG: logger.debug("return: " + str(res)) - logger.info("exit: describeQuery") + logger.debug("exit: describeQuery") return res @@ -516,11 +516,11 @@ async def getQueryDescription(self, queryName: Optional[Union[str, list]] = "all - `GET /gsqlserver/gsql/description?graph={graph_name}` (In TigerGraph version 4.0) - `GET /gsql/v1/description?graph={graph_name}` (In TigerGraph versions >4.0) """ - logger.info("entry: getQueryDescription") + logger.debug("entry: getQueryDescription") self.ver = await self.getVer() major_ver, minor_ver, patch_ver = self.ver.split(".") if int(major_ver) < 4: - logger.info("exit: getQueryDescription") + logger.debug("exit: getQueryDescription") raise TigerGraphException( "This function is only supported on versions of TigerGraph >= 4.0.0.", 0) @@ -558,11 +558,11 @@ async def dropQueryDescription(self, queryName: str, dropParamDescriptions: bool - `DELETE /gsqlserver/gsql/description?graph={graph_name}` (In TigerGraph version 4.0) - `DELETE /gsql/v1/description?graph={graph_name}` (In TigerGraph versions >4.0) """ - logger.info("entry: dropQueryDescription") + logger.debug("entry: dropQueryDescription") self.ver = await self.getVer() major_ver, minor_ver, patch_ver = self.ver.split(".") if int(major_ver) < 4: - logger.info("exit: describeQuery") + logger.debug("exit: describeQuery") raise TigerGraphException( "This function is only supported on versions of TigerGraph >= 4.0.0.", 0) @@ -581,6 +581,6 @@ async def dropQueryDescription(self, queryName: str, dropParamDescriptions: bool if logger.level == logging.DEBUG: logger.debug("return: " + str(res)) - logger.info("exit: dropQueryDescription") + logger.debug("exit: dropQueryDescription") return res diff --git a/pyTigerGraph/pytgasync/pyTigerGraphSchema.py b/pyTigerGraph/pytgasync/pyTigerGraphSchema.py index 4966ac99..1c8c8448 100644 --- a/pyTigerGraph/pytgasync/pyTigerGraphSchema.py +++ b/pyTigerGraph/pytgasync/pyTigerGraphSchema.py @@ -31,7 +31,7 @@ async def _getUDTs(self) -> dict: GET /gsqlserver/gsql/udtlist (In TigerGraph versions 3.x) GET /gsql/v1/udt/tuples (In TigerGraph versions 4.x) """ - logger.info("entry: _getUDTs") + logger.debug("entry: _getUDTs") if await self._version_greater_than_4_0(): res = await self._req("GET", self.gsUrl + "/gsql/v1/udt/tuples?graph=" + self.graphname, @@ -42,7 +42,7 @@ async def _getUDTs(self) -> dict: if logger.level == logging.DEBUG: logger.debug("return: " + str(res)) - logger.info("exit: _getUDTs") + logger.debug("exit: _getUDTs") return res @@ -65,7 +65,7 @@ async def getSchema(self, udts: bool = True, force: bool = False) -> dict: See xref:tigergraph-server:API:built-in-endpoints.adoc#_show_graph_schema_metadata[Show graph schema metadata] - `GET /gsql/v1/schema/graphs/{graph_name}` """ - logger.info("entry: getSchema") + logger.debug("entry: getSchema") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -81,7 +81,7 @@ async def getSchema(self, udts: bool = True, force: bool = False) -> dict: if logger.level == logging.DEBUG: logger.debug("return: " + str(self.schema)) - logger.info("exit: getSchema") + logger.debug("exit: getSchema") return self.schema @@ -95,7 +95,7 @@ async def getSchemaVer(self) -> int: - `POST /gsqlserver/interpreted_query` (In TigerGraph versions 3.x) - `POST /gsql/v1/queries/interpret` (In TigerGraph versions 4.x) """ - logger.info("entry: getSchemaVer") + logger.debug("entry: getSchemaVer") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -121,7 +121,7 @@ async def getSchemaVer(self) -> int: logger.warning(f"Schema version '{schema_version}' could not be converted to integer") if schema_version_int is None: logger.warning("Schema version not found in query result") - logger.info("exit: _get_schema_ver") + logger.debug("exit: _get_schema_ver") return schema_version_int except Exception as e: @@ -162,7 +162,7 @@ async def upsertData(self, data: Union[str, object], atomic: bool = False, ackAl - `POST /graph/{graph_name}` See xref:tigergraph-server:API:built-in-endpoints.adoc#_upsert_data_to_graph[Upsert data to graph] """ - logger.info("entry: upsertData") + logger.debug("entry: upsertData") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -175,7 +175,7 @@ async def upsertData(self, data: Union[str, object], atomic: bool = False, ackAl if logger.level == logging.DEBUG: logger.debug("return: " + str(res)) - logger.info("exit: upsertData") + logger.debug("exit: upsertData") return res @@ -197,7 +197,7 @@ async def getEndpoints(self, builtin: bool = False, dynamic: bool = False, - `GET /endpoints/{graph_name}` See xref:tigergraph-server:API:built-in-endpoints.adoc#_list_all_endpoints[List all endpoints] """ - logger.info("entry: getEndpoints") + logger.debug("entry: getEndpoints") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -227,7 +227,7 @@ async def getEndpoints(self, builtin: bool = False, dynamic: bool = False, if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getEndpoints") + logger.debug("exit: getEndpoints") return ret diff --git a/pyTigerGraph/pytgasync/pyTigerGraphUDT.py b/pyTigerGraph/pytgasync/pyTigerGraphUDT.py index 7976e147..76bd2582 100644 --- a/pyTigerGraph/pytgasync/pyTigerGraphUDT.py +++ b/pyTigerGraph/pytgasync/pyTigerGraphUDT.py @@ -22,7 +22,7 @@ async def getUDTs(self) -> list: Returns: The list of names of UDTs (defined in the global scope, i.e. not in queries). """ - logger.info("entry: getUDTs") + logger.debug("entry: getUDTs") ret = [] for udt in await self._getUDTs(): @@ -30,7 +30,7 @@ async def getUDTs(self) -> list: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getUDTs") + logger.debug("exit: getUDTs") return ret @@ -47,7 +47,7 @@ async def getUDT(self, udtName: str) -> list: The metadata (the details of the fields) of the UDT. """ - logger.info("entry: getUDT") + logger.debug("entry: getUDT") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -57,12 +57,12 @@ async def getUDT(self, udtName: str) -> list: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getUDT (found)") + logger.debug("exit: getUDT (found)") return ret if logger.level == logging.DEBUG: logger.warning("UDT `" + udtName + "` was not found") - logger.info("exit: getUDT (not found)") + logger.debug("exit: getUDT (not found)") return [] # UDT was not found diff --git a/pyTigerGraph/pytgasync/pyTigerGraphUtils.py b/pyTigerGraph/pytgasync/pyTigerGraphUtils.py index d273160b..781eaec1 100644 --- a/pyTigerGraph/pytgasync/pyTigerGraphUtils.py +++ b/pyTigerGraph/pytgasync/pyTigerGraphUtils.py @@ -36,7 +36,7 @@ async def echo(self, usePost: bool = False) -> str: - `POST /echo` See xref:tigergraph-server:API:built-in-endpoints.adoc#_echo[Echo] """ - logger.info("entry: echo") + logger.debug("entry: echo") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -45,7 +45,7 @@ async def echo(self, usePost: bool = False) -> str: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: echo (POST)") + logger.debug("exit: echo (POST)") return ret @@ -53,7 +53,7 @@ async def echo(self, usePost: bool = False) -> str: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: echo (GET)") + logger.debug("exit: echo (GET)") return ret @@ -64,14 +64,14 @@ async def getLicenseInfo(self) -> dict: Returns license details. For an evaluation/trial deployment, returns an information message and -1 remaining days. """ - logger.info("entry: getLicenseInfo") + logger.debug("entry: getLicenseInfo") res = await self._req("GET", self.restppUrl + "/showlicenseinfo", resKey="", skipCheck=True) ret = _parse_get_license_info(res) if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getLicenseInfo") + logger.debug("exit: getLicenseInfo") return ret diff --git a/pyTigerGraph/pytgasync/pyTigerGraphVertex.py b/pyTigerGraph/pytgasync/pyTigerGraphVertex.py index ac1ffae9..840a742d 100644 --- a/pyTigerGraph/pytgasync/pyTigerGraphVertex.py +++ b/pyTigerGraph/pytgasync/pyTigerGraphVertex.py @@ -48,7 +48,7 @@ async def getVertexTypes(self, force: bool = False) -> list: Returns: The list of vertex types defined in the current graph. """ - logger.info("entry: getVertexTypes") + logger.debug("entry: getVertexTypes") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -60,7 +60,7 @@ async def getVertexTypes(self, force: bool = False) -> list: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getVertexTypes") + logger.debug("exit: getVertexTypes") return ret @@ -79,7 +79,7 @@ async def getVertexAttrs(self, vertexType: str) -> list: - "map_type(key_type,value_type)" and it is a string. """ - logger.info("entry: getAttributes") + logger.debug("entry: getAttributes") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -94,7 +94,7 @@ async def getVertexAttrs(self, vertexType: str) -> list: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getAttributes") + logger.debug("exit: getAttributes") return ret @@ -113,7 +113,7 @@ async def getVertexVectors(self, vertexType: str) -> list: - "map_type(key_type,value_type)" and it is a string. """ - logger.info("entry: getVertexVectors") + logger.debug("entry: getVertexVectors") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -128,7 +128,7 @@ async def getVertexVectors(self, vertexType: str) -> list: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getVertexVectors") + logger.debug("exit: getVertexVectors") return ret @@ -147,7 +147,7 @@ async def getVectorStatus(self, vertexType: str, vectorName: str = "") -> bool: Endpoint: - `GET /vector/status/{graph_name}/{vertex_type}/[{vector_name}]` """ - logger.info("entry: getVectorStatus") + logger.debug("entry: getVectorStatus") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -156,7 +156,7 @@ async def getVectorStatus(self, vertexType: str, vectorName: str = "") -> bool: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getVectorStatus") + logger.debug("exit: getVectorStatus") return len(ret["NeedRebuildServers"]) == 0 @@ -173,7 +173,7 @@ async def getVertexType(self, vertexType: str, force: bool = False) -> dict: Returns: The metadata of the vertex type. """ - logger.info("entry: getVertexType") + logger.debug("entry: getVertexType") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -183,12 +183,12 @@ async def getVertexType(self, vertexType: str, force: bool = False) -> dict: if vt["Name"] == vertexType: if logger.level == logging.DEBUG: logger.debug("return: " + str(vt)) - logger.info("exit: getVertexType (found)") + logger.debug("exit: getVertexType (found)") return vt logger.warning("Vertex type `" + vertexType + "` was not found.") - logger.info("exit: getVertexType (not found)") + logger.debug("exit: getVertexType (not found)") return {} # Vertex type was not found @@ -229,7 +229,7 @@ async def getVertexCount(self, vertexType: Union[str, list] = "*", where: str = - `POST /builtins` See xref:tigergraph-server:API:built-in-endpoints.adoc#_run_built_in_functions_on_graph[Run built-in functions] """ - logger.info("entry: getVertexCount") + logger.debug("entry: getVertexCount") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -249,7 +249,7 @@ async def getVertexCount(self, vertexType: Union[str, list] = "*", where: str = if logger.level == logging.DEBUG: logger.debug("return: " + str(res)) - logger.info("exit: getVertexCount (1)") + logger.debug("exit: getVertexCount (1)") return res @@ -261,7 +261,7 @@ async def getVertexCount(self, vertexType: Union[str, list] = "*", where: str = if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getVertexCount (2)") + logger.debug("exit: getVertexCount (2)") return ret @@ -297,7 +297,7 @@ async def upsertVertex(self, vertexType: str, vertexId: str, attributes: dict = - `POST /graph/{graph_name}` See xref:tigergraph-server:API:built-in-endpoints.adoc#_upsert_data_to_graph[Upsert data to graph] """ - logger.info("entry: upsertVertex") + logger.debug("entry: upsertVertex") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -309,7 +309,7 @@ async def upsertVertex(self, vertexType: str, vertexId: str, attributes: dict = if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: upsertVertex") + logger.debug("exit: upsertVertex") return ret @@ -358,7 +358,7 @@ async def upsertVertices(self, vertexType: str, vertices: list, atomic: bool = F - `POST /graph/{graph_name}` See xref:tigergraph-server:API:built-in-endpoints.adoc#_upsert_data_to_graph[Upsert data to graph] """ - logger.info("entry: upsertVertices") + logger.debug("entry: upsertVertices") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -377,7 +377,7 @@ async def upsertVertices(self, vertexType: str, vertices: list, atomic: bool = F if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: upsertVertices") + logger.debug("exit: upsertVertices") return ret @@ -407,7 +407,7 @@ async def upsertVertexDataFrame(self, df: 'pd.DataFrame', vertexType: str, v_id: Returns: The number of vertices upserted. """ - logger.info("entry: upsertVertexDataFrame") + logger.debug("entry: upsertVertexDataFrame") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -417,7 +417,7 @@ async def upsertVertexDataFrame(self, df: 'pd.DataFrame', vertexType: str, v_id: if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: upsertVertexDataFrame") + logger.debug("exit: upsertVertexDataFrame") return ret @@ -466,7 +466,7 @@ async def getVertices(self, vertexType: str, select: str = "", where: str = "", - `GET /graph/{graph_name}/vertices/{vertex_type}` See xref:tigergraph-server:API:built-in-endpoints.adoc#_list_vertices[List vertices] """ - logger.info("entry: getVertices") + logger.debug("entry: getVertices") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -489,7 +489,7 @@ async def getVertices(self, vertexType: str, select: str = "", where: str = "", if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getVertices") + logger.debug("exit: getVertices") return ret @@ -526,7 +526,7 @@ async def getVertexDataFrame(self, vertexType: str, select: str = "", where: str The (selected) details of the (matching) vertex instances (sorted, limited) as pandas DataFrame. """ - logger.info("entry: getVertexDataFrame") + logger.debug("entry: getVertexDataFrame") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -535,7 +535,7 @@ async def getVertexDataFrame(self, vertexType: str, select: str = "", where: str if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getVertexDataFrame") + logger.debug("exit: getVertexDataFrame") return ret @@ -586,7 +586,7 @@ async def getVerticesById(self, vertexType: str, vertexIds: Union[int, str, list TODO Find out how/if select and timeout can be specified """ - logger.info("entry: getVerticesById") + logger.debug("entry: getVerticesById") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -608,7 +608,7 @@ async def getVerticesById(self, vertexType: str, vertexIds: Union[int, str, list if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getVerticesById") + logger.debug("exit: getVerticesById") return ret @@ -629,7 +629,7 @@ async def getVertexDataFrameById(self, vertexType: str, vertexIds: Union[int, st Returns: The (selected) details of the (matching) vertex instances as pandas DataFrame. """ - logger.info("entry: getVertexDataFrameById") + logger.debug("entry: getVertexDataFrameById") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -638,7 +638,7 @@ async def getVertexDataFrameById(self, vertexType: str, vertexIds: Union[int, st if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getVertexDataFrameById") + logger.debug("exit: getVertexDataFrameById") return ret @@ -672,7 +672,7 @@ async def getVertexStats(self, vertexTypes: Union[str, list], skipNA: bool = Fal - `POST /builtins/{graph_name}` See xref:tigergraph-server:API:built-in-endpoints.adoc#_run_built_in_functions_on_graph[Run built-in functions] """ - logger.info("entry: getVertexStats") + logger.debug("entry: getVertexStats") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -695,7 +695,7 @@ async def getVertexStats(self, vertexTypes: Union[str, list], skipNA: bool = Fal if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: getVertexStats") + logger.debug("exit: getVertexStats") return ret @@ -737,7 +737,7 @@ async def delVertices(self, vertexType: str, where: str = "", limit: str = "", s - `DELETE /graph/{graph_name}/vertices/{vertex_type}` See xref:tigergraph-server:API:built-in-endpoints.adoc#_delete_vertices[Delete vertices] """ - logger.info("entry: delVertices") + logger.debug("entry: delVertices") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -756,7 +756,7 @@ async def delVertices(self, vertexType: str, where: str = "", limit: str = "", s if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: delVertices") + logger.debug("exit: delVertices") return ret @@ -782,7 +782,7 @@ async def delVerticesById(self, vertexType: str, vertexIds: Union[int, str, list - `DELETE /graph/{graph_name}/vertices/{vertex_type}/{vertex_id}` See xref:tigergraph-server:API:built-in-endpoints.adoc#_delete_a_vertex[Delete a vertex] """ - logger.info("entry: delVerticesById") + logger.debug("entry: delVerticesById") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -801,7 +801,7 @@ async def delVerticesById(self, vertexType: str, vertexIds: Union[int, str, list if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: delVerticesById") + logger.debug("exit: delVerticesById") return ret @@ -828,7 +828,7 @@ async def delVerticesByType(self, vertexType: str, permanent: bool = False, ack: ``` """ - logger.info("entry: delVerticesByType") + logger.debug("entry: delVerticesByType") logger.debug("params: " + str(locals())) if ack.lower() not in ["none", "all"]: raise TigerGraphException("Invalid value for ack parameter. Use 'none' or 'all'.", None) @@ -844,7 +844,7 @@ async def delVerticesByType(self, vertexType: str, permanent: bool = False, ack: ret = await self._delete(url)["deleted_vertices"] logger.debug("return: " + str(ret)) - logger.info("exit: delVerticesByType") + logger.debug("exit: delVerticesByType") return ret @@ -865,7 +865,7 @@ async def vertexSetToDataFrame(self, vertexSet: dict, withId: bool = True, withT Returns: The vertex set as a pandas DataFrame. """ - logger.info("entry: vertexSetToDataFrame") + logger.debug("entry: vertexSetToDataFrame") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -873,6 +873,6 @@ async def vertexSetToDataFrame(self, vertexSet: dict, withId: bool = True, withT if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) - logger.info("exit: vertexSetToDataFrame") + logger.debug("exit: vertexSetToDataFrame") return ret From 696a13836d7b1c6f8331c9066153afe134f6b184 Mon Sep 17 00:00:00 2001 From: Chengbiao Jin Date: Tue, 28 Oct 2025 14:50:07 -0700 Subject: [PATCH 06/10] GML-1995 Fix vertex id handling, add more endpoints and deprecate authMode --- pyTigerGraph/common/base.py | 19 +- pyTigerGraph/common/query.py | 4 +- pyTigerGraph/pyTigerGraphQuery.py | 228 +++++++++++++++++- pyTigerGraph/pyTigerGraphSchema.py | 210 ++++++++++++++++- pyTigerGraph/pytgasync/pyTigerGraphQuery.py | 235 ++++++++++++++++++- pyTigerGraph/pytgasync/pyTigerGraphSchema.py | 210 ++++++++++++++++- tests/test_pyTigerGraphQuery.py | 79 +++++++ tests/test_pyTigerGraphQueryAsync.py | 79 +++++++ tests/test_pyTigerGraphSchema.py | 156 ++++++++++++ tests/test_pyTigerGraphSchemaAsync.py | 156 ++++++++++++ 10 files changed, 1353 insertions(+), 23 deletions(-) diff --git a/pyTigerGraph/common/base.py b/pyTigerGraph/common/base.py index 6779fbe7..31a9088c 100644 --- a/pyTigerGraph/common/base.py +++ b/pyTigerGraph/common/base.py @@ -111,7 +111,7 @@ def __init__(self, host: str = "http://127.0.0.1", graphname: str = "", "{0}:{1}".format(self.username, self.password).encode("utf-8")).decode("utf-8") # Detect auth mode automatically by checking if jwtToken or apiToken is provided - self.authHeader, self.authMode = self._set_auth_header() + self.authHeader = self._set_auth_header() # TODO Eliminate version and use gsqlVersion only, meaning TigerGraph server version if gsqlVersion: @@ -217,11 +217,14 @@ def __init__(self, host: str = "http://127.0.0.1", graphname: str = "", def _set_auth_header(self): """Set the authentication header based on available tokens or credentials.""" if self.jwtToken: - return {"Authorization": "Bearer " + self.jwtToken}, "token" + self.authMode = "token" + return {"Authorization": "Bearer " + self.jwtToken} elif self.apiToken: - return {"Authorization": "Bearer " + self.apiToken}, "token" + self.authMode = "token" + return {"Authorization": "Bearer " + self.apiToken} else: - return {"Authorization": "Basic {0}".format(self.base64_credential)}, "pwd" + self.authMode = "pwd" + return {"Authorization": "Basic {0}".format(self.base64_credential)} def _verify_jwt_token_support(self): try: @@ -277,7 +280,7 @@ def _error_check(self, res: dict) -> bool: return False def _prep_req(self, headers, url, method, data): - logger.debug("entry: _req") + logger.debug("entry: _prep_req") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -322,10 +325,12 @@ def _prep_req(self, headers, url, method, data): verify = True _headers.update({"X-User-Agent": "pyTigerGraph"}) + logger.debug("exit: _prep_req") return _headers, _data, verify def _parse_req(self, res, jsonResponse, strictJson, skipCheck, resKey): + logger.debug("entry: _parse_req") if jsonResponse: try: res = json.loads(res.text, strict=strictJson) @@ -339,7 +344,7 @@ def _parse_req(self, res, jsonResponse, strictJson, skipCheck, resKey): if not resKey: if logger.level == logging.DEBUG: logger.debug("return: " + str(res)) - logger.debug("exit: _req (no resKey)") + logger.debug("exit: _parse_req (no resKey)") return res @@ -348,7 +353,7 @@ def _parse_req(self, res, jsonResponse, strictJson, skipCheck, resKey): logger.info("Removed _ from resKey") if logger.level == logging.DEBUG: logger.debug("return: " + str(res[resKey])) - logger.debug("exit: _req (resKey)") + logger.debug("exit: _parse_req (resKey)") return res[resKey] diff --git a/pyTigerGraph/common/query.py b/pyTigerGraph/common/query.py index 6d46dfe7..7b5b3655 100644 --- a/pyTigerGraph/common/query.py +++ b/pyTigerGraph/common/query.py @@ -73,7 +73,7 @@ def _parse_query_parameters(params: dict) -> str: if isinstance(vv, tuple): if len(vv) == 2 and isinstance(vv[1], str): ret += k + "[" + str(i) + "]=" + _safe_char(vv[0]) + "&" + \ - k + "[" + str(i) + "].type=" + _safe_char(vv[1]) + "&" + k + "[" + str(i) + "].type=" + vv[1] + "&" else: raise TigerGraphException( "Invalid parameter value: (vertex_primary_id, vertex_type)" @@ -86,7 +86,7 @@ def _parse_query_parameters(params: dict) -> str: _safe_char(v.strftime("%Y-%m-%d %H:%M:%S")) + "&" else: ret += k + "=" + _safe_char(v) + "&" - if not ret: + if ret: ret = ret[:-1] if logger.level == logging.DEBUG: diff --git a/pyTigerGraph/pyTigerGraphQuery.py b/pyTigerGraph/pyTigerGraphQuery.py index d0047621..d268ffc5 100644 --- a/pyTigerGraph/pyTigerGraphQuery.py +++ b/pyTigerGraph/pyTigerGraphQuery.py @@ -72,6 +72,202 @@ def getQueryMetadata(self, queryName: str) -> dict: else: TigerGraphException(res["message"], res["code"]) + def getQueryContent(self, queryName: str) -> dict: + """Returns the content/source code of a query. + + Args: + queryName (str): + Name of the query to get content of. + + Returns: + The response from the database containing the query content. + + Endpoints: + - `GET /gsql/v1/queries/{queryName}` (In TigerGraph versions >= 4.0) + """ + logger.debug("entry: getQueryContent") + if not self._version_greater_than_4_0(): + logger.debug("exit: getQueryContent") + raise TigerGraphException( + "This function is only supported on versions of TigerGraph >= 4.0.", 0) + + params = {"graph": self.graphname} + res = self._get(self.gsUrl+"/gsql/v1/queries/"+queryName, + params=params, authMode="pwd", resKey="", headers={'Content-Type': 'application/json'}) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: getQueryContent") + + return res + + def createQuery(self, queryText: str) -> dict: + """Creates a query in the graph. + + Args: + queryText (str): + The text of the GSQL query to create. Must be in the format: + "create query queryName (...) FOR GRAPH graphName { ... }" + + Returns: + The response from the database containing the creation result. + + Endpoints: + - `POST /gsql/v1/queries` (In TigerGraph versions >= 4.0) + """ + logger.debug("entry: createQuery") + if not self._version_greater_than_4_0(): + logger.debug("exit: createQuery") + raise TigerGraphException( + "This function is only supported on versions of TigerGraph >= 4.0.", 0) + + # Replace graphname placeholders + queryText = queryText.replace("$graphname", self.graphname) + queryText = queryText.replace("@graphname@", self.graphname) + + params = {"graph": self.graphname} + res = self._post(self.gsUrl+"/gsql/v1/queries", + params=params, data=queryText, authMode="pwd", + headers={'Content-Type': 'text/plain'}) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: createQuery") + + return res + + def dropQueries(self, queryName: Union[str, list]) -> dict: + """Drops one or more queries from the graph. + + Args: + queryName (str or list): + Name of the query to drop, or list of query names to drop. + + Returns: + The response from the database containing the drop result. + + Endpoints: + - `DELETE /gsql/v1/queries/{queryName}` (In TigerGraph versions >= 4.0) + """ + logger.debug("entry: dropQueries") + if not self._version_greater_than_4_0(): + logger.debug("exit: dropQueries") + raise TigerGraphException( + "This function is only supported on versions of TigerGraph >= 4.0.", 0) + + # Handle single query name + if isinstance(queryName, str): + params = {"graph": self.graphname} + res = self._delete(self.gsUrl+"/gsql/v1/queries/"+queryName, + params=params, authMode="pwd", resKey="", headers={'Content-Type': 'application/json'}) + # Handle list of query names + elif isinstance(queryName, list): + if not queryName: + raise TigerGraphException("Query name list cannot be empty.", 0) + + params = {"graph": self.graphname, "query": queryName} + res = self._delete(self.gsUrl+"/gsql/v1/queries", + params=params, authMode="pwd", resKey="", headers={'Content-Type': 'application/json'}) + else: + raise TigerGraphException("queryName must be a string or list of strings.", 0) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: dropQueries") + + return res + + def checkQuerySemantic(self, queryCode: str) -> dict: + """Performs a semantic check of a query. + + Args: + queryCode (str): + The GSQL query code to check for semantic errors. + + Returns: + The response from the database containing the semantic check result. + + Endpoints: + - `POST /gsql/v1/internal/check/query` (In TigerGraph versions >= 4.0) + """ + logger.debug("entry: checkQuerySemantic") + if not self._version_greater_than_4_0(): + logger.debug("exit: checkQuerySemantic") + raise TigerGraphException( + "This function is only supported on versions of TigerGraph >= 4.0.", 0) + + data = {"code": queryCode} + res = self._post(self.gsUrl+"/gsql/v1/internal/check/query", + data=data, authMode="pwd", resKey="", + headers={'Content-Type': 'application/json'}) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: checkQuerySemantic") + + return res + + def getQueryInfo(self, queryName: str = None, status: str = None) -> dict: + """Gets query information for the graph. + + Args: + queryName (str, optional): + The specific query name to get information for. If None, returns info for all queries. + status (str, optional): + Filter queries by status (e.g., "VALID", "INVALID", "INSTALLING"). + + Returns: + The response from the database containing query information. + + Endpoints: + - `GET /gsql/v1/queries/info` (In TigerGraph versions >= 4.0) + """ + logger.debug("entry: getQueryInfo") + if not self._version_greater_than_4_0(): + logger.debug("exit: getQueryInfo") + raise TigerGraphException( + "This function is only supported on versions of TigerGraph >= 4.0.", 0) + + params = {"graph": self.graphname} + if queryName is not None: + params["query"] = queryName + if status is not None: + params["status"] = status + + res = self._get(self.gsUrl+"/gsql/v1/queries/info", + params=params, authMode="pwd", resKey="", headers={'Content-Type': 'application/json'}) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: getQueryInfo") + + return res + + def listQueryNames(self) -> list: + """Lists all query names of a graph. + + Returns: + The response from the database containing the list of query names. + + Endpoints: + - `GET /gsql/v1/queries` (In TigerGraph versions >= 4.0) + """ + logger.debug("entry: listQueryNames") + if not self._version_greater_than_4_0(): + logger.debug("exit: listQueryNames") + raise TigerGraphException( + "This function is only supported on versions of TigerGraph >= 4.0.", 0) + + params = {"graph": self.graphname} + res = self._get(self.gsUrl+"/gsql/v1/queries", + params=params, authMode="pwd", headers={'Content-Type': 'application/json'}) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: listQueryNames") + + return res + def getInstalledQueries(self, fmt: str = "py") -> Union[dict, str, 'pd.DataFrame']: """Returns a list of installed queries. @@ -265,8 +461,10 @@ def runInstalledQuery(self, queryName: str, params: Union[str, dict] = None, return ret else: - if isinstance(params, dict): - params = _parse_query_parameters(params) + if params: + if isinstance(params, dict): + params = _parse_query_parameters(params) + logger.info("params: " + params) ret = self._req("GET", self.restppUrl + "/query/" + self.graphname + "/" + queryName, params=params, headers=headers, resKey=res_key) @@ -609,6 +807,26 @@ def getStatistics(self, seconds: int = 10, segments: int = 10) -> dict: return ret def describeQuery(self, queryName: str, queryDescription: str, parameterDescriptions: dict = {}): + """DEPRECATED: Use updateQueryDescription() instead. Add a query description and parameter descriptions. Only supported on versions of TigerGraph >= 4.0.0. + + Args: + queryName: + The name of the query to describe. + queryDescription: + A description of the query. + parameterDescriptions (optional): + A dictionary of parameter descriptions. The keys are the parameter names and the values are the descriptions. + + Returns: + The response from the database. + + Endpoints: + - `PUT /gsqlserver/gsql/description?graph={graph_name}` (In TigerGraph version 4.0) + - `PUT /gsql/v1/description?graph={graph_name}` (In TigerGraph versions >4.0) + """ + return self.updateQueryDescription(queryName, queryDescription, parameterDescriptions) + + def updateQueryDescription(self, queryName: str, queryDescription: str, parameterDescriptions: dict = {}): """Add a query description and parameter descriptions. Only supported on versions of TigerGraph >= 4.0.0. Args: @@ -626,11 +844,11 @@ def describeQuery(self, queryName: str, queryDescription: str, parameterDescript - `PUT /gsqlserver/gsql/description?graph={graph_name}` (In TigerGraph version 4.0) - `PUT /gsql/v1/description?graph={graph_name}` (In TigerGraph versions >4.0) """ - logger.debug("entry: describeQuery") + logger.debug("entry: updateQueryDescription") self.ver = self.getVer() major_ver, minor_ver, patch_ver = self.ver.split(".") if int(major_ver) < 4: - logger.debug("exit: describeQuery") + logger.debug("exit: updateQueryDescription") raise TigerGraphException( "This function is only supported on versions of TigerGraph >= 4.0.0.", 0) @@ -656,7 +874,7 @@ def describeQuery(self, queryName: str, queryDescription: str, parameterDescript if logger.level == logging.DEBUG: logger.debug("return: " + str(res)) - logger.debug("exit: describeQuery") + logger.debug("exit: updateQueryDescription") return res diff --git a/pyTigerGraph/pyTigerGraphSchema.py b/pyTigerGraph/pyTigerGraphSchema.py index a0901272..d3ddb613 100644 --- a/pyTigerGraph/pyTigerGraphSchema.py +++ b/pyTigerGraph/pyTigerGraphSchema.py @@ -230,4 +230,212 @@ def getEndpoints(self, builtin: bool = False, dynamic: bool = False, return ret - # TODO GET /rebuildnow/{graph_name} + def createGlobalVertices(self, gsql_commands: Union[str, list]) -> dict: + """Creates global vertices using GSQL commands. + + Args: + gsql_commands (str or list): + GSQL CREATE VERTEX statement(s). Can be a single string or list of strings. + + Returns: + The response from the database containing the creation result. + + Endpoints: + - `POST /gsql/v1/schema/vertices` (In TigerGraph versions >= 4.0) + """ + logger.debug("entry: createGlobalVertices") + if not self._version_greater_than_4_0(): + logger.debug("exit: createGlobalVertices") + raise TigerGraphException( + "This function is only supported on versions of TigerGraph >= 4.0.", 0) + + # Handle single command + if isinstance(gsql_commands, str): + gsql_commands = [gsql_commands] + elif not isinstance(gsql_commands, list): + raise TigerGraphException("gsql_commands must be a string or list of strings.", 0) + + if not gsql_commands: + raise TigerGraphException("gsql_commands cannot be empty.", 0) + + # Validate that all commands are CREATE VERTEX statements + for cmd in gsql_commands: + if not cmd.strip().upper().startswith("CREATE VERTEX"): + raise TigerGraphException(f"Invalid GSQL command: {cmd}. Must be a CREATE VERTEX statement.", 0) + + data = {"gsql": gsql_commands} + params = {"gsql": "true"} + res = self._post(self.gsUrl+"/gsql/v1/schema/vertices", + params=params, data=data, authMode="pwd", resKey="", + headers={'Content-Type': 'application/json'}) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: createGlobalVertices") + + return res + + def createGlobalVerticesJson(self, vertices_config: Union[dict, list]) -> dict: + """Creates global vertices using JSON configuration. + + Args: + vertices_config (dict or list): + JSON configuration for vertex creation. Can be a single vertex config dict + or a list of vertex config dicts. Each vertex config should include: + - Name: Vertex type name + - PrimaryId: Primary ID configuration with AttributeType and AttributeName + - Attributes: List of attribute configurations + - Config: Optional configuration (e.g., STATS) + + Returns: + The response from the database containing the creation result. + + Endpoints: + - `POST /gsql/v1/schema/vertices` (In TigerGraph versions >= 4.0) + """ + logger.debug("entry: createGlobalVerticesJson") + if not self._version_greater_than_4_0(): + logger.debug("exit: createGlobalVerticesJson") + raise TigerGraphException( + "This function is only supported on versions of TigerGraph >= 4.0.", 0) + + # Handle single vertex config + if isinstance(vertices_config, dict): + vertices_config = [vertices_config] + elif not isinstance(vertices_config, list): + raise TigerGraphException("vertices_config must be a dict or list of dicts.", 0) + + if not vertices_config: + raise TigerGraphException("vertices_config cannot be empty.", 0) + + # Validate vertex configurations + for i, vertex_config in enumerate(vertices_config): + if not isinstance(vertex_config, dict): + raise TigerGraphException(f"Vertex config at index {i} must be a dict.", 0) + + required_fields = ["Name", "PrimaryId", "Attributes"] + for field in required_fields: + if field not in vertex_config: + raise TigerGraphException(f"Vertex config at index {i} missing required field: {field}", 0) + + data = {"createVertices": vertices_config} + res = self._post(self.gsUrl+"/gsql/v1/schema/vertices", + data=data, authMode="pwd", resKey="", + headers={'Content-Type': 'application/json'}) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: createGlobalVerticesJson") + + return res + + def addGlobalVerticesToGraph(self, vertex_names: Union[str, list], target_graph: str = None) -> dict: + """Adds existing global vertices to a local graph. + + Args: + vertex_names (str or list): + Name(s) of the global vertices to add to the graph. Can be a single + vertex name string or a list of vertex names. + target_graph (str, optional): + The graph to which the global vertices should be added. If not provided, + uses the current connection's graphname. + + Returns: + The response from the database containing the addition result. + + Endpoints: + - `POST /gsql/v1/schema/vertices` (In TigerGraph versions >= 4.0) + """ + logger.debug("entry: addGlobalVerticesToGraph") + if not self._version_greater_than_4_0(): + logger.debug("exit: addGlobalVerticesToGraph") + raise TigerGraphException( + "This function is only supported on versions of TigerGraph >= 4.0.", 0) + + # Handle single vertex name + if isinstance(vertex_names, str): + vertex_names = [vertex_names] + elif not isinstance(vertex_names, list): + raise TigerGraphException("vertex_names must be a string or list of strings.", 0) + + if not vertex_names: + raise TigerGraphException("vertex_names cannot be empty.", 0) + + # Validate that all items are strings + for i, name in enumerate(vertex_names): + if not isinstance(name, str): + raise TigerGraphException(f"Vertex name at index {i} must be a string.", 0) + + # Use target_graph or current graphname + graph_name = target_graph if target_graph is not None else self.graphname + + data = {"addVertices": vertex_names} + params = {"graph": graph_name} + res = self._post(self.gsUrl+"/gsql/v1/schema/vertices", + params=params, data=data, authMode="pwd", resKey="", + headers={'Content-Type': 'application/json'}) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: addGlobalVerticesToGraph") + + return res + + def rebuildGraphEngine(self, threadnum: int = None, vertextype: str = None, + segid: int = None, path: str = None, force: bool = None) -> dict: + """Rebuilds the graph engine. + + When new data is being loaded into the graph (such as new vertices or edges), + the data is initially stored in memory before being saved permanently to disk. + TigerGraph runs a rebuild of the Graph Processing Engine (GPE) to commit the + data in memory to disk. + + Args: + threadnum (int, optional): + Number of threads used to execute the rebuild. If not specified, + the number specified in the .tg.cfg file will be used (default: 3). + vertextype (str, optional): + Vertex type to perform the rebuild for. If not provided, the rebuild + will be run for all vertex types. + segid (int, optional): + Segment ID of the segments to rebuild. If not provided, all segments + will be rebuilt. + path (str, optional): + Path to save the summary of the rebuild to. If not provided, the + default path is /tmp/rebuildnow. + force (bool, optional): + Boolean value that indicates whether to perform rebuilds for segments + for which there are no records of new data. + + Returns: + The response from the database containing the rebuild result. + + Endpoints: + - `GET /restpp/rebuildnow/{graph_name}` (In TigerGraph versions >= 4.0) + """ + logger.debug("entry: rebuildGraphEngine") + if not self._version_greater_than_4_0(): + logger.debug("exit: rebuildGraphEngine") + raise TigerGraphException( + "This function is only supported on versions of TigerGraph >= 4.0.", 0) + + params = {} + if threadnum is not None: + params["threadnum"] = threadnum + if vertextype is not None: + params["vertextype"] = vertextype + if segid is not None: + params["segid"] = segid + if path is not None: + params["path"] = path + if force is not None: + params["force"] = force + + res = self._get(self.restppUrl+"/rebuildnow/"+self.graphname, + params=params, authMode="pwd", resKey="") + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: rebuildGraphEngine") + + return res diff --git a/pyTigerGraph/pytgasync/pyTigerGraphQuery.py b/pyTigerGraph/pytgasync/pyTigerGraphQuery.py index 6f7baee9..825b5108 100644 --- a/pyTigerGraph/pytgasync/pyTigerGraphQuery.py +++ b/pyTigerGraph/pytgasync/pyTigerGraphQuery.py @@ -68,6 +68,202 @@ async def getQueryMetadata(self, queryName: str) -> dict: else: TigerGraphException(res["message"], res["code"]) + async def getQueryContent(self, queryName: str) -> dict: + """Returns the content/source code of a query. + + Args: + queryName (str): + Name of the query to get content of. + + Returns: + The response from the database containing the query content. + + Endpoints: + - `GET /gsql/v1/queries/{queryName}` (In TigerGraph versions >= 4.0) + """ + logger.debug("entry: getQueryContent") + if not await self._version_greater_than_4_0(): + logger.debug("exit: getQueryContent") + raise TigerGraphException( + "This function is only supported on versions of TigerGraph >= 4.0.", 0) + + params = {"graph": self.graphname} + res = await self._req("GET", self.gsUrl+"/gsql/v1/queries/"+queryName, + params=params, authMode="pwd", resKey="", headers={'Content-Type': 'application/json'}) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: getQueryContent") + + return res + + async def createQuery(self, queryText: str) -> dict: + """Creates a query in the graph. + + Args: + queryText (str): + The text of the GSQL query to create. Must be in the format: + "create query queryName (...) FOR GRAPH graphName { ... }" + + Returns: + The response from the database containing the creation result. + + Endpoints: + - `POST /gsql/v1/queries` (In TigerGraph versions >= 4.0) + """ + logger.debug("entry: createQuery") + if not await self._version_greater_than_4_0(): + logger.debug("exit: createQuery") + raise TigerGraphException( + "This function is only supported on versions of TigerGraph >= 4.0.", 0) + + # Replace graphname placeholders + queryText = queryText.replace("$graphname", self.graphname) + queryText = queryText.replace("@graphname@", self.graphname) + + params = {"graph": self.graphname} + res = await self._req("POST", self.gsUrl+"/gsql/v1/queries", + params=params, data=queryText, authMode="pwd", + headers={'Content-Type': 'text/plain'}) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: createQuery") + + return res + + async def dropQueries(self, queryName: Union[str, list]) -> dict: + """Drops one or more queries from the graph. + + Args: + queryName (str or list): + Name of the query to drop, or list of query names to drop. + + Returns: + The response from the database containing the drop result. + + Endpoints: + - `DELETE /gsql/v1/queries/{queryName}` (In TigerGraph versions >= 4.0) + """ + logger.debug("entry: dropQueries") + if not await self._version_greater_than_4_0(): + logger.debug("exit: dropQueries") + raise TigerGraphException( + "This function is only supported on versions of TigerGraph >= 4.0.", 0) + + # Handle single query name + if isinstance(queryName, str): + params = {"graph": self.graphname} + res = await self._req("DELETE", self.gsUrl+"/gsql/v1/queries/"+queryName, + params=params, authMode="pwd", resKey="", headers={'Content-Type': 'application/json'}) + # Handle list of query names + elif isinstance(queryName, list): + if not queryName: + raise TigerGraphException("Query name list cannot be empty.", 0) + + params = {"graph": self.graphname, "query": queryName} + res = await self._req("DELETE", self.gsUrl+"/gsql/v1/queries", + params=params, authMode="pwd", resKey="") + else: + raise TigerGraphException("queryName must be a string or list of strings.", 0) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: dropQueries") + + return res + + async def checkQuerySemantic(self, queryCode: str) -> dict: + """Performs a semantic check of a query. + + Args: + queryCode (str): + The GSQL query code to check for semantic errors. + + Returns: + The response from the database containing the semantic check result. + + Endpoints: + - `POST /gsql/v1/internal/check/query` (In TigerGraph versions >= 4.0) + """ + logger.debug("entry: checkQuerySemantic") + if not await self._version_greater_than_4_0(): + logger.debug("exit: checkQuerySemantic") + raise TigerGraphException( + "This function is only supported on versions of TigerGraph >= 4.0.", 0) + + data = {"code": queryCode} + res = await self._req("POST", self.gsUrl+"/gsql/v1/internal/check/query", + data=data, authMode="pwd", resKey="", + headers={'Content-Type': 'application/json'}) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: checkQuerySemantic") + + return res + + async def getQueryInfo(self, queryName: str = None, status: str = None) -> dict: + """Gets query information for the graph. + + Args: + queryName (str, optional): + The specific query name to get information for. If None, returns info for all queries. + status (str, optional): + Filter queries by status (e.g., "VALID", "INVALID", "INSTALLING"). + + Returns: + The response from the database containing query information. + + Endpoints: + - `GET /gsql/v1/queries/info` (In TigerGraph versions >= 4.0) + """ + logger.debug("entry: getQueryInfo") + if not await self._version_greater_than_4_0(): + logger.debug("exit: getQueryInfo") + raise TigerGraphException( + "This function is only supported on versions of TigerGraph >= 4.0.", 0) + + params = {"graph": self.graphname} + if queryName is not None: + params["query"] = queryName + if status is not None: + params["status"] = status + + res = await self._req("GET", self.gsUrl+"/gsql/v1/queries/info", + params=params, authMode="pwd", resKey="", headers={'Content-Type': 'application/json'}) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: getQueryInfo") + + return res + + async def listQueryNames(self) -> list: + """Lists all query names of a graph. + + Returns: + The response from the database containing the list of query names. + + Endpoints: + - `GET /gsql/v1/queries` (In TigerGraph versions >= 4.0) + """ + logger.debug("entry: listQueryNames") + if not await self._version_greater_than_4_0(): + logger.debug("exit: listQueryNames") + raise TigerGraphException( + "This function is only supported on versions of TigerGraph >= 4.0.", 0) + + params = {"graph": self.graphname} + res = await self._req("GET", self.gsUrl+"/gsql/v1/queries", + params=params, authMode="pwd", headers={'Content-Type': 'application/json'}) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: listQueryNames") + + return res + async def getInstalledQueries(self, fmt: str = "py") -> Union[dict, str, 'pd.DataFrame']: """Returns a list of installed queries. @@ -271,10 +467,15 @@ async def runInstalledQuery(self, queryName: str, params: Union[str, dict] = Non return ret else: - if isinstance(params, dict): - params = _parse_query_parameters(params) - ret = await self._req("GET", self.restppUrl + "/query/" + self.graphname + "/" + queryName, - params=params, headers=headers, resKey=res_key) + # for params contains spaces, we need to append to url directly to keep %20 format + if params: + if isinstance(params, dict): + params = _parse_query_parameters(params) + ret = await self._req("GET", self.restppUrl + "/query/" + self.graphname + "/" + queryName + "?" + str(params), + headers=headers, resKey=res_key) + else: + ret = await self._req("GET", self.restppUrl + "/query/" + self.graphname + "/" + queryName, + headers=headers, resKey=res_key) if logger.level == logging.DEBUG: logger.debug("return: " + str(ret)) @@ -451,6 +652,26 @@ async def getStatistics(self, seconds: int = 10, segments: int = 10) -> dict: return ret async def describeQuery(self, queryName: str, queryDescription: str, parameterDescriptions: dict = {}): + """DEPRECATED: Use updateQueryDescription() instead. Add a query description and parameter descriptions. Only supported on versions of TigerGraph >= 4.0.0. + + Args: + queryName: + The name of the query to describe. + queryDescription: + A description of the query. + parameterDescriptions (optional): + A dictionary of parameter descriptions. The keys are the parameter names and the values are the descriptions. + + Returns: + The response from the database. + + Endpoints: + - `PUT /gsqlserver/gsql/description?graph={graph_name}` (In TigerGraph version 4.0) + - `PUT /gsql/v1/description?graph={graph_name}` (In TigerGraph versions >4.0) + """ + return await self.updateQueryDescription(queryName, queryDescription, parameterDescriptions) + + async def updateQueryDescription(self, queryName: str, queryDescription: str, parameterDescriptions: dict = {}): """Add a query description and parameter descriptions. Only supported on versions of TigerGraph >= 4.0.0. Args: @@ -468,11 +689,11 @@ async def describeQuery(self, queryName: str, queryDescription: str, parameterDe - `PUT /gsqlserver/gsql/description?graph={graph_name}` (In TigerGraph version 4.0) - `PUT /gsql/v1/description?graph={graph_name}` (In TigerGraph versions >4.0) """ - logger.debug("entry: describeQuery") + logger.debug("entry: updateQueryDescription") self.ver = await self.getVer() major_ver, minor_ver, patch_ver = self.ver.split(".") if int(major_ver) < 4: - logger.debug("exit: describeQuery") + logger.debug("exit: updateQueryDescription") raise TigerGraphException( "This function is only supported on versions of TigerGraph >= 4.0.0.", 0) @@ -496,7 +717,7 @@ async def describeQuery(self, queryName: str, queryDescription: str, parameterDe if logger.level == logging.DEBUG: logger.debug("return: " + str(res)) - logger.debug("exit: describeQuery") + logger.debug("exit: updateQueryDescription") return res diff --git a/pyTigerGraph/pytgasync/pyTigerGraphSchema.py b/pyTigerGraph/pytgasync/pyTigerGraphSchema.py index 1c8c8448..78f708d6 100644 --- a/pyTigerGraph/pytgasync/pyTigerGraphSchema.py +++ b/pyTigerGraph/pytgasync/pyTigerGraphSchema.py @@ -231,4 +231,212 @@ async def getEndpoints(self, builtin: bool = False, dynamic: bool = False, return ret - # TODO GET /rebuildnow/{graph_name} + async def createGlobalVertices(self, gsql_commands: Union[str, list]) -> dict: + """Creates global vertices using GSQL commands. + + Args: + gsql_commands (str or list): + GSQL CREATE VERTEX statement(s). Can be a single string or list of strings. + + Returns: + The response from the database containing the creation result. + + Endpoints: + - `POST /gsql/v1/schema/vertices` (In TigerGraph versions >= 4.0) + """ + logger.debug("entry: createGlobalVertices") + if not await self._version_greater_than_4_0(): + logger.debug("exit: createGlobalVertices") + raise TigerGraphException( + "This function is only supported on versions of TigerGraph >= 4.0.", 0) + + # Handle single command + if isinstance(gsql_commands, str): + gsql_commands = [gsql_commands] + elif not isinstance(gsql_commands, list): + raise TigerGraphException("gsql_commands must be a string or list of strings.", 0) + + if not gsql_commands: + raise TigerGraphException("gsql_commands cannot be empty.", 0) + + # Validate that all commands are CREATE VERTEX statements + for cmd in gsql_commands: + if not cmd.strip().upper().startswith("CREATE VERTEX"): + raise TigerGraphException(f"Invalid GSQL command: {cmd}. Must be a CREATE VERTEX statement.", 0) + + data = {"gsql": gsql_commands} + params = {"gsql": "true"} + res = await self._req("POST", self.gsUrl+"/gsql/v1/schema/vertices", + params=params, data=data, authMode="pwd", resKey="", + headers={'Content-Type': 'application/json'}) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: createGlobalVertices") + + return res + + async def createGlobalVerticesJson(self, vertices_config: Union[dict, list]) -> dict: + """Creates global vertices using JSON configuration. + + Args: + vertices_config (dict or list): + JSON configuration for vertex creation. Can be a single vertex config dict + or a list of vertex config dicts. Each vertex config should include: + - Name: Vertex type name + - PrimaryId: Primary ID configuration with AttributeType and AttributeName + - Attributes: List of attribute configurations + - Config: Optional configuration (e.g., STATS) + + Returns: + The response from the database containing the creation result. + + Endpoints: + - `POST /gsql/v1/schema/vertices` (In TigerGraph versions >= 4.0) + """ + logger.debug("entry: createGlobalVerticesJson") + if not await self._version_greater_than_4_0(): + logger.debug("exit: createGlobalVerticesJson") + raise TigerGraphException( + "This function is only supported on versions of TigerGraph >= 4.0.", 0) + + # Handle single vertex config + if isinstance(vertices_config, dict): + vertices_config = [vertices_config] + elif not isinstance(vertices_config, list): + raise TigerGraphException("vertices_config must be a dict or list of dicts.", 0) + + if not vertices_config: + raise TigerGraphException("vertices_config cannot be empty.", 0) + + # Validate vertex configurations + for i, vertex_config in enumerate(vertices_config): + if not isinstance(vertex_config, dict): + raise TigerGraphException(f"Vertex config at index {i} must be a dict.", 0) + + required_fields = ["Name", "PrimaryId", "Attributes"] + for field in required_fields: + if field not in vertex_config: + raise TigerGraphException(f"Vertex config at index {i} missing required field: {field}", 0) + + data = {"createVertices": vertices_config} + res = await self._req("POST", self.gsUrl+"/gsql/v1/schema/vertices", + data=data, authMode="pwd", resKey="", + headers={'Content-Type': 'application/json'}) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: createGlobalVerticesJson") + + return res + + async def addGlobalVerticesToGraph(self, vertex_names: Union[str, list], target_graph: str = None) -> dict: + """Adds existing global vertices to a local graph. + + Args: + vertex_names (str or list): + Name(s) of the global vertices to add to the graph. Can be a single + vertex name string or a list of vertex names. + target_graph (str, optional): + The graph to which the global vertices should be added. If not provided, + uses the current connection's graphname. + + Returns: + The response from the database containing the addition result. + + Endpoints: + - `POST /gsql/v1/schema/vertices` (In TigerGraph versions >= 4.0) + """ + logger.debug("entry: addGlobalVerticesToGraph") + if not await self._version_greater_than_4_0(): + logger.debug("exit: addGlobalVerticesToGraph") + raise TigerGraphException( + "This function is only supported on versions of TigerGraph >= 4.0.", 0) + + # Handle single vertex name + if isinstance(vertex_names, str): + vertex_names = [vertex_names] + elif not isinstance(vertex_names, list): + raise TigerGraphException("vertex_names must be a string or list of strings.", 0) + + if not vertex_names: + raise TigerGraphException("vertex_names cannot be empty.", 0) + + # Validate that all items are strings + for i, name in enumerate(vertex_names): + if not isinstance(name, str): + raise TigerGraphException(f"Vertex name at index {i} must be a string.", 0) + + # Use target_graph or current graphname + graph_name = target_graph if target_graph is not None else self.graphname + + data = {"addVertices": vertex_names} + params = {"graph": graph_name} + res = await self._req("POST", self.gsUrl+"/gsql/v1/schema/vertices", + params=params, data=data, authMode="pwd", resKey="", + headers={'Content-Type': 'application/json'}) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: addGlobalVerticesToGraph") + + return res + + async def rebuildGraphEngine(self, threadnum: int = None, vertextype: str = None, + segid: int = None, path: str = None, force: bool = None) -> dict: + """Rebuilds the graph engine. + + When new data is being loaded into the graph (such as new vertices or edges), + the data is initially stored in memory before being saved permanently to disk. + TigerGraph runs a rebuild of the Graph Processing Engine (GPE) to commit the + data in memory to disk. + + Args: + threadnum (int, optional): + Number of threads used to execute the rebuild. If not specified, + the number specified in the .tg.cfg file will be used (default: 3). + vertextype (str, optional): + Vertex type to perform the rebuild for. If not provided, the rebuild + will be run for all vertex types. + segid (int, optional): + Segment ID of the segments to rebuild. If not provided, all segments + will be rebuilt. + path (str, optional): + Path to save the summary of the rebuild to. If not provided, the + default path is /tmp/rebuildnow. + force (bool, optional): + Boolean value that indicates whether to perform rebuilds for segments + for which there are no records of new data. + + Returns: + The response from the database containing the rebuild result. + + Endpoints: + - `GET /restpp/rebuildnow/{graph_name}` (In TigerGraph versions >= 4.0) + """ + logger.debug("entry: rebuildGraphEngine") + if not await self._version_greater_than_4_0(): + logger.debug("exit: rebuildGraphEngine") + raise TigerGraphException( + "This function is only supported on versions of TigerGraph >= 4.0.", 0) + + params = {} + if threadnum is not None: + params["threadnum"] = threadnum + if vertextype is not None: + params["vertextype"] = vertextype + if segid is not None: + params["segid"] = segid + if path is not None: + params["path"] = path + if force is not None: + params["force"] = force + + res = await self._req("GET", self.restppUrl+"/rebuildnow/"+self.graphname, + params=params, authMode="pwd", resKey="") + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: rebuildGraphEngine") + + return res diff --git a/tests/test_pyTigerGraphQuery.py b/tests/test_pyTigerGraphQuery.py index c60d1d9e..83dc1bd7 100644 --- a/tests/test_pyTigerGraphQuery.py +++ b/tests/test_pyTigerGraphQuery.py @@ -250,6 +250,85 @@ def test_installQueries(self): with self.assertRaises(ValueError): self.conn.installQueries("non_existent_query") + def test_getQueryContent(self): + """Test getQueryContent function.""" + # Test getting content of an existing query + res = self.conn.getQueryContent("query1") + self.assertIsInstance(res, dict) + self.assertIn("error", res) + + def test_createQuery(self): + """Test createQuery function.""" + # Test creating a simple query + query_text = """ + CREATE QUERY testCreateQuery() FOR GRAPH $graphname { + PRINT "Hello World"; + } + """ + res = self.conn.createQuery(query_text) + self.assertIsInstance(res, dict) + self.assertIn("error", res) + self.assertIn("message", res) + + def test_dropQueries(self): + """Test dropQueries function.""" + # Test dropping a single query + res = self.conn.dropQueries("testCreateQuery") + self.assertIsInstance(res, dict) + self.assertIn("error", res) + + # Test dropping multiple queries + res = self.conn.dropQueries(["testQuery1", "testQuery2"]) + self.assertIsInstance(res, dict) + self.assertIn("error", res) + + # Test invalid input + with self.assertRaises(Exception): + self.conn.dropQueries(123) # Should be string or list + + def test_listQueryNames(self): + """Test listQueryNames function.""" + res = self.conn.listQueryNames() + self.assertIsInstance(res, list) + + def test_checkQuerySemantic(self): + """Test checkQuerySemantic function.""" + # Test valid query + valid_query = """ + CREATE QUERY testSemanticQuery() { + PRINT "Hello World"; + } + """ + res = self.conn.checkQuerySemantic(valid_query) + self.assertIsInstance(res, dict) + self.assertIn("warnings", res) + self.assertIn("errors", res) + + # Test invalid query + invalid_query = "INVALID GSQL SYNTAX" + res = self.conn.checkQuerySemantic(invalid_query) + self.assertIsInstance(res, dict) + self.assertIn("warnings", res) + self.assertIn("errors", res) + + def test_getQueryInfo(self): + """Test getQueryInfo function.""" + # Test getting info for all queries + res = self.conn.getQueryInfo() + self.assertIsInstance(res, dict) + self.assertIn("error", res) + self.assertIn("results", res) + + # Test getting info for specific query + res = self.conn.getQueryInfo(queryName="query1") + self.assertIsInstance(res, dict) + self.assertIn("error", res) + + # Test getting info with status filter + res = self.conn.getQueryInfo(status="VALID") + self.assertIsInstance(res, dict) + self.assertIn("error", res) + if __name__ == '__main__': unittest.main() diff --git a/tests/test_pyTigerGraphQueryAsync.py b/tests/test_pyTigerGraphQueryAsync.py index b3951931..bdca3ddb 100644 --- a/tests/test_pyTigerGraphQueryAsync.py +++ b/tests/test_pyTigerGraphQueryAsync.py @@ -223,6 +223,85 @@ async def test_04_installQueries(self): with self.assertRaises(ValueError): await self.conn.installQueries("non_existent_query") + async def test_getQueryContent(self): + """Test getQueryContent function.""" + # Test getting content of an existing query + res = await self.conn.getQueryContent("query1") + self.assertIsInstance(res, dict) + self.assertIn("error", res) + + async def test_createQuery(self): + """Test createQuery function.""" + # Test creating a simple query + query_text = """ + CREATE QUERY testCreateQuery() FOR GRAPH $graphname { + PRINT "Hello World"; + } + """ + res = await self.conn.createQuery(query_text) + self.assertIsInstance(res, dict) + self.assertIn("error", res) + self.assertIn("message", res) + + async def test_dropQueries(self): + """Test dropQueries function.""" + # Test dropping a single query + res = await self.conn.dropQueries("testCreateQuery") + self.assertIsInstance(res, dict) + self.assertIn("error", res) + + # Test dropping multiple queries + res = await self.conn.dropQueries(["testQuery1", "testQuery2"]) + self.assertIsInstance(res, dict) + self.assertIn("error", res) + + # Test invalid input + with self.assertRaises(Exception): + await self.conn.dropQueries(123) # Should be string or list + + async def test_listQueryNames(self): + """Test listQueryNames function.""" + res = await self.conn.listQueryNames() + self.assertIsInstance(res, list) + + async def test_checkQuerySemantic(self): + """Test checkQuerySemantic function.""" + # Test valid query + valid_query = """ + CREATE QUERY testSemanticQuery() { + PRINT "Hello World"; + } + """ + res = await self.conn.checkQuerySemantic(valid_query) + self.assertIsInstance(res, dict) + self.assertIn("warnings", res) + self.assertIn("errors", res) + + # Test invalid query + invalid_query = "INVALID GSQL SYNTAX" + res = await self.conn.checkQuerySemantic(invalid_query) + self.assertIsInstance(res, dict) + self.assertIn("warnings", res) + self.assertIn("errors", res) + + async def test_getQueryInfo(self): + """Test getQueryInfo function.""" + # Test getting info for all queries + res = await self.conn.getQueryInfo() + self.assertIsInstance(res, dict) + self.assertIn("error", res) + self.assertIn("results", res) + + # Test getting info for specific query + res = await self.conn.getQueryInfo(queryName="query1") + self.assertIsInstance(res, dict) + self.assertIn("error", res) + + # Test getting info with status filter + res = await self.conn.getQueryInfo(status="VALID") + self.assertIsInstance(res, dict) + self.assertIn("error", res) + if __name__ == '__main__': unittest.main() diff --git a/tests/test_pyTigerGraphSchema.py b/tests/test_pyTigerGraphSchema.py index f969918b..2cb584f4 100644 --- a/tests/test_pyTigerGraphSchema.py +++ b/tests/test_pyTigerGraphSchema.py @@ -374,6 +374,162 @@ def test_05_getEndpoints(self): res = self.conn.getEndpoints(dynamic=True) self.assertEqual(4, len(res)) + def test_createGlobalVertices(self): + """Test createGlobalVertices function with GSQL commands.""" + # Test single GSQL command + gsql_command = "CREATE VERTEX TestVertex1 (PRIMARY_ID id UINT, name STRING)" + res = self.conn.createGlobalVertices(gsql_command) + self.assertIsInstance(res, dict) + self.assertIn("error", res) + self.assertIn("message", res) + + # Test multiple GSQL commands + gsql_commands = [ + "CREATE VERTEX TestVertex2 (PRIMARY_ID id UINT, name STRING)", + "CREATE VERTEX TestVertex3 (PRIMARY_ID id UINT, age UINT)" + ] + res = self.conn.createGlobalVertices(gsql_commands) + self.assertIsInstance(res, dict) + self.assertIn("error", res) + self.assertIn("message", res) + + # Test invalid input + with self.assertRaises(Exception): + self.conn.createGlobalVertices("INVALID COMMAND") + + def test_createGlobalVerticesJson(self): + """Test createGlobalVerticesJson function with JSON configuration.""" + # Test single vertex config + vertex_config = { + "Config": { + "STATS": "OUTDEGREE_BY_EDGETYPE" + }, + "Attributes": [ + { + "AttributeType": { + "Name": "STRING" + }, + "AttributeName": "name" + } + ], + "PrimaryId": { + "AttributeType": { + "Name": "UINT" + }, + "AttributeName": "user_id" + }, + "Name": "TestJsonVertex1" + } + res = self.conn.createGlobalVerticesJson(vertex_config) + self.assertIsInstance(res, dict) + self.assertIn("error", res) + self.assertIn("message", res) + + # Test multiple vertex configs + vertices_config = [ + { + "Config": { + "STATS": "OUTDEGREE_BY_EDGETYPE" + }, + "Attributes": [ + { + "AttributeType": { + "Name": "STRING" + }, + "AttributeName": "name" + } + ], + "PrimaryId": { + "AttributeType": { + "Name": "UINT" + }, + "AttributeName": "user_id" + }, + "Name": "TestJsonVertex2" + }, + { + "Config": { + "STATS": "OUTDEGREE_BY_EDGETYPE" + }, + "Attributes": [ + { + "AttributeType": { + "Name": "STRING" + }, + "AttributeName": "name" + } + ], + "PrimaryId": { + "AttributeType": { + "Name": "UINT" + }, + "AttributeName": "user_id" + }, + "Name": "TestJsonVertex3" + } + ] + res = self.conn.createGlobalVerticesJson(vertices_config) + self.assertIsInstance(res, dict) + self.assertIn("error", res) + self.assertIn("message", res) + + # Test invalid input - missing required fields + invalid_config = { + "Name": "InvalidVertex" + # Missing PrimaryId and Attributes + } + with self.assertRaises(Exception): + self.conn.createGlobalVerticesJson(invalid_config) + + def test_addGlobalVerticesToGraph(self): + """Test addGlobalVerticesToGraph function.""" + # Test single vertex name + res = self.conn.addGlobalVerticesToGraph("TestVertex1") + self.assertIsInstance(res, dict) + self.assertIn("error", res) + self.assertIn("message", res) + + # Test multiple vertex names + res = self.conn.addGlobalVerticesToGraph(["TestVertex2", "TestVertex3"]) + self.assertIsInstance(res, dict) + self.assertIn("error", res) + self.assertIn("message", res) + + # Test with specific target graph + res = self.conn.addGlobalVerticesToGraph(["TestVertex1"], target_graph="testGraph") + self.assertIsInstance(res, dict) + self.assertIn("error", res) + self.assertIn("message", res) + + # Test invalid input + with self.assertRaises(Exception): + self.conn.addGlobalVerticesToGraph(123) # Should be string or list + + def test_rebuildGraphEngine(self): + """Test rebuildGraphEngine function.""" + # Test basic rebuild + res = self.conn.rebuildGraphEngine() + self.assertIsInstance(res, dict) + self.assertIn("error", res) + self.assertIn("message", res) + + # Test with parameters + res = self.conn.rebuildGraphEngine( + threadnum=2, + vertextype="TestVertex1", + path="/tmp/test_rebuild", + force=True + ) + self.assertIsInstance(res, dict) + self.assertIn("error", res) + self.assertIn("message", res) + + # Test with segid parameter + res = self.conn.rebuildGraphEngine(segid=1) + self.assertIsInstance(res, dict) + self.assertIn("error", res) + self.assertIn("message", res) + if __name__ == '__main__': unittest.main() diff --git a/tests/test_pyTigerGraphSchemaAsync.py b/tests/test_pyTigerGraphSchemaAsync.py index 330b7aa2..3e9fcd2d 100644 --- a/tests/test_pyTigerGraphSchemaAsync.py +++ b/tests/test_pyTigerGraphSchemaAsync.py @@ -375,6 +375,162 @@ async def test_05_getEndpoints(self): res = await self.conn.getEndpoints(dynamic=True) self.assertEqual(4, len(res)) + async def test_createGlobalVertices(self): + """Test createGlobalVertices function with GSQL commands.""" + # Test single GSQL command + gsql_command = "CREATE VERTEX TestVertex1 (PRIMARY_ID id UINT, name STRING)" + res = await self.conn.createGlobalVertices(gsql_command) + self.assertIsInstance(res, dict) + self.assertIn("error", res) + self.assertIn("message", res) + + # Test multiple GSQL commands + gsql_commands = [ + "CREATE VERTEX TestVertex2 (PRIMARY_ID id UINT, name STRING)", + "CREATE VERTEX TestVertex3 (PRIMARY_ID id UINT, age UINT)" + ] + res = await self.conn.createGlobalVertices(gsql_commands) + self.assertIsInstance(res, dict) + self.assertIn("error", res) + self.assertIn("message", res) + + # Test invalid input + with self.assertRaises(Exception): + await self.conn.createGlobalVertices("INVALID COMMAND") + + async def test_createGlobalVerticesJson(self): + """Test createGlobalVerticesJson function with JSON configuration.""" + # Test single vertex config + vertex_config = { + "Config": { + "STATS": "OUTDEGREE_BY_EDGETYPE" + }, + "Attributes": [ + { + "AttributeType": { + "Name": "STRING" + }, + "AttributeName": "name" + } + ], + "PrimaryId": { + "AttributeType": { + "Name": "UINT" + }, + "AttributeName": "user_id" + }, + "Name": "TestJsonVertex1" + } + res = await self.conn.createGlobalVerticesJson(vertex_config) + self.assertIsInstance(res, dict) + self.assertIn("error", res) + self.assertIn("message", res) + + # Test multiple vertex configs + vertices_config = [ + { + "Config": { + "STATS": "OUTDEGREE_BY_EDGETYPE" + }, + "Attributes": [ + { + "AttributeType": { + "Name": "STRING" + }, + "AttributeName": "name" + } + ], + "PrimaryId": { + "AttributeType": { + "Name": "UINT" + }, + "AttributeName": "user_id" + }, + "Name": "TestJsonVertex2" + }, + { + "Config": { + "STATS": "OUTDEGREE_BY_EDGETYPE" + }, + "Attributes": [ + { + "AttributeType": { + "Name": "STRING" + }, + "AttributeName": "name" + } + ], + "PrimaryId": { + "AttributeType": { + "Name": "UINT" + }, + "AttributeName": "user_id" + }, + "Name": "TestJsonVertex3" + } + ] + res = await self.conn.createGlobalVerticesJson(vertices_config) + self.assertIsInstance(res, dict) + self.assertIn("error", res) + self.assertIn("message", res) + + # Test invalid input - missing required fields + invalid_config = { + "Name": "InvalidVertex" + # Missing PrimaryId and Attributes + } + with self.assertRaises(Exception): + await self.conn.createGlobalVerticesJson(invalid_config) + + async def test_addGlobalVerticesToGraph(self): + """Test addGlobalVerticesToGraph function.""" + # Test single vertex name + res = await self.conn.addGlobalVerticesToGraph("TestVertex1") + self.assertIsInstance(res, dict) + self.assertIn("error", res) + self.assertIn("message", res) + + # Test multiple vertex names + res = await self.conn.addGlobalVerticesToGraph(["TestVertex2", "TestVertex3"]) + self.assertIsInstance(res, dict) + self.assertIn("error", res) + self.assertIn("message", res) + + # Test with specific target graph + res = await self.conn.addGlobalVerticesToGraph(["TestVertex1"], target_graph="testGraph") + self.assertIsInstance(res, dict) + self.assertIn("error", res) + self.assertIn("message", res) + + # Test invalid input + with self.assertRaises(Exception): + await self.conn.addGlobalVerticesToGraph(123) # Should be string or list + + async def test_rebuildGraphEngine(self): + """Test rebuildGraphEngine function.""" + # Test basic rebuild + res = await self.conn.rebuildGraphEngine() + self.assertIsInstance(res, dict) + self.assertIn("error", res) + self.assertIn("message", res) + + # Test with parameters + res = await self.conn.rebuildGraphEngine( + threadnum=2, + vertextype="TestVertex1", + path="/tmp/test_rebuild", + force=True + ) + self.assertIsInstance(res, dict) + self.assertIn("error", res) + self.assertIn("message", res) + + # Test with segid parameter + res = await self.conn.rebuildGraphEngine(segid=1) + self.assertIsInstance(res, dict) + self.assertIn("error", res) + self.assertIn("message", res) + if __name__ == '__main__': unittest.main() From 8c367808bc977aca723440edff62a06734222875 Mon Sep 17 00:00:00 2001 From: Chengbiao Jin Date: Tue, 28 Oct 2025 19:56:05 -0700 Subject: [PATCH 07/10] add more gsql apis --- pyTigerGraph/common/auth.py | 9 +- pyTigerGraph/pyTigerGraphAuth.py | 48 ++- pyTigerGraph/pyTigerGraphGSQL.py | 315 +++++++++++++++++++ pyTigerGraph/pyTigerGraphSchema.py | 53 +--- pyTigerGraph/pytgasync/pyTigerGraph.py | 1 + pyTigerGraph/pytgasync/pyTigerGraphAuth.py | 49 ++- pyTigerGraph/pytgasync/pyTigerGraphGSQL.py | 315 +++++++++++++++++++ pyTigerGraph/pytgasync/pyTigerGraphSchema.py | 53 +--- tests/test_pyTigerGraphGSQL.py | 41 +++ tests/test_pyTigerGraphGSQLAsync.py | 38 +++ 10 files changed, 830 insertions(+), 92 deletions(-) diff --git a/pyTigerGraph/common/auth.py b/pyTigerGraph/common/auth.py index 1c5f8379..969a233e 100644 --- a/pyTigerGraph/common/auth.py +++ b/pyTigerGraph/common/auth.py @@ -61,7 +61,7 @@ def _parse_create_secret(response: str, alias: str = "", withAlias: bool = False def _prep_token_request(restppUrl: str, gsUrl: str, - graphname: str, + graphname: str = None, version: str = None, secret: str = None, lifetime: int = None, @@ -113,7 +113,10 @@ def _parse_token_response(response: dict, mainVer: int, base64_credential: str) -> Tuple[Union[Tuple[str, str], str], dict]: if not response.get("error"): - token = response["token"] + # Note that /requesttoken has sightly different response using username-password pair. + # See https://docs.tigergraph.com/tigergraph-server/3.10/api/built-in-endpoints#_request_a_token + token = response.get("results", response)["token"] + if setToken: apiToken = token authHeader = {'Authorization': "Bearer " + apiToken} @@ -125,7 +128,7 @@ def _parse_token_response(response: dict, if response.get("expiration"): # On >=4.1 the format for the date of expiration changed. Convert back to old format # Can't use self._versionGreaterThan4_0 since you need a token for that - if mainVer == 4: + if mainVer >= 4: return (token, response.get("expiration")), authHeader else: return (token, response.get("expiration"), \ diff --git a/pyTigerGraph/pyTigerGraphAuth.py b/pyTigerGraph/pyTigerGraphAuth.py index 27d6a2ce..1c14b31f 100644 --- a/pyTigerGraph/pyTigerGraphAuth.py +++ b/pyTigerGraph/pyTigerGraphAuth.py @@ -143,10 +143,10 @@ def dropSecret(self, alias: Union[str, list], ignoreErrors: bool = True) -> str: return res - def _token(self, secret: str = None, lifetime: int = None, token: str = None, _method: str = None) -> Union[tuple, str]: + def _token(self, secret: str = None, lifetime: int = None, token: str = None, _method: str = None, for_graph: bool = True) -> Union[tuple, str]: method, url, alt_url, authMode, data, alt_data = _prep_token_request(self.restppUrl, self.gsUrl, - self.graphname, + None if for_graph else self.graphname, self.version, secret, lifetime, @@ -191,7 +191,8 @@ def _token(self, secret: str = None, lifetime: int = None, token: str = None, _m def getToken(self, secret: str = None, setToken: bool = True, - lifetime: int = None) -> Union[Tuple[str, str], str]: + lifetime: int = None, + for_graph: bool = True) -> Union[Tuple[str, str], str]: """Requests an authorization token. This function returns a token only if REST++ authentication is enabled. If not, an exception @@ -346,3 +347,44 @@ def deleteToken(self, secret: str, token: str = None, skipNA: bool = False) -> b raise TigerGraphException( res["message"], (res["code"] if "code" in res else None)) + def checkJwtToken(self, token: str = None) -> dict: + """Check JWT token validity. + + Check if a JWT token is valid or not. + + Args: + token (str, optional): + The JWT token to check. If not provided, uses the current connection's token. + + Returns: + dict: The response from the database containing the token validation result. + + Endpoints: + - `POST /gsql/v1/tokens/check` (In TigerGraph versions >= 4.0) + """ + logger.debug("entry: checkJwtToken") + if not self._version_greater_than_4_0(): + logger.debug("exit: checkJwtToken") + raise TigerGraphException( + "This function is only supported on versions of TigerGraph >= 4.0.", 0) + + if logger.level == logging.DEBUG: + logger.debug("params: " + self._locals(locals())) + + if token is None: + token = self.apiToken + + if not token: + raise TigerGraphException("No token provided and no token is currently set.", 0) + + data = {"token": token} + res = self._post(self.gsUrl+"/gsql/v1/tokens/check", + data=data, authMode="pwd", resKey="", + headers={'Content-Type': 'application/json'}) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: checkJwtToken") + + return res + diff --git a/pyTigerGraph/pyTigerGraphGSQL.py b/pyTigerGraph/pyTigerGraphGSQL.py index ac4c60f2..741bc8dd 100644 --- a/pyTigerGraph/pyTigerGraphGSQL.py +++ b/pyTigerGraph/pyTigerGraphGSQL.py @@ -180,3 +180,318 @@ def getUDF(self, ExprFunctions: bool = True, ExprUtil: bool = True, json_out=Fal responses[file_name] = resp return _parse_get_udf(responses, json_out=json_out) + + def getAsyncRequestStatus(self, requestId: str) -> dict: + """Check status of asynchronous request with requestId. + + Args: + requestId (str): + The request ID of the asynchronous statement to check. + + Returns: + dict: The response from the database containing the statement status. + + Endpoints: + - `GET /gsql/v1/statements/{requestId}` (In TigerGraph versions >= 4.0) + """ + logger.debug("entry: getAsyncRequestStatus") + if not self._version_greater_than_4_0(): + logger.debug("exit: getAsyncRequestStatus") + raise TigerGraphException( + "This function is only supported on versions of TigerGraph >= 4.0.", 0) + + if logger.level == logging.DEBUG: + logger.debug("params: " + self._locals(locals())) + + res = self._get(self.gsUrl+"/gsql/v1/statements/"+requestId, + authMode="pwd", resKey="", headers={'Content-Type': 'application/json'}) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: getAsyncRequestStatus") + + return res + + def cancelAsyncRequest(self, requestId: str) -> dict: + """Cancel an asynchronous request with requestId. + + Args: + requestId (str): + The request ID of the asynchronous statement to cancel. + + Returns: + dict: The response from the database containing the cancellation result. + + Endpoints: + - `PUT /gsql/v1/statements/{requestId}/cancel` (In TigerGraph versions >= 4.0) + """ + logger.debug("entry: cancelAsyncRequest") + if not self._version_greater_than_4_0(): + logger.debug("exit: cancelAsyncRequest") + raise TigerGraphException( + "This function is only supported on versions of TigerGraph >= 4.0.", 0) + + if logger.level == logging.DEBUG: + logger.debug("params: " + self._locals(locals())) + + res = self._put(self.gsUrl+"/gsql/v1/statements/"+requestId+"/cancel", + authMode="pwd", resKey="", headers={'Content-Type': 'application/json'}) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: cancelAsyncRequest") + + return res + + def recoverCatalog(self) -> dict: + """Recover gdict catalog. + + Args: + None + + Returns: + dict: The response from the database containing the recovery result. + + Endpoints: + - `POST /gsql/v1/schema/recover` (In TigerGraph versions >= 4.0) + """ + logger.debug("entry: recoverCatalog") + if not self._version_greater_than_4_0(): + logger.debug("exit: recoverCatalog") + raise TigerGraphException( + "This function is only supported on versions of TigerGraph >= 4.0.", 0) + + res = self._post(self.gsUrl+"/gsql/v1/schema/recover", + authMode="pwd", resKey="", headers={'Content-Type': 'text/plain'}) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: recoverCatalog") + + return res + + def clearGraphStore(self) -> dict: + """Clear graph store. + + This endpoint permanently deletes all the data out of the graph store (database), + for all graphs. It does not delete the database schema, nor does it delete queries + or loading jobs. It is equivalent to the GSQL command CLEAR GRAPH STORE. + + WARNING: This operation is not reversible. The deleted data cannot be recovered. + + Args: + None + + Returns: + dict: The response from the database containing the clear operation result. + + Endpoints: + - `GET /gsql/v1/clear-store` (In TigerGraph versions >= 4.0) + """ + logger.debug("entry: clearGraphStore") + if not self._version_greater_than_4_0(): + logger.debug("exit: clearGraphStore") + raise TigerGraphException( + "This function is only supported on versions of TigerGraph >= 4.0.", 0) + + res = self._get(self.gsUrl+"/gsql/v1/clear-store", + authMode="pwd", resKey="", headers={'Content-Type': 'application/json'}) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: clearGraphStore") + + return res + + def dropAll(self) -> dict: + """Drop all. + + This endpoint drops all graphs, vertices, edges, queries, and loading jobs + from the database. This operation is equivalent to dropping everything + and starting fresh. + + WARNING: This operation is not reversible. The deleted data cannot be recovered. + + Args: + None + + Returns: + dict: The response from the database containing the drop operation result. + + Endpoints: + - `GET /gsql/v1/drop-all` (In TigerGraph versions >= 4.0) + """ + logger.debug("entry: dropAll") + if not self._version_greater_than_4_0(): + logger.debug("exit: dropAll") + raise TigerGraphException( + "This function is only supported on versions of TigerGraph >= 4.0.", 0) + + res = self._get(self.gsUrl+"/gsql/v1/drop-all", + authMode="pwd", resKey="", headers={'Content-Type': 'application/json'}) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: dropAll") + + return res + + def exportDatabase(self, path: str, graphNames: list = None, schema: bool = False, + template: bool = False, data: bool = False, users: bool = False, + password: str = None, separator: str = "\u001d", eol: str = "\u001c") -> dict: + """Export database. + + Args: + path (str): + The path where the database export will be saved. + graphNames (list, optional): + List of graph names to export. Defaults to ["*"] for all graphs. + schema (bool, optional): + Whether to export schema. Defaults to False. + template (bool, optional): + Whether to export templates. Defaults to False. + data (bool, optional): + Whether to export data. Defaults to False. + users (bool, optional): + Whether to export users. Defaults to False. + password (str, optional): + Password for the export operation. + separator (str, optional): + Field separator character. Defaults to "\u001d". + eol (str, optional): + End of line character. Defaults to "\u001c". + + Returns: + dict: The response from the database containing the export operation result. + + Endpoints: + - `POST /gsql/v1/db-export` (In TigerGraph versions >= 4.0) + """ + logger.debug("entry: exportDatabase") + if not self._version_greater_than_4_0(): + logger.debug("exit: exportDatabase") + raise TigerGraphException( + "This function is only supported on versions of TigerGraph >= 4.0.", 0) + + if logger.level == logging.DEBUG: + logger.debug("params: " + self._locals(locals())) + + if graphNames is None: + graphNames = ["*"] + + data = { + "path": path, + "graphNames": graphNames, + "schema": schema, + "template": template, + "data": data, + "users": users, + "separator": separator, + "eol": eol + } + + if password is None: + password = self.password + + if password is not None: + data["password"] = password + + res = self._post(self.gsUrl+"/gsql/v1/db-export", + data=data, authMode="pwd", resKey="", + headers={'Content-Type': 'application/json'}) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: exportDatabase") + + return res + + def importDatabase(self, path: str, graphNames: list = None, keepUsers: bool = False, + password: str = None) -> dict: + """Import database. + + Args: + path (str): + The path where the database import will be loaded from. + graphNames (list, optional): + List of graph names to import. Defaults to ["*"] for all graphs. + keepUsers (bool, optional): + Whether to keep existing users. Defaults to False. + password (str, optional): + Password for the import operation. + + Returns: + dict: The response from the database containing the import operation result. + + Endpoints: + - `POST /gsql/v1/db-import` (In TigerGraph versions >= 4.0) + """ + logger.debug("entry: importDatabase") + if not self._version_greater_than_4_0(): + logger.debug("exit: importDatabase") + raise TigerGraphException( + "This function is only supported on versions of TigerGraph >= 4.0.", 0) + + if logger.level == logging.DEBUG: + logger.debug("params: " + self._locals(locals())) + + if graphNames is None: + graphNames = ["*"] + + data = { + "path": path, + "graphNames": graphNames, + "keepUsers": keepUsers + } + + if password is None: + password = self.password + + if password is not None: + data["password"] = password + + res = self._post(self.gsUrl+"/gsql/v1/db-import", + data=data, authMode="pwd", resKey="", + headers={'Content-Type': 'application/json'}) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: importDatabase") + + return res + + def getGSQLVersion(self, verbose: bool = False) -> dict: + """Get GSQL version information. + + Args: + verbose (bool, optional): + Whether to return detailed version information. Defaults to False. + + Returns: + dict: The response from the database containing the GSQL version information. + + Endpoints: + - `GET /gsql/v1/version` (In TigerGraph versions >= 4.0) + """ + logger.debug("entry: getGSQLVersion") + if not self._version_greater_than_4_0(): + logger.debug("exit: getGSQLVersion") + raise TigerGraphException( + "This function is only supported on versions of TigerGraph >= 4.0.", 0) + + if logger.level == logging.DEBUG: + logger.debug("params: " + self._locals(locals())) + + params = {} + if verbose: + params["verbose"] = verbose + + res = self._get(self.gsUrl+"/gsql/v1/version", + params=params, authMode="pwd", resKey="", + headers={'Content-Type': 'text/plain'}) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: getGSQLVersion") + + return res diff --git a/pyTigerGraph/pyTigerGraphSchema.py b/pyTigerGraph/pyTigerGraphSchema.py index d3ddb613..8cd46d5c 100644 --- a/pyTigerGraph/pyTigerGraphSchema.py +++ b/pyTigerGraph/pyTigerGraphSchema.py @@ -381,61 +381,32 @@ def addGlobalVerticesToGraph(self, vertex_names: Union[str, list], target_graph: return res - def rebuildGraphEngine(self, threadnum: int = None, vertextype: str = None, - segid: int = None, path: str = None, force: bool = None) -> dict: - """Rebuilds the graph engine. + def validateGraphSchema(self) -> dict: + """Validate graph schema. - When new data is being loaded into the graph (such as new vertices or edges), - the data is initially stored in memory before being saved permanently to disk. - TigerGraph runs a rebuild of the Graph Processing Engine (GPE) to commit the - data in memory to disk. + Check that the current graph schema is valid. Args: - threadnum (int, optional): - Number of threads used to execute the rebuild. If not specified, - the number specified in the .tg.cfg file will be used (default: 3). - vertextype (str, optional): - Vertex type to perform the rebuild for. If not provided, the rebuild - will be run for all vertex types. - segid (int, optional): - Segment ID of the segments to rebuild. If not provided, all segments - will be rebuilt. - path (str, optional): - Path to save the summary of the rebuild to. If not provided, the - default path is /tmp/rebuildnow. - force (bool, optional): - Boolean value that indicates whether to perform rebuilds for segments - for which there are no records of new data. + None Returns: - The response from the database containing the rebuild result. + dict: The response from the database containing the schema validation result. Endpoints: - - `GET /restpp/rebuildnow/{graph_name}` (In TigerGraph versions >= 4.0) + - `POST /gsql/v1/schema/check` (In TigerGraph versions >= 4.0) """ - logger.debug("entry: rebuildGraphEngine") + logger.debug("entry: validateGraphSchema") if not self._version_greater_than_4_0(): - logger.debug("exit: rebuildGraphEngine") + logger.debug("exit: validateGraphSchema") raise TigerGraphException( "This function is only supported on versions of TigerGraph >= 4.0.", 0) - params = {} - if threadnum is not None: - params["threadnum"] = threadnum - if vertextype is not None: - params["vertextype"] = vertextype - if segid is not None: - params["segid"] = segid - if path is not None: - params["path"] = path - if force is not None: - params["force"] = force - - res = self._get(self.restppUrl+"/rebuildnow/"+self.graphname, - params=params, authMode="pwd", resKey="") + res = self._post(self.gsUrl+"/gsql/v1/schema/check", + authMode="pwd", resKey="", + headers={'Content-Type': 'text/plain'}) if logger.level == logging.DEBUG: logger.debug("return: " + str(res)) - logger.debug("exit: rebuildGraphEngine") + logger.debug("exit: validateGraphSchema") return res diff --git a/pyTigerGraph/pytgasync/pyTigerGraph.py b/pyTigerGraph/pytgasync/pyTigerGraph.py index 1f5a7cd2..d35d3978 100644 --- a/pyTigerGraph/pytgasync/pyTigerGraph.py +++ b/pyTigerGraph/pytgasync/pyTigerGraph.py @@ -3,6 +3,7 @@ from typing import TYPE_CHECKING, Union import urllib3 +import asyncio from pyTigerGraph.pytgasync.pyTigerGraphVertex import AsyncPyTigerGraphVertex from pyTigerGraph.pytgasync.pyTigerGraphDataset import AsyncPyTigerGraphDataset diff --git a/pyTigerGraph/pytgasync/pyTigerGraphAuth.py b/pyTigerGraph/pytgasync/pyTigerGraphAuth.py index a319700a..6c2f8230 100644 --- a/pyTigerGraph/pytgasync/pyTigerGraphAuth.py +++ b/pyTigerGraph/pytgasync/pyTigerGraphAuth.py @@ -143,10 +143,10 @@ async def dropSecret(self, alias: Union[str, list], ignoreErrors: bool = True) - return res - async def _token(self, secret: str = None, lifetime: int = None, token=None, _method=None) -> Union[tuple, str]: + async def _token(self, secret: str = None, lifetime: int = None, token=None, _method=None, for_graph: bool = True) -> Union[tuple, str]: method, url, alt_url, authMode, data, alt_data = _prep_token_request(self.restppUrl, self.gsUrl, - self.graphname, + self.graphname if for_graph else None, secret=secret, lifetime=lifetime, token=token) @@ -178,12 +178,12 @@ async def _token(self, secret: str = None, lifetime: int = None, token=None, _me # uses mainVer instead of _versionGreaterThan4_0 since you need a token for verson checking return res, mainVer - async def getToken(self, secret: str = None, setToken: bool = True, lifetime: int = None) -> Union[tuple, str]: + async def getToken(self, secret: str = None, setToken: bool = True, lifetime: int = None, for_graph: bool = True) -> Union[tuple, str]: logger.debug("entry: getToken") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) - res, mainVer = await self._token(secret, lifetime) + res, mainVer = await self._token(secret, lifetime, for_graph=for_graph) token, auth_header = _parse_token_response(res, setToken, mainVer, @@ -229,3 +229,44 @@ async def deleteToken(self, secret: str, token=None, skipNA=True) -> bool: raise TigerGraphException( res["message"], (res["code"] if "code" in res else None)) + + async def checkJwtToken(self, token: str = None) -> dict: + """Check JWT token validity. + + Check if a JWT token is valid or not. + + Args: + token (str, optional): + The JWT token to check. If not provided, uses the current connection's token. + + Returns: + dict: The response from the database containing the token validation result. + + Endpoints: + - `POST /gsql/v1/tokens/check` (In TigerGraph versions >= 4.0) + """ + logger.debug("entry: checkJwtToken") + if not await self._version_greater_than_4_0(): + logger.debug("exit: checkJwtToken") + raise TigerGraphException( + "This function is only supported on versions of TigerGraph >= 4.0.", 0) + + if logger.level == logging.DEBUG: + logger.debug("params: " + self._locals(locals())) + + if token is None: + token = self.apiToken + + if not token: + raise TigerGraphException("No token provided and no token is currently set.", 0) + + data = {"token": token} + res = await self._req("POST", self.gsUrl+"/gsql/v1/tokens/check", + data=data, authMode="pwd", resKey="", + headers={'Content-Type': 'application/json'}) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: checkJwtToken") + + return res diff --git a/pyTigerGraph/pytgasync/pyTigerGraphGSQL.py b/pyTigerGraph/pytgasync/pyTigerGraphGSQL.py index 80b49743..a4397e1f 100644 --- a/pyTigerGraph/pytgasync/pyTigerGraphGSQL.py +++ b/pyTigerGraph/pytgasync/pyTigerGraphGSQL.py @@ -107,3 +107,318 @@ async def getUDF(self, ExprFunctions: bool = True, ExprUtil: bool = True, json_o responses[file_name] = resp return _parse_get_udf(responses, json_out=json_out) + + async def getAsyncRequestStatus(self, requestId: str) -> dict: + """Check status of asynchronous request with requestId. + + Args: + requestId (str): + The request ID of the asynchronous statement to check. + + Returns: + dict: The response from the database containing the statement status. + + Endpoints: + - `GET /gsql/v1/statements/{requestId}` (In TigerGraph versions >= 4.0) + """ + logger.debug("entry: getAsyncRequestStatus") + if not await self._version_greater_than_4_0(): + logger.debug("exit: getAsyncRequestStatus") + raise TigerGraphException( + "This function is only supported on versions of TigerGraph >= 4.0.", 0) + + if logger.level == logging.DEBUG: + logger.debug("params: " + self._locals(locals())) + + res = await self._req("GET", self.gsUrl+"/gsql/v1/statements/"+requestId, + authMode="pwd", resKey="", headers={'Content-Type': 'application/json'}) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: getAsyncRequestStatus") + + return res + + async def cancelAsyncRequest(self, requestId: str) -> dict: + """Cancel an asynchronous request with requestId. + + Args: + requestId (str): + The request ID of the asynchronous statement to cancel. + + Returns: + dict: The response from the database containing the cancellation result. + + Endpoints: + - `PUT /gsql/v1/statements/{requestId}/cancel` (In TigerGraph versions >= 4.0) + """ + logger.debug("entry: cancelAsyncRequest") + if not await self._version_greater_than_4_0(): + logger.debug("exit: cancelAsyncRequest") + raise TigerGraphException( + "This function is only supported on versions of TigerGraph >= 4.0.", 0) + + if logger.level == logging.DEBUG: + logger.debug("params: " + self._locals(locals())) + + res = await self._req("PUT", self.gsUrl+"/gsql/v1/statements/"+requestId+"/cancel", + authMode="pwd", resKey="", headers={'Content-Type': 'application/json'}) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: cancelAsyncRequest") + + return res + + async def recoverCatalog(self) -> dict: + """Recover gdict catalog. + + Args: + None + + Returns: + dict: The response from the database containing the recovery result. + + Endpoints: + - `POST /gsql/v1/schema/recover` (In TigerGraph versions >= 4.0) + """ + logger.debug("entry: recoverCatalog") + if not await self._version_greater_than_4_0(): + logger.debug("exit: recoverCatalog") + raise TigerGraphException( + "This function is only supported on versions of TigerGraph >= 4.0.", 0) + + res = await self._req("POST", self.gsUrl+"/gsql/v1/schema/recover", + authMode="pwd", resKey="", headers={'Content-Type': 'text/plain'}) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: recoverCatalog") + + return res + + async def clearGraphStore(self) -> dict: + """Clear graph store. + + This endpoint permanently deletes all the data out of the graph store (database), + for all graphs. It does not delete the database schema, nor does it delete queries + or loading jobs. It is equivalent to the GSQL command CLEAR GRAPH STORE. + + WARNING: This operation is not reversible. The deleted data cannot be recovered. + + Args: + None + + Returns: + dict: The response from the database containing the clear operation result. + + Endpoints: + - `GET /gsql/v1/clear-store` (In TigerGraph versions >= 4.0) + """ + logger.debug("entry: clearGraphStore") + if not await self._version_greater_than_4_0(): + logger.debug("exit: clearGraphStore") + raise TigerGraphException( + "This function is only supported on versions of TigerGraph >= 4.0.", 0) + + res = await self._req("GET", self.gsUrl+"/gsql/v1/clear-store", + authMode="pwd", resKey="", headers={'Content-Type': 'application/json'}) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: clearGraphStore") + + return res + + async def dropAll(self) -> dict: + """Drop all. + + This endpoint drops all graphs, vertices, edges, queries, and loading jobs + from the database. This operation is equivalent to dropping everything + and starting fresh. + + WARNING: This operation is not reversible. The deleted data cannot be recovered. + + Args: + None + + Returns: + dict: The response from the database containing the drop operation result. + + Endpoints: + - `GET /gsql/v1/drop-all` (In TigerGraph versions >= 4.0) + """ + logger.debug("entry: dropAll") + if not await self._version_greater_than_4_0(): + logger.debug("exit: dropAll") + raise TigerGraphException( + "This function is only supported on versions of TigerGraph >= 4.0.", 0) + + res = await self._req("GET", self.gsUrl+"/gsql/v1/drop-all", + authMode="pwd", resKey="", headers={'Content-Type': 'application/json'}) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: dropAll") + + return res + + async def exportDatabase(self, path: str, graphNames: list = None, schema: bool = False, + template: bool = False, data: bool = False, users: bool = False, + password: str = None, separator: str = "\u001d", eol: str = "\u001c") -> dict: + """Export database. + + Args: + path (str): + The path where the database export will be saved. + graphNames (list, optional): + List of graph names to export. Defaults to ["*"] for all graphs. + schema (bool, optional): + Whether to export schema. Defaults to False. + template (bool, optional): + Whether to export templates. Defaults to False. + data (bool, optional): + Whether to export data. Defaults to False. + users (bool, optional): + Whether to export users. Defaults to False. + password (str, optional): + Password for the export operation. + separator (str, optional): + Field separator character. Defaults to "\u001d". + eol (str, optional): + End of line character. Defaults to "\u001c". + + Returns: + dict: The response from the database containing the export operation result. + + Endpoints: + - `POST /gsql/v1/db-export` (In TigerGraph versions >= 4.0) + """ + logger.debug("entry: exportDatabase") + if not await self._version_greater_than_4_0(): + logger.debug("exit: exportDatabase") + raise TigerGraphException( + "This function is only supported on versions of TigerGraph >= 4.0.", 0) + + if logger.level == logging.DEBUG: + logger.debug("params: " + self._locals(locals())) + + if graphNames is None: + graphNames = ["*"] + + data = { + "path": path, + "graphNames": graphNames, + "schema": schema, + "template": template, + "data": data, + "users": users, + "separator": separator, + "eol": eol + } + + if password is None: + password = self.password + + if password is not None: + data["password"] = password + + res = await self._req("POST", self.gsUrl+"/gsql/v1/db-export", + data=data, authMode="pwd", resKey="", + headers={'Content-Type': 'application/json'}) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: exportDatabase") + + return res + + async def importDatabase(self, path: str, graphNames: list = None, keepUsers: bool = False, + password: str = None) -> dict: + """Import database. + + Args: + path (str): + The path where the database import will be loaded from. + graphNames (list, optional): + List of graph names to import. Defaults to ["*"] for all graphs. + keepUsers (bool, optional): + Whether to keep existing users. Defaults to False. + password (str, optional): + Password for the import operation. + + Returns: + dict: The response from the database containing the import operation result. + + Endpoints: + - `POST /gsql/v1/db-import` (In TigerGraph versions >= 4.0) + """ + logger.debug("entry: importDatabase") + if not await self._version_greater_than_4_0(): + logger.debug("exit: importDatabase") + raise TigerGraphException( + "This function is only supported on versions of TigerGraph >= 4.0.", 0) + + if logger.level == logging.DEBUG: + logger.debug("params: " + self._locals(locals())) + + if graphNames is None: + graphNames = ["*"] + + data = { + "path": path, + "graphNames": graphNames, + "keepUsers": keepUsers + } + + if password is None: + password = self.password + + if password is not None: + data["password"] = password + + res = await self._req("POST", self.gsUrl+"/gsql/v1/db-import", + data=data, authMode="pwd", resKey="", + headers={'Content-Type': 'application/json'}) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: importDatabase") + + return res + + async def getGSQLVersion(self, verbose: bool = False) -> dict: + """Get GSQL version information. + + Args: + verbose (bool, optional): + Whether to return detailed version information. Defaults to False. + + Returns: + dict: The response from the database containing the GSQL version information. + + Endpoints: + - `GET /gsql/v1/version` (In TigerGraph versions >= 4.0) + """ + logger.debug("entry: getGSQLVersion") + if not await self._version_greater_than_4_0(): + logger.debug("exit: getGSQLVersion") + raise TigerGraphException( + "This function is only supported on versions of TigerGraph >= 4.0.", 0) + + if logger.level == logging.DEBUG: + logger.debug("params: " + self._locals(locals())) + + params = {} + if verbose: + params["verbose"] = verbose + + res = await self._req("GET", self.gsUrl+"/gsql/v1/version", + params=params, authMode="pwd", resKey="", + headers={'Content-Type': 'text/plain'}) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: getGSQLVersion") + + return res diff --git a/pyTigerGraph/pytgasync/pyTigerGraphSchema.py b/pyTigerGraph/pytgasync/pyTigerGraphSchema.py index 78f708d6..096090c3 100644 --- a/pyTigerGraph/pytgasync/pyTigerGraphSchema.py +++ b/pyTigerGraph/pytgasync/pyTigerGraphSchema.py @@ -382,61 +382,32 @@ async def addGlobalVerticesToGraph(self, vertex_names: Union[str, list], target_ return res - async def rebuildGraphEngine(self, threadnum: int = None, vertextype: str = None, - segid: int = None, path: str = None, force: bool = None) -> dict: - """Rebuilds the graph engine. + async def validateGraphSchema(self) -> dict: + """Validate graph schema. - When new data is being loaded into the graph (such as new vertices or edges), - the data is initially stored in memory before being saved permanently to disk. - TigerGraph runs a rebuild of the Graph Processing Engine (GPE) to commit the - data in memory to disk. + Check that the current graph schema is valid. Args: - threadnum (int, optional): - Number of threads used to execute the rebuild. If not specified, - the number specified in the .tg.cfg file will be used (default: 3). - vertextype (str, optional): - Vertex type to perform the rebuild for. If not provided, the rebuild - will be run for all vertex types. - segid (int, optional): - Segment ID of the segments to rebuild. If not provided, all segments - will be rebuilt. - path (str, optional): - Path to save the summary of the rebuild to. If not provided, the - default path is /tmp/rebuildnow. - force (bool, optional): - Boolean value that indicates whether to perform rebuilds for segments - for which there are no records of new data. + None Returns: - The response from the database containing the rebuild result. + dict: The response from the database containing the schema validation result. Endpoints: - - `GET /restpp/rebuildnow/{graph_name}` (In TigerGraph versions >= 4.0) + - `POST /gsql/v1/schema/check` (In TigerGraph versions >= 4.0) """ - logger.debug("entry: rebuildGraphEngine") + logger.debug("entry: validateGraphSchema") if not await self._version_greater_than_4_0(): - logger.debug("exit: rebuildGraphEngine") + logger.debug("exit: validateGraphSchema") raise TigerGraphException( "This function is only supported on versions of TigerGraph >= 4.0.", 0) - params = {} - if threadnum is not None: - params["threadnum"] = threadnum - if vertextype is not None: - params["vertextype"] = vertextype - if segid is not None: - params["segid"] = segid - if path is not None: - params["path"] = path - if force is not None: - params["force"] = force - - res = await self._req("GET", self.restppUrl+"/rebuildnow/"+self.graphname, - params=params, authMode="pwd", resKey="") + res = await self._req("POST", self.gsUrl+"/gsql/v1/schema/check", + authMode="pwd", resKey="", + headers={'Content-Type': 'text/plain'}) if logger.level == logging.DEBUG: logger.debug("return: " + str(res)) - logger.debug("exit: rebuildGraphEngine") + logger.debug("exit: validateGraphSchema") return res diff --git a/tests/test_pyTigerGraphGSQL.py b/tests/test_pyTigerGraphGSQL.py index 2ec73f88..1e8a7c2d 100644 --- a/tests/test_pyTigerGraphGSQL.py +++ b/tests/test_pyTigerGraphGSQL.py @@ -48,6 +48,44 @@ def test_getUDF(self): udf = self.conn.getUDF(ExprFunctions=False) self.assertIn("class KafkaProducer", udf) + def test_getAsyncRequestStatus(self): + """Test getAsyncRequestStatus function.""" + # Test with a sample request ID (this will likely fail in test environment) + # but we can test the function structure and error handling + test_request_id = "00000000006.317280417" + + try: + res = self.conn.getAsyncRequestStatus(test_request_id) + self.assertIsInstance(res, dict) + self.assertIn("error", res) + self.assertIn("message", res) + except Exception as e: + # Expected to fail in test environment, but should be a proper error response + self.assertIsInstance(e, Exception) + + def test_cancelAsyncRequest(self): + """Test cancelAsyncRequest function.""" + # Test with a sample request ID (this will likely fail in test environment) + # but we can test the function structure and error handling + test_request_id = "00000000006.317280417" + + try: + res = self.conn.cancelAsyncRequest(test_request_id) + self.assertIsInstance(res, dict) + self.assertIn("error", res) + self.assertIn("message", res) + except Exception as e: + # Expected to fail in test environment, but should be a proper error response + self.assertIsInstance(e, Exception) + + def test_recoverCatalog(self): + """Test recoverCatalog function.""" + # Test basic catalog recovery + res = self.conn.recoverCatalog() + self.assertIsInstance(res, dict) + self.assertIn("error", res) + self.assertIn("message", res) + if __name__ == "__main__": suite = unittest.TestSuite() @@ -56,6 +94,9 @@ def test_getUDF(self): # suite.addTest(test_pyTigerGraphGSQL("test_03_installUDF")) # suite.addTest(test_pyTigerGraphGSQL("test_04_installUDFRemote")) suite.addTest(test_pyTigerGraphGSQL("test_getUDF")) + suite.addTest(test_pyTigerGraphGSQL("test_getAsyncRequestStatus")) + suite.addTest(test_pyTigerGraphGSQL("test_cancelAsyncRequest")) + suite.addTest(test_pyTigerGraphGSQL("test_recoverCatalog")) runner = unittest.TextTestRunner(verbosity=2, failfast=True) runner.run(suite) diff --git a/tests/test_pyTigerGraphGSQLAsync.py b/tests/test_pyTigerGraphGSQLAsync.py index e80fac44..35e7bd46 100644 --- a/tests/test_pyTigerGraphGSQLAsync.py +++ b/tests/test_pyTigerGraphGSQLAsync.py @@ -49,6 +49,44 @@ async def test_getUDF(self): udf = await self.conn.getUDF(ExprFunctions=False) self.assertIn("class KafkaProducer", udf) + async def test_getAsyncRequestStatus(self): + """Test getAsyncRequestStatus function.""" + # Test with a sample request ID (this will likely fail in test environment) + # but we can test the function structure and error handling + test_request_id = "00000000006.317280417" + + try: + res = await self.conn.getAsyncRequestStatus(test_request_id) + self.assertIsInstance(res, dict) + self.assertIn("error", res) + self.assertIn("message", res) + except Exception as e: + # Expected to fail in test environment, but should be a proper error response + self.assertIsInstance(e, Exception) + + async def test_cancelAsyncRequest(self): + """Test cancelAsyncRequest function.""" + # Test with a sample request ID (this will likely fail in test environment) + # but we can test the function structure and error handling + test_request_id = "00000000006.317280417" + + try: + res = await self.conn.cancelAsyncRequest(test_request_id) + self.assertIsInstance(res, dict) + self.assertIn("error", res) + self.assertIn("message", res) + except Exception as e: + # Expected to fail in test environment, but should be a proper error response + self.assertIsInstance(e, Exception) + + async def test_recoverCatalog(self): + """Test recoverCatalog function.""" + # Test basic catalog recovery + res = await self.conn.recoverCatalog() + self.assertIsInstance(res, dict) + self.assertIn("error", res) + self.assertIn("message", res) + if __name__ == "__main__": # suite = unittest.TestSuite() From 78b9501df922ca4901d356f56a479550ede16653 Mon Sep 17 00:00:00 2001 From: Chengbiao Jin Date: Wed, 29 Oct 2025 21:43:03 -0700 Subject: [PATCH 08/10] Push authMode change to next major release --- pyTigerGraph/common/base.py | 44 +-- pyTigerGraph/pyTigerGraphAuth.py | 337 +++++++++++++++----- pyTigerGraph/pyTigerGraphBase.py | 31 +- pyTigerGraph/pyTigerGraphQuery.py | 1 - pyTigerGraph/pytgasync/pyTigerGraphAuth.py | 338 ++++++++++++++++----- pyTigerGraph/pytgasync/pyTigerGraphBase.py | 31 +- tests/test_pyTigerGraphGSQL.py | 8 +- tests/test_pyTigerGraphGSQLAsync.py | 8 +- tests/test_pyTigerGraphQuery.py | 3 +- tests/test_pyTigerGraphQueryAsync.py | 3 +- tests/test_pyTigerGraphSchema.py | 6 +- tests/test_pyTigerGraphSchemaAsync.py | 6 +- 12 files changed, 620 insertions(+), 196 deletions(-) diff --git a/pyTigerGraph/common/base.py b/pyTigerGraph/common/base.py index 31a9088c..a9bff04c 100644 --- a/pyTigerGraph/common/base.py +++ b/pyTigerGraph/common/base.py @@ -217,13 +217,10 @@ def __init__(self, host: str = "http://127.0.0.1", graphname: str = "", def _set_auth_header(self): """Set the authentication header based on available tokens or credentials.""" if self.jwtToken: - self.authMode = "token" return {"Authorization": "Bearer " + self.jwtToken} elif self.apiToken: - self.authMode = "token" return {"Authorization": "Bearer " + self.apiToken} else: - self.authMode = "pwd" return {"Authorization": "Basic {0}".format(self.base64_credential)} def _verify_jwt_token_support(self): @@ -279,7 +276,7 @@ def _error_check(self, res: dict) -> bool: ) return False - def _prep_req(self, headers, url, method, data): + def _prep_req(self, authMode, headers, url, method, data): logger.debug("entry: _prep_req") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) @@ -287,24 +284,31 @@ def _prep_req(self, headers, url, method, data): _headers = {} # If JWT token is provided, always use jwtToken as token - if isinstance(self.jwtToken, str) and self.jwtToken.strip() != "": - token = self.jwtToken - elif isinstance(self.apiToken, tuple): - token = self.apiToken[0] - elif isinstance(self.apiToken, str) and self.apiToken.strip() != "": - token = self.apiToken - else: - token = None + if authMode == "token": + if isinstance(self.jwtToken, str) and self.jwtToken.strip() != "": + token = self.jwtToken + elif isinstance(self.apiToken, tuple): + token = self.apiToken[0] + elif isinstance(self.apiToken, str) and self.apiToken.strip() != "": + token = self.apiToken + else: + token = None - if token: - self.authHeader = {'Authorization': "Bearer " + token} - _headers = self.authHeader - self.authMode = "token" + if token: + self.authHeader = {'Authorization': "Bearer " + token} + _headers = self.authHeader + else: + self.authHeader = { + 'Authorization': 'Basic {0}'.format(self.base64_credential)} + _headers = self.authHeader + self.authMode = "pwd" else: - self.authHeader = { - 'Authorization': 'Basic {0}'.format(self.base64_credential)} - _headers = self.authHeader - self.authMode = 'pwd' + if self.jwtToken: + _headers = {'Authorization': "Bearer " + self.jwtToken} + else: + _headers = {'Authorization': 'Basic {0}'.format( + self.base64_credential)} + self.authMode = "pwd" if headers: _headers.update(headers) diff --git a/pyTigerGraph/pyTigerGraphAuth.py b/pyTigerGraph/pyTigerGraphAuth.py index 1c14b31f..268dc5dd 100644 --- a/pyTigerGraph/pyTigerGraphAuth.py +++ b/pyTigerGraph/pyTigerGraphAuth.py @@ -25,30 +25,116 @@ class pyTigerGraphAuth(pyTigerGraphGSQL): - def getSecrets(self) -> Dict[str, str]: - """Issues a `SHOW SECRET` GSQL statement and returns the secret generated by that - statement. - Secrets are unique strings that serve as credentials when generating authentication tokens. + def getSecrets(self, userName: str = "", alias: str = "", createNew: bool = False) -> Dict[str, str]: + """Lists all secrets for the current user. + + For TigerGraph versions >= 4.0, uses the REST API endpoint. + For older versions, uses the GSQL command. + + Args: + userName (str, optional): + The user name for whom to list secrets. If not provided (TigerGraph 4.x only), + lists secrets for the default logged-in user. This parameter is only + supported in TigerGraph >= 4.0. + alias (str, optional): + The alias of a specific secret to retrieve. If not provided, all secrets + are returned. This parameter is only supported in TigerGraph >= 4.0. + createNew (bool, optional): + If True and no secrets are found (or the specified alias is not found), + automatically create a new secret. Defaults to False. + When creating a new secret: + - If `alias` is provided, creates a secret with that alias. + - If `alias` is not provided, creates a secret with auto-generated alias. + This parameter is only supported in TigerGraph >= 4.0. Returns: A dictionary of `alias: secret_string` pairs. Notes: - This function returns the masked version of the secret. The original value of the secret cannot - be retrieved after creation. + In TigerGraph versions < 4.0, this function returns the masked version of the secret. + The original value of the secret cannot be retrieved after creation. + In TigerGraph versions >= 4.0, the REST API returns secrets in plain text. + If `createNew` is True in TigerGraph < 4.0, this parameter is ignored. + + Endpoints: + - `GET /gsql/v1/secrets?userName=` (In TigerGraph versions >= 4.0) + - `GET /gsql/v1/secrets/` (In TigerGraph versions >= 4.0, when alias is provided) + - GSQL: `SHOW SECRET` (In TigerGraph versions < 4.0) """ logger.debug("entry: getSecrets") + if logger.level == logging.DEBUG: + logger.debug("params: " + self._locals(locals())) - res = self.gsql(""" - USE GRAPH {} - SHOW SECRET""".format(self.graphname), ) - ret = _parse_get_secrets(res) + # Try to use TigerGraph 4.x REST API first, if failed then use GSQL command + try: + if alias: + # Get specific secret by alias + try: + res = self._get(self.gsUrl+"/gsql/v1/secrets/"+alias, + authMode="pwd", + headers={'Content-Type': 'application/json'}) + except TigerGraphException as e: + # Secret not found + res = "" + + # Response format: {"alias": "...", "value": "..."} + ret = {} + + if res and isinstance(res, dict) and res.get("alias"): + # Secret found + ret[res.get("alias", "")] = res.get("value", "") + elif createNew: + # Secret not found and createNew is True + created_secret = self.createSecret(alias=alias, userName=userName, withAlias=True) + if isinstance(created_secret, dict): + ret.update(created_secret) + else: + # This shouldn't happen with withAlias=True, but handle it + ret[alias] = created_secret + else: + # Get all secrets + params = {} + if userName: + params["userName"] = userName + res = self._get(self.gsUrl+"/gsql/v1/secrets", + params=params, authMode="pwd", + headers={'Content-Type': 'application/json'}) + + # Response format: [{"alias": "...", "value": "..."}, ...] + ret = {} + + # Handle list response + if isinstance(res, list): + for item in res: + ret[item.get("alias", "")] = item.get("value", "") + + # If no secrets found and createNew is True, create a new one + if not ret and createNew: + created_secret = self.createSecret(userName=userName, withAlias=True) + if isinstance(created_secret, dict): + ret.update(created_secret) + else: + # This shouldn't happen with withAlias=True, but handle it + ret["AUTO_GENERATED"] = created_secret - if logger.level == logging.DEBUG: - logger.debug("return: " + str(ret)) - logger.debug("exit: getSecrets") + if logger.level == logging.DEBUG: + logger.debug("return: " + str(ret)) + logger.debug("exit: getSecrets") + + return ret + except Exception as e: + print(e) + # For older versions, use GSQL command + res = self.gsql(""" + USE GRAPH {} + SHOW SECRET""".format(self.graphname), ) + ret = _parse_get_secrets(res) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(ret)) + logger.debug("exit: getSecrets") - return ret + return ret def showSecrets(self) -> Dict[str, str]: """DEPRECATED @@ -60,93 +146,202 @@ def showSecrets(self) -> Dict[str, str]: return self.getSecrets() - def createSecret(self, alias: str = "", withAlias: bool = False) -> Union[str, Dict[str, str]]: - """Issues a `CREATE SECRET` GSQL statement and returns the secret generated by that statement. - Secrets are unique strings that serve as credentials when generating authentication tokens. + def createSecret(self, alias: str = "", withAlias: bool = False, value: str = "", userName: str = "" ) -> Union[str, Dict[str, str]]: + """Creates a secret for generating authentication tokens. + + For TigerGraph versions >= 4.0, uses the REST API endpoint. + For older versions, uses the GSQL command. Args: - alias: - The alias of the secret. / - The system will generate a random alias for the secret if the user does not provide - an alias for that secret. Randomly generated aliases begin with - `AUTO_GENERATED_ALIAS_` and include a random 7-character string. - withAlias: + alias (str, optional): + The alias of the secret. If not provided, a random alias starting with + `AUTO_GENERATED_ALIAS_` followed by a random 7-character string will be generated. + value (str, optional): + The secret value. If not provided (TigerGraph 4.x only), a random 32-character + string will be generated. This parameter is only supported in TigerGraph >= 4.0. + userName (str, optional): + The user name for whom the secret is created. If not provided (TigerGraph 4.x only), + the secret is created for the default logged-in user. This parameter is only + supported in TigerGraph >= 4.0. + withAlias (bool, optional): Return the new secret as an `{"alias": "secret"}` dictionary. This can be useful if - an alias was not provided, for example if it is auto-generated). + an alias was not provided, for example if it is auto-generated. Returns: - The secret string. + The secret string, or a dictionary with alias and secret if `withAlias` is True. Notes: Generally, secrets are generated by the database administrator and used to generate a token. If you use this function, please consider reviewing your internal processes of granting access to TigerGraph instances. Normally, this function should not be necessary and should not be executable by generic users. + + Endpoints: + - `POST /gsql/v1/secrets` (In TigerGraph versions >= 4.0) + - GSQL: `CREATE SECRET []` (In TigerGraph versions < 4.0) """ logger.debug("entry: createSecret") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) - res = self.gsql(""" - USE GRAPH {} - CREATE SECRET {} """.format(self.graphname, alias)) - secret = _parse_create_secret( - res, alias=alias, withAlias=withAlias) - - # Alias was not provided, let's find out the autogenerated one - # done in createSecret since need to call self.getSecrets which is a possibly async function - if withAlias and not alias: - masked = secret[:3] + "****" + secret[-3:] - secs = self.getSecrets() - for (a, s) in secs.items(): - if s == masked: - secret = {a: secret} + # Try to use TigerGraph 4.x REST API first, if failed then use GSQL command + try: + params = {} + if userName: + params["userName"] = userName + if alias: + params["alias"] = alias + if value: + params["value"] = value + + res = self._post(self.gsUrl+"/gsql/v1/secrets", + params=params, authMode="pwd", + headers={'Content-Type': 'application/json'}) + + # Response format: {"alias": "...", "value": "..."} + secret = res.get("value", "") + actual_alias = res.get("alias", alias) + + if withAlias: + if logger.level == logging.DEBUG: + logger.debug("return: " + str({actual_alias: secret})) + logger.debug("exit: createSecret") + return {actual_alias: secret} - if logger.level == logging.DEBUG: - logger.debug("return: " + str(secret)) - logger.debug("exit: createSecret") + if logger.level == logging.DEBUG: + logger.debug("return: " + str(secret)) + logger.debug("exit: createSecret") + return secret + except Exception as e: + print(e) + # For older versions, use GSQL command + res = self.gsql(""" + USE GRAPH {} + CREATE SECRET {} """.format(self.graphname, alias)) + secret = _parse_create_secret( + res, alias=alias, withAlias=withAlias) + + # Alias was not provided, let's find out the autogenerated one + # done in createSecret since need to call self.getSecrets which is a possibly async function + if withAlias and not alias: + masked = secret[:3] + "****" + secret[-3:] + secs = self.getSecrets() + for (a, s) in secs.items(): + if s == masked: + secret = {a: secret} - return secret + if logger.level == logging.DEBUG: + logger.debug("return: " + str(secret)) + logger.debug("exit: createSecret") - def dropSecret(self, alias: Union[str, list], ignoreErrors: bool = True) -> str: + return secret + + def dropSecret(self, alias: Union[str, list], ignoreErrors: bool = True, userName: str = "") -> Union[str, dict]: """Drops a secret. - See https://docs.tigergraph.com/tigergraph-server/current/user-access/managing-credentials#_drop_a_secret - Args: - alias: - One or more alias(es) of secret(s). - ignoreErrors: - Ignore errors arising from trying to drop non-existent secrets. + For TigerGraph versions >= 4.0, uses the REST API endpoint. + For older versions, uses the GSQL command. + + See https://docs.tigergraph.com/tigergraph-server/current/user-access/managing-credentials#_drop_a_secret + + Args: + alias: + One or more alias(es) or secret value(s) to drop. Can be a string or list of strings. + ignoreErrors: + Ignore errors arising from trying to drop non-existent secrets. + userName (str, optional): + The user name for whom to drop secrets. If not provided (TigerGraph 4.x only), + drops secrets for the default logged-in user. This parameter is only + supported in TigerGraph >= 4.0. + + Returns: + For TigerGraph versions < 4.0: Returns the GSQL response string. + For TigerGraph versions >= 4.0: Returns the REST API response dictionary. - Raises: - `TigerGraphException` if a non-existent secret is attempted to be dropped (unless - `ignoreErrors` is `True`). Re-raises other exceptions. + Raises: + `TigerGraphException` if a non-existent secret is attempted to be dropped (unless + `ignoreErrors` is `True`). Re-raises other exceptions. + + Endpoints: + - `DELETE /gsql/v1/secrets/` (In TigerGraph versions >= 4.0, for single alias without userName) + - `DELETE /gsql/v1/secrets?userName=` (In TigerGraph versions >= 4.0, with payload) + - GSQL: `DROP SECRET or ` (In TigerGraph versions < 4.0) """ logger.debug("entry: dropSecret") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) - if isinstance(alias, str): - alias = [alias] - cmd = """ - USE GRAPH {}""".format(self.graphname) - for a in alias: - cmd += """ - DROP SECRET {}""".format(a) - res = self.gsql(cmd) - if "Failed to drop secrets" in res and not ignoreErrors: - raise TigerGraphException(res) + # For TigerGraph 4.x, use REST API + if self._version_greater_than_4_0(): + # Normalize to list + secrets_list = [alias] if isinstance(alias, str) else alias - if logger.level == logging.DEBUG: - logger.debug("return: " + str(res)) - logger.debug("exit: dropSecret") + if not secrets_list: + raise TigerGraphException("No secret or alias provided.", 0) - return res + # Single alias without userName - use path parameter for cleaner API call + if len(secrets_list) == 1 and not userName: + single_secret = secrets_list[0] + try: + res = self._delete(self.gsUrl+"/gsql/v1/secrets/"+single_secret, + authMode="pwd", resKey="message", + headers={'Content-Type': 'application/json'}) + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: dropSecret") + return res + except Exception as e: + if not ignoreErrors: + raise + if logger.level == logging.DEBUG: + logger.debug("return: error ignored") + logger.debug("exit: dropSecret") + return {"error": False, "message": "Error ignored as requested"} + + # Multiple secrets/aliases or with userName - use payload + url = self.gsUrl+"/gsql/v1/secrets" + params = {} + if userName: + params["userName"] = userName + + data = {"secrets": secrets_list} + try: + res = self._delete(url, data=data, params=params, authMode="pwd", resKey="message", + headers={'Content-Type': 'application/json'}, jsonData=True) + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: dropSecret") + return res + except Exception as e: + if not ignoreErrors: + raise + if logger.level == logging.DEBUG: + logger.debug("return: error ignored") + logger.debug("exit: dropSecret") + return {"error": False, "message": "Error ignored as requested"} + else: + # For older versions, use GSQL command + if isinstance(alias, str): + alias = [alias] + cmd = """ + USE GRAPH {}""".format(self.graphname) + for a in alias: + cmd += """ + DROP SECRET {}""".format(a) + res = self.gsql(cmd) + if "Failed to drop secrets" in res and not ignoreErrors: + raise TigerGraphException(res) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: dropSecret") + + return res - def _token(self, secret: str = None, lifetime: int = None, token: str = None, _method: str = None, for_graph: bool = True) -> Union[tuple, str]: + def _token(self, secret: str = None, lifetime: int = None, token: str = None, _method: str = None, is_global: bool = True) -> Union[tuple, str]: method, url, alt_url, authMode, data, alt_data = _prep_token_request(self.restppUrl, self.gsUrl, - None if for_graph else self.graphname, + None if is_global else self.graphname, self.version, secret, lifetime, @@ -192,7 +387,7 @@ def getToken(self, secret: str = None, setToken: bool = True, lifetime: int = None, - for_graph: bool = True) -> Union[Tuple[str, str], str]: + is_global: bool = True) -> Union[Tuple[str, str], str]: """Requests an authorization token. This function returns a token only if REST++ authentication is enabled. If not, an exception @@ -232,7 +427,7 @@ def getToken(self, if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) - res, mainVer = self._token(secret, lifetime) + res, mainVer = self._token(secret, lifetime, is_global=is_global) token, auth_header = _parse_token_response(res, setToken, mainVer, diff --git a/pyTigerGraph/pyTigerGraphBase.py b/pyTigerGraph/pyTigerGraphBase.py index c75ab4a6..23bffa64 100644 --- a/pyTigerGraph/pyTigerGraphBase.py +++ b/pyTigerGraph/pyTigerGraphBase.py @@ -178,13 +178,12 @@ def _req(self, method: str, url: str, authMode: str = "token", headers: dict = N Returns: The (relevant part of the) response from the request (as a dictionary). """ - # Deprecated: authMode - _headers, _data, verify = self._prep_req(headers, url, method, data) + _headers, _data, verify = self._prep_req(authMode, headers, url, method, data) if "GSQL-TIMEOUT" in _headers: - http_timeout = (10, int(int(_headers["GSQL-TIMEOUT"])/1000) + 10) + http_timeout = (30, int(int(_headers["GSQL-TIMEOUT"])/1000) + 30) else: - http_timeout = None + http_timeout = (30, None) if jsonData: res = requests.request( @@ -438,11 +437,27 @@ def _version_greater_than_4_0(self) -> bool: Returns: Boolean of whether databse version is greater than 4.0. + + Note: + The result is cached to avoid repeated server calls. The cache is cleared + when the connection object is recreated. """ - version = self.getVer().split('.') - if version[0] >= "4" and version[1] > "0": - return True - return False + # Use cached value if available + if hasattr(self, '_cached_version_greater_than_4_0'): + return self._cached_version_greater_than_4_0 + + # Cache not set, fetch version and cache the result + try: + version = self.getVer().split('.') + except TigerGraphException as e: + if e.code == "REST-10016": + self.getToken() + version = self.getVer().split('.') + else: + raise e + result = version[0] >= "4" and version[1] > "0" + self._cached_version_greater_than_4_0 = result + return result def _validate_graphname(self, operation_name=""): """Validate that graphname is set for operations that require it.""" diff --git a/pyTigerGraph/pyTigerGraphQuery.py b/pyTigerGraph/pyTigerGraphQuery.py index d268ffc5..6e0c1699 100644 --- a/pyTigerGraph/pyTigerGraphQuery.py +++ b/pyTigerGraph/pyTigerGraphQuery.py @@ -464,7 +464,6 @@ def runInstalledQuery(self, queryName: str, params: Union[str, dict] = None, if params: if isinstance(params, dict): params = _parse_query_parameters(params) - logger.info("params: " + params) ret = self._req("GET", self.restppUrl + "/query/" + self.graphname + "/" + queryName, params=params, headers=headers, resKey=res_key) diff --git a/pyTigerGraph/pytgasync/pyTigerGraphAuth.py b/pyTigerGraph/pytgasync/pyTigerGraphAuth.py index 6c2f8230..e45ef3fa 100644 --- a/pyTigerGraph/pytgasync/pyTigerGraphAuth.py +++ b/pyTigerGraph/pytgasync/pyTigerGraphAuth.py @@ -23,31 +23,115 @@ class AsyncPyTigerGraphAuth(AsyncPyTigerGraphGSQL): - async def getSecrets(self) -> Dict[str, str]: - """Issues a `SHOW SECRET` GSQL statement and returns the secret generated by that - statement. - Secrets are unique strings that serve as credentials when generating authentication tokens. + async def getSecrets(self, userName: str = "", alias: str = "", createNew: bool = False) -> Dict[str, str]: + """Lists all secrets for the current user. + + For TigerGraph versions >= 4.0, uses the REST API endpoint. + For older versions, uses the GSQL command. + + Args: + userName (str, optional): + The user name for whom to list secrets. If not provided (TigerGraph 4.x only), + lists secrets for the default logged-in user. This parameter is only + supported in TigerGraph >= 4.0. + alias (str, optional): + The alias of a specific secret to retrieve. If not provided, all secrets + are returned. This parameter is only supported in TigerGraph >= 4.0. + createNew (bool, optional): + If True and no secrets are found (or the specified alias is not found), + automatically create a new secret. Defaults to False. + When creating a new secret: + - If `alias` is provided, creates a secret with that alias. + - If `alias` is not provided, creates a secret with auto-generated alias. + This parameter is only supported in TigerGraph >= 4.0. Returns: A dictionary of `alias: secret_string` pairs. Notes: - This function returns the masked version of the secret. The original value of the secret cannot - be retrieved after creation. + In TigerGraph versions < 4.0, this function returns the masked version of the secret. + The original value of the secret cannot be retrieved after creation. + In TigerGraph versions >= 4.0, the REST API returns secrets in plain text. + If `createNew` is True in TigerGraph < 4.0, this parameter is ignored. + + Endpoints: + - `GET /gsql/v1/secrets?userName=` (In TigerGraph versions >= 4.0) + - `GET /gsql/v1/secrets/` (In TigerGraph versions >= 4.0, when alias is provided) + - GSQL: `SHOW SECRET` (In TigerGraph versions < 4.0) """ logger.debug("entry: getSecrets") + if logger.level == logging.DEBUG: + logger.debug("params: " + self._locals(locals())) - res = await self.gsql(""" - USE GRAPH {} - SHOW SECRET""".format(self.graphname), ) - ret = _parse_get_secrets(res) + # Try to use TigerGraph 4.x REST API first, if failed then use GSQL command + try: + if alias: + # Get specific secret by alias + try: + res = await self._req("GET", self.gsUrl+"/gsql/v1/secrets/"+alias, + authMode="pwd", headers={'Content-Type': 'application/json'}) + except TigerGraphException as e: + # Secret not found + res = "" + + # Response format: {"alias": "...", "value": "..."} + ret = {} + + if res and isinstance(res, dict) and res.get("alias"): + # Secret found + ret[res.get("alias", "")] = res.get("value", "") + elif createNew: + # Secret not found and createNew is True + created_secret = await self.createSecret(alias=alias, userName=userName, withAlias=True) + if isinstance(created_secret, dict): + ret.update(created_secret) + else: + # This shouldn't happen with withAlias=True, but handle it + ret[alias] = created_secret + else: + # Get all secrets + params = {} + if userName: + params["userName"] = userName + res = await self._req("GET", self.gsUrl+"/gsql/v1/secrets", + params=params, authMode="pwd", + headers={'Content-Type': 'application/json'}) + + # Response format: [{"alias": "...", "value": "..."}, ...] + ret = {} + + # Handle list response + if isinstance(res, list): + for item in res: + ret[item.get("alias", "")] = item.get("value", "") + + # If no secrets found and createNew is True, create a new one + if not ret and createNew: + created_secret = await self.createSecret(userName=userName, withAlias=True) + if isinstance(created_secret, dict): + ret.update(created_secret) + else: + # This shouldn't happen with withAlias=True, but handle it + ret["AUTO_GENERATED"] = created_secret - if logger.level == logging.DEBUG: - logger.debug("return: " + str(ret)) - logger.debug("exit: getSecrets") + if logger.level == logging.DEBUG: + logger.debug("return: " + str(ret)) + logger.debug("exit: getSecrets") + + return ret + except Exception as e: + print(e) + # For older versions, use GSQL command + res = await self.gsql(""" + USE GRAPH {} + SHOW SECRET""".format(self.graphname), ) + ret = _parse_get_secrets(res) - return ret - # TODO Process response, return a dictionary of alias/secret pairs + if logger.level == logging.DEBUG: + logger.debug("return: " + str(ret)) + logger.debug("exit: getSecrets") + + return ret async def showSecrets(self) -> Dict[str, str]: """DEPRECATED @@ -60,93 +144,203 @@ async def showSecrets(self) -> Dict[str, str]: ret = await self.getSecrets() return ret - async def createSecret(self, alias: str = "", withAlias: bool = False) -> Union[str, Dict[str, str]]: - """Issues a `CREATE SECRET` GSQL statement and returns the secret generated by that statement. - Secrets are unique strings that serve as credentials when generating authentication tokens. + async def createSecret(self, alias: str = "", withAlias: bool = False, value: str = "", userName: str = "" ) -> Union[str, Dict[str, str]]: + """Creates a secret for generating authentication tokens. + + For TigerGraph versions >= 4.0, uses the REST API endpoint. + For older versions, uses the GSQL command. Args: - alias: - The alias of the secret. / - The system will generate a random alias for the secret if the user does not provide - an alias for that secret. Randomly generated aliases begin with - `AUTO_GENERATED_ALIAS_` and include a random 7-character string. - withAlias: + alias (str, optional): + The alias of the secret. If not provided, a random alias starting with + `AUTO_GENERATED_ALIAS_` followed by a random 7-character string will be generated. + value (str, optional): + The secret value. If not provided (TigerGraph 4.x only), a random 32-character + string will be generated. This parameter is only supported in TigerGraph >= 4.0. + userName (str, optional): + The user name for whom the secret is created. If not provided (TigerGraph 4.x only), + the secret is created for the default logged-in user. This parameter is only + supported in TigerGraph >= 4.0. + withAlias (bool, optional): Return the new secret as an `{"alias": "secret"}` dictionary. This can be useful if - an alias was not provided, for example if it is auto-generated). + an alias was not provided, for example if it is auto-generated. Returns: - The secret string. + The secret string, or a dictionary with alias and secret if `withAlias` is True. Notes: Generally, secrets are generated by the database administrator and used to generate a token. If you use this function, please consider reviewing your internal processes of granting access to TigerGraph instances. Normally, this function should not be necessary and should not be executable by generic users. + + Endpoints: + - `POST /gsql/v1/secrets` (In TigerGraph versions >= 4.0) + - GSQL: `CREATE SECRET []` (In TigerGraph versions < 4.0) """ logger.debug("entry: createSecret") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) - res = await self.gsql(""" - USE GRAPH {} - CREATE SECRET {} """.format(self.graphname, alias)) - secret = _parse_create_secret( - res, alias=alias, withAlias=withAlias) - - # Alias was not provided, let's find out the autogenerated one - # done in createSecret since need to call self.getSecrets which is a possibly async function - if withAlias and not alias: - masked = secret[:3] + "****" + secret[-3:] - secs = await self.getSecrets() - for a, s in secs.items(): - if s == masked: - secret = {a: secret} + # Try to use TigerGraph 4.x REST API first, if failed then use GSQL command + try: + params = {} + if userName is not None: + params["userName"] = userName + if alias: + params["alias"] = alias + if value: + params["value"] = value + + res = await self._req("POST", self.gsUrl+"/gsql/v1/secrets", + params=params, authMode="pwd", + headers={'Content-Type': 'application/json'}) + + # Response format: {"alias": "...", "value": "..."} + secret = res.get("value", "") + actual_alias = res.get("alias", alias) + + if withAlias: + if logger.level == logging.DEBUG: + logger.debug("return: " + str({actual_alias: secret})) + logger.debug("exit: createSecret") + return {actual_alias: secret} - if logger.level == logging.DEBUG: - logger.debug("return: " + str(secret)) - logger.debug("exit: createSecret") - return secret + if logger.level == logging.DEBUG: + logger.debug("return: " + str(secret)) + logger.debug("exit: createSecret") + return secret + except Exception as e: + print(e) + # For older versions, use GSQL command + res = await self.gsql(""" + USE GRAPH {} + CREATE SECRET {} """.format(self.graphname, alias)) + secret = _parse_create_secret( + res, alias=alias, withAlias=withAlias) + + # Alias was not provided, let's find out the autogenerated one + # done in createSecret since need to call self.getSecrets which is a possibly async function + if withAlias and not alias: + masked = secret[:3] + "****" + secret[-3:] + secs = await self.getSecrets() + for a, s in secs.items(): + if s == masked: + secret = {a: secret} - async def dropSecret(self, alias: Union[str, list], ignoreErrors: bool = True) -> str: + if logger.level == logging.DEBUG: + logger.debug("return: " + str(secret)) + logger.debug("exit: createSecret") + return secret + + async def dropSecret(self, alias: Union[str, list], ignoreErrors: bool = True, userName: str = "") -> Union[str, dict]: """Drops a secret. - See https://docs.tigergraph.com/tigergraph-server/current/user-access/managing-credentials#_drop_a_secret - Args: - alias: - One or more alias(es) of secret(s). - ignoreErrors: - Ignore errors arising from trying to drop non-existent secrets. + For TigerGraph versions >= 4.0, uses the REST API endpoint. + For older versions, uses the GSQL command. + + See https://docs.tigergraph.com/tigergraph-server/current/user-access/managing-credentials#_drop_a_secret + + Args: + alias: + One or more alias(es) or secret value(s) to drop. Can be a string or list of strings. + ignoreErrors: + Ignore errors arising from trying to drop non-existent secrets. + userName (str, optional): + The user name for whom to drop secrets. If not provided (TigerGraph 4.x only), + drops secrets for the default logged-in user. This parameter is only + supported in TigerGraph >= 4.0. + + Returns: + For TigerGraph versions < 4.0: Returns the GSQL response string. + For TigerGraph versions >= 4.0: Returns the REST API response dictionary. - Raises: - `TigerGraphException` if a non-existent secret is attempted to be dropped (unless - `ignoreErrors` is `True`). Re-raises other exceptions. + Raises: + `TigerGraphException` if a non-existent secret is attempted to be dropped (unless + `ignoreErrors` is `True`). Re-raises other exceptions. + + Endpoints: + - `DELETE /gsql/v1/secrets/` (In TigerGraph versions >= 4.0, for single alias without userName) + - `DELETE /gsql/v1/secrets?userName=` (In TigerGraph versions >= 4.0, with payload) + - GSQL: `DROP SECRET or ` (In TigerGraph versions < 4.0) """ logger.debug("entry: dropSecret") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) - if isinstance(alias, str): - alias = [alias] - cmd = """ - USE GRAPH {}""".format(self.graphname) - for a in alias: - cmd += """ - DROP SECRET {}""".format(a) - res = await self.gsql(cmd) + # For TigerGraph 4.x, use REST API + if await self._version_greater_than_4_0(): + # Normalize to list + secrets_list = [alias] if isinstance(alias, str) else alias - if "Failed to drop secrets" in res and not ignoreErrors: - raise TigerGraphException(res) + if not secrets_list: + raise TigerGraphException("No secret or alias provided.", 0) - if logger.level == logging.DEBUG: - logger.debug("return: " + str(res)) - logger.debug("exit: dropSecret") + # Single alias without userName - use path parameter for cleaner API call + if len(secrets_list) == 1 and not userName: + single_secret = secrets_list[0] + try: + res = await self._delete(self.gsUrl+"/gsql/v1/secrets/"+single_secret, + authMode="pwd", resKey="message", + headers={'Content-Type': 'application/json'}) + + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: dropSecret") + return res + except Exception as e: + if not ignoreErrors: + raise + if logger.level == logging.DEBUG: + logger.debug("return: error ignored") + logger.debug("exit: dropSecret") + return {"error": False, "message": "Error ignored as requested"} + + # Multiple secrets/aliases or with userName - use payload + url = self.gsUrl+"/gsql/v1/secrets" + params = {} + if userName: + params["userName"] = userName + + data = {"secrets": secrets_list} + try: + res = await self._delete(url, data=data, params=params, authMode="pwd", resKey="message", + headers={'Content-Type': 'application/json'}, jsonData=True) + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: dropSecret") + return res + except Exception as e: + if not ignoreErrors: + raise + if logger.level == logging.DEBUG: + logger.debug("return: error ignored") + logger.debug("exit: dropSecret") + return {"error": False, "message": "Error ignored as requested"} + else: + # For older versions, use GSQL command + if isinstance(alias, str): + alias = [alias] + cmd = """ + USE GRAPH {}""".format(self.graphname) + for a in alias: + cmd += """ + DROP SECRET {}""".format(a) + res = await self.gsql(cmd) + + if "Failed to drop secrets" in res and not ignoreErrors: + raise TigerGraphException(res) - return res + if logger.level == logging.DEBUG: + logger.debug("return: " + str(res)) + logger.debug("exit: dropSecret") + + return res - async def _token(self, secret: str = None, lifetime: int = None, token=None, _method=None, for_graph: bool = True) -> Union[tuple, str]: + async def _token(self, secret: str = None, lifetime: int = None, token=None, _method=None, is_global: bool = True) -> Union[tuple, str]: method, url, alt_url, authMode, data, alt_data = _prep_token_request(self.restppUrl, self.gsUrl, - self.graphname if for_graph else None, + None if is_global else self.graphname, secret=secret, lifetime=lifetime, token=token) @@ -178,12 +372,12 @@ async def _token(self, secret: str = None, lifetime: int = None, token=None, _me # uses mainVer instead of _versionGreaterThan4_0 since you need a token for verson checking return res, mainVer - async def getToken(self, secret: str = None, setToken: bool = True, lifetime: int = None, for_graph: bool = True) -> Union[tuple, str]: + async def getToken(self, secret: str = None, setToken: bool = True, lifetime: int = None, is_global: bool = True) -> Union[tuple, str]: logger.debug("entry: getToken") if logger.level == logging.DEBUG: logger.debug("params: " + self._locals(locals())) - res, mainVer = await self._token(secret, lifetime, for_graph=for_graph) + res, mainVer = await self._token(secret, lifetime, is_global=is_global) token, auth_header = _parse_token_response(res, setToken, mainVer, diff --git a/pyTigerGraph/pytgasync/pyTigerGraphBase.py b/pyTigerGraph/pytgasync/pyTigerGraphBase.py index 0573cb90..2edc7ffd 100644 --- a/pyTigerGraph/pytgasync/pyTigerGraphBase.py +++ b/pyTigerGraph/pytgasync/pyTigerGraphBase.py @@ -130,13 +130,12 @@ async def _req(self, method: str, url: str, authMode: str = "token", headers: di Returns: The (relevant part of the) response from the request (as a dictionary). """ - # Deprecated: authMode - _headers, _data, verify = self._prep_req(headers, url, method, data) + _headers, _data, verify = self._prep_req(authMode, headers, url, method, data) if "GSQL-TIMEOUT" in _headers: - http_timeout = (10, int(int(_headers["GSQL-TIMEOUT"])/1000) + 10) + http_timeout = (30, int(int(_headers["GSQL-TIMEOUT"])/1000) + 30) else: - http_timeout = None + http_timeout = (30, None) async with httpx.AsyncClient(timeout=None) as client: if jsonData: @@ -379,9 +378,25 @@ async def _version_greater_than_4_0(self) -> bool: Returns: Boolean of whether databse version is greater than 4.0. + + Note: + The result is cached to avoid repeated server calls. The cache is cleared + when the connection object is recreated. """ - version = await self.getVer() + # Use cached value if available + if hasattr(self, '_cached_version_greater_than_4_0'): + return self._cached_version_greater_than_4_0 + + # Cache not set, fetch version and cache the result + try: + version = self.getVer().split('.') + except TigerGraphException as e: + if e.code == "REST-10016": + self.getToken() + version = self.getVer().split('.') + else: + raise e version = version.split('.') - if version[0] >= "4" and version[1] > "0": - return True - return False + result = version[0] >= "4" and version[1] > "0" + self._cached_version_greater_than_4_0 = result + return result diff --git a/tests/test_pyTigerGraphGSQL.py b/tests/test_pyTigerGraphGSQL.py index 1e8a7c2d..0dcd72b5 100644 --- a/tests/test_pyTigerGraphGSQL.py +++ b/tests/test_pyTigerGraphGSQL.py @@ -39,14 +39,14 @@ def test_getUDF(self): self.assertEqual(res, "") # Get both ExprFunctions and ExprUtil (default) udf = self.conn.getUDF() - self.assertIn("init_kafka_producer", udf[0]) - self.assertIn("class KafkaProducer", udf[1]) + self.assertIn("ExprFunctions", udf[0]) + self.assertIn("ExprUtil", udf[1]) # Get ExprFunctions only udf = self.conn.getUDF(ExprUtil=False) - self.assertIn("init_kafka_producer", udf) + self.assertIn("ExprFunctions", udf) # Get ExprUtil only udf = self.conn.getUDF(ExprFunctions=False) - self.assertIn("class KafkaProducer", udf) + self.assertIn("ExprUtil", udf) def test_getAsyncRequestStatus(self): """Test getAsyncRequestStatus function.""" diff --git a/tests/test_pyTigerGraphGSQLAsync.py b/tests/test_pyTigerGraphGSQLAsync.py index 35e7bd46..0199c2e6 100644 --- a/tests/test_pyTigerGraphGSQLAsync.py +++ b/tests/test_pyTigerGraphGSQLAsync.py @@ -40,14 +40,14 @@ async def test_getUDF(self): self.assertEqual(res, "") # Get both ExprFunctions and ExprUtil (default) udf = await self.conn.getUDF() - self.assertIn("init_kafka_producer", udf[0]) - self.assertIn("class KafkaProducer", udf[1]) + self.assertIn("ExprFunctions", udf[0]) + self.assertIn("ExprUtil", udf[1]) # Get ExprFunctions only udf = await self.conn.getUDF(ExprUtil=False) - self.assertIn("init_kafka_producer", udf) + self.assertIn("ExprFunctions", udf) # Get ExprUtil only udf = await self.conn.getUDF(ExprFunctions=False) - self.assertIn("class KafkaProducer", udf) + self.assertIn("ExprUtil", udf) async def test_getAsyncRequestStatus(self): """Test getAsyncRequestStatus function.""" diff --git a/tests/test_pyTigerGraphQuery.py b/tests/test_pyTigerGraphQuery.py index 83dc1bd7..3f5f2fad 100644 --- a/tests/test_pyTigerGraphQuery.py +++ b/tests/test_pyTigerGraphQuery.py @@ -277,7 +277,8 @@ def test_dropQueries(self): self.assertIsInstance(res, dict) self.assertIn("error", res) - # Test dropping multiple queries + # Test dropping multiple queries (use queries that don't exist to test error handling) + # This should return an error response but still be a valid dict res = self.conn.dropQueries(["testQuery1", "testQuery2"]) self.assertIsInstance(res, dict) self.assertIn("error", res) diff --git a/tests/test_pyTigerGraphQueryAsync.py b/tests/test_pyTigerGraphQueryAsync.py index bdca3ddb..e7968c52 100644 --- a/tests/test_pyTigerGraphQueryAsync.py +++ b/tests/test_pyTigerGraphQueryAsync.py @@ -250,7 +250,8 @@ async def test_dropQueries(self): self.assertIsInstance(res, dict) self.assertIn("error", res) - # Test dropping multiple queries + # Test dropping multiple queries (use queries that don't exist to test error handling) + # This should return an error response but still be a valid dict res = await self.conn.dropQueries(["testQuery1", "testQuery2"]) self.assertIsInstance(res, dict) self.assertIn("error", res) diff --git a/tests/test_pyTigerGraphSchema.py b/tests/test_pyTigerGraphSchema.py index 2cb584f4..7e016adb 100644 --- a/tests/test_pyTigerGraphSchema.py +++ b/tests/test_pyTigerGraphSchema.py @@ -496,7 +496,7 @@ def test_addGlobalVerticesToGraph(self): self.assertIn("message", res) # Test with specific target graph - res = self.conn.addGlobalVerticesToGraph(["TestVertex1"], target_graph="testGraph") + res = self.conn.addGlobalVerticesToGraph(["TestVertex1"], target_graph=self.conn.graphname) self.assertIsInstance(res, dict) self.assertIn("error", res) self.assertIn("message", res) @@ -513,10 +513,10 @@ def test_rebuildGraphEngine(self): self.assertIn("error", res) self.assertIn("message", res) - # Test with parameters + # Test with parameters (use existing vertex type from testserver.gsql) res = self.conn.rebuildGraphEngine( threadnum=2, - vertextype="TestVertex1", + vertextype="vertex4", path="/tmp/test_rebuild", force=True ) diff --git a/tests/test_pyTigerGraphSchemaAsync.py b/tests/test_pyTigerGraphSchemaAsync.py index 3e9fcd2d..4141e6d8 100644 --- a/tests/test_pyTigerGraphSchemaAsync.py +++ b/tests/test_pyTigerGraphSchemaAsync.py @@ -497,7 +497,7 @@ async def test_addGlobalVerticesToGraph(self): self.assertIn("message", res) # Test with specific target graph - res = await self.conn.addGlobalVerticesToGraph(["TestVertex1"], target_graph="testGraph") + res = await self.conn.addGlobalVerticesToGraph(["TestVertex1"], target_graph=self.conn.graphname) self.assertIsInstance(res, dict) self.assertIn("error", res) self.assertIn("message", res) @@ -514,10 +514,10 @@ async def test_rebuildGraphEngine(self): self.assertIn("error", res) self.assertIn("message", res) - # Test with parameters + # Test with parameters (use existing vertex type from testserver.gsql) res = await self.conn.rebuildGraphEngine( threadnum=2, - vertextype="TestVertex1", + vertextype="vertex4", path="/tmp/test_rebuild", force=True ) From 0645b43e5d19242566dd5ea279ae09254a1e93c2 Mon Sep 17 00:00:00 2001 From: Chengbiao Jin Date: Thu, 30 Oct 2025 16:29:22 -0700 Subject: [PATCH 09/10] Add optional param for runDocumentIngest() --- pyTigerGraph/ai/ai.py | 26 ++++++++++++++++++---- pyTigerGraph/pyTigerGraphAuth.py | 1 - pyTigerGraph/pytgasync/pyTigerGraphAuth.py | 1 - 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/pyTigerGraph/ai/ai.py b/pyTigerGraph/ai/ai.py index 01ffec9d..dfb365b5 100644 --- a/pyTigerGraph/ai/ai.py +++ b/pyTigerGraph/ai/ai.py @@ -247,7 +247,7 @@ def initializeServer(self, server="graphrag"): url = f"{self.nlqs_host}/{self.conn.graphname}/{self.server_mode}/initialize" return self.conn._req("POST", url, authMode="pwd", resKey=None) - def createDocumentIngest(self, data_source, data_source_config, loader_config, file_format): + def createDocumentIngest(self, data_source="", data_source_config={}, loader_config={}, file_format=""): """ Create a document ingest. Args: data_source (str): @@ -271,7 +271,7 @@ def createDocumentIngest(self, data_source, data_source_config, loader_config, f url = f"{self.nlqs_host}/{self.conn.graphname}/{self.server_mode}/create_ingest" return self.conn._req("POST", url, authMode="pwd", data=data, jsonData=True, resKey=None) - def runDocumentIngest(self, load_job_id, data_source_id, data_path, data_source="remote"): + def runDocumentIngest(self, load_job_id="", data_source_id="", data_path="", data_source="", load_job_info: dict = None): """ Run a document ingest. Args: load_job_id (str): @@ -280,17 +280,35 @@ def runDocumentIngest(self, load_job_id, data_source_id, data_path, data_source= The data source ID of the document ingest. data_path (str): The data path of the document ingest. + data_source (str): + The data source of the document ingest. + load_job_info (dict): + The information of the load job. Returns: JSON response from the document ingest. """ - if data_source.lower() == "local" or data_path.startswith(("/", ".", "~")) : + if load_job_info: + if not load_job_id and "load_job_id" in load_job_info: + load_job_id = load_job_info["load_job_id"] + if not data_source_id and "data_source_id" in load_job_info: + data_source_id = load_job_info["data_source_id"] + if not data_path and "data_path" in load_job_info: + data_path = load_job_info["data_path"] + if not data_source and "data_source" in load_job_info: + data_source = load_job_info["data_source"] + + if data_source.lower() == "local" and data_path.startswith(("/", ".", "~")) : return self.conn.runLoadingJobWithFile(data_path, data_source_id, load_job_id) else: data = { "load_job_id": load_job_id, - "data_source_id": data_source_id, "file_path": data_path } + if load_job_info: + data["load_job_info"] = load_job_info + if data_source_id: + data["data_source_id"] = data_source_id + url = f"{self.nlqs_host}/{self.conn.graphname}/{self.server_mode}/ingest" return self.conn._req("POST", url, authMode="pwd", data=data, jsonData=True, resKey=None) diff --git a/pyTigerGraph/pyTigerGraphAuth.py b/pyTigerGraph/pyTigerGraphAuth.py index 268dc5dd..67440db6 100644 --- a/pyTigerGraph/pyTigerGraphAuth.py +++ b/pyTigerGraph/pyTigerGraphAuth.py @@ -213,7 +213,6 @@ def createSecret(self, alias: str = "", withAlias: bool = False, value: str = "" logger.debug("exit: createSecret") return secret except Exception as e: - print(e) # For older versions, use GSQL command res = self.gsql(""" USE GRAPH {} diff --git a/pyTigerGraph/pytgasync/pyTigerGraphAuth.py b/pyTigerGraph/pytgasync/pyTigerGraphAuth.py index e45ef3fa..f5b99bb9 100644 --- a/pyTigerGraph/pytgasync/pyTigerGraphAuth.py +++ b/pyTigerGraph/pytgasync/pyTigerGraphAuth.py @@ -211,7 +211,6 @@ async def createSecret(self, alias: str = "", withAlias: bool = False, value: st logger.debug("exit: createSecret") return secret except Exception as e: - print(e) # For older versions, use GSQL command res = await self.gsql(""" USE GRAPH {} From 34841d5636431949e7689ab160dc0b6de882dc03 Mon Sep 17 00:00:00 2001 From: Chengbiao Jin Date: Thu, 30 Oct 2025 16:48:20 -0700 Subject: [PATCH 10/10] Add error check for runDocumentIngest() parameters --- pyTigerGraph/ai/ai.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyTigerGraph/ai/ai.py b/pyTigerGraph/ai/ai.py index dfb365b5..7f5f339d 100644 --- a/pyTigerGraph/ai/ai.py +++ b/pyTigerGraph/ai/ai.py @@ -297,6 +297,9 @@ def runDocumentIngest(self, load_job_id="", data_source_id="", data_path="", dat if not data_source and "data_source" in load_job_info: data_source = load_job_info["data_source"] + if not load_job_id or not data_path or not data_source_id and not load_job_info: + raise ValueError("load_job_id and data_path are required, one of data_source_id or load_job_info must be provided.") + if data_source.lower() == "local" and data_path.startswith(("/", ".", "~")) : return self.conn.runLoadingJobWithFile(data_path, data_source_id, load_job_id) else: