def describe_config(config_name: str, show_sensitive: bool): """Output all the parameters from a TgcliConfiguration, optionally showing sensitive data.""" configs = {} try: configs = get_configs(raise_on_nonexistent=True) except TgcliConfigurationError as e: cli.terminate(message=e.message, is_err=True) config = configs.get(config_name, None) if not config: cli.terminate(message=f"Configuration {config_name} not found.", is_err=True) cli.print_to_console(f"Configuration {config_name}") # Print configuration values cli.print_to_console(f"Server: {config.server}") cli.print_to_console(f"Client Version: {config.client_version}") cli.print_to_console(f"REST++ Port: {config.restpp_port}") cli.print_to_console(f"GS Port: {config.gs_port}") cli.print_to_console(f"Use Auth: {config.use_auth}") cli.print_to_console(f"Username: {config.username}") # Password password = "******" if show_sensitive: password = config.password cli.print_to_console(f"Password: {password}") # Secrets if show_sensitive: for graph_name, secret in config.secrets.items(): cli.print_to_console(f"Secret ({graph_name}): {secret}")
def get_initialized_tg_connection(config_name: str, graph_name: Optional[str] = None, require_graph: bool = False, clean_init: bool = False): """A wrapper to retrieve a working TigerGraph connection using CLI inputs""" if require_graph and not graph_name: cli.terminate(1, "A graph name is required for this command.", is_err=True) config = get_configs().get(config_name, None) if not config: cli.terminate(1, "Invalid configuration. Please provide a valid configuration name.", is_err=True) return get_tg_connection(config, graph_name, clean_init=clean_init)
def add_config(): """Adds a configuration - only supports interactive input for now""" new_config = __get_config_interactive__() curr_configs = get_configs() if curr_configs.get(new_config.name, None): # Make sure that we want to overwrite if not cli.get_input_bool( prompt= f"Configuration {new_config.name} already exists. Do you want to overwrite it?" ): cli.terminate(message="Add configuration cancelled.") # Overwriting a configuration may need a reinitialization of dependencies cli.print_to_console( f"Configuration {new_config.name} already exists. You may need to run " f"tgcli reinit-dependencies to update dependencies to reflect this new configuration." ) curr_configs[new_config.name] = new_config save_configs(curr_configs) cli.print_to_console( f"Configuration {new_config.name} added for server {new_config.server}" )
def run_gsql( config_name: str = typer.Argument(None, help=CONFIG_ARG_HELP), graph_name: str = typer.Argument(None, help=GRAPH_ARG_HELP), inline_command: str = typer.Option(None, "--command", help="Inline GSQL command"), file_command: Path = typer.Option( None, "--file", help="Filepath to load a GSQL command from.", exists=True, file_okay=True, dir_okay=False, readable=True, resolve_path=True), launch_editor: bool = typer.Option( False, "--editor", help="Launch an interactive editor to load the GSQL command")): """Run a GSQL query against a configuration through an inline command, file, or interactive editor""" conn = get_initialized_tg_connection(config_name=config_name, graph_name=graph_name) options = [] if graph_name: options = ["-g", graph_name] command = None # Get the GSQL command depending on the flag if inline_command: command = inline_command elif file_command: with open(file_command, "r") as cmd_file: command = cmd_file.read() elif launch_editor: command = cli.get_input_from_editor("") command = command.strip() if not command: cli.terminate(message="No command specified.", is_err=True) output = conn.gsql(command, options=options) cli.print_to_console(output)
def load_vertices( # Basic config config_name: str = typer.Argument(None, help=CONFIG_ARG_HELP), graph_name: str = typer.Argument(None, help=GRAPH_ARG_HELP), # Required attributes vertex_type: str = typer.Option(..., "--type", help="Vertex type to map data to.", prompt="Vertex type"), vertex_id_col: str = typer.Option( ..., "--id", help="Column name to set as the ID of the vertex", prompt="Column name for ID"), # No prompt here - must be provided via CLI (string split into chars because of typer processing) attrs: List[str] = typer. Option( [], "--attr", help= "Column name of an vertex attribute, multiple can be specified by using the flag multiple times. " "If no values are provided, all columns will be used.", ), # Data sources csv_filepath: Path = typer.Option( None, "--csv", help="CSV filepath to load vertices from.", exists=True, file_okay=True, dir_okay=False, readable=True, resolve_path=True), pickle_filepath: Path = typer.Option( None, "--pickle", help="Pickle filepath to load vertices from.", exists=True, file_okay=True, dir_okay=False, readable=True, resolve_path=True), json_filepath: Path = typer.Option( None, "--json", help="JSON filepath to load vertices from.", exists=True, file_okay=True, dir_okay=False, readable=True, resolve_path=True)): """Loads a set of vertices from a given datasource.""" conn = get_initialized_tg_connection(config_name=config_name, graph_name=graph_name, require_graph=True) num_upserted: int = 0 vertex_attributes = None df = None if attrs: vertex_attributes = {val: val for val in attrs} if csv_filepath: df = __get_df__(csv_filepath, "csv") elif pickle_filepath: df = __get_df__(pickle_filepath, "pickle") elif json_filepath: df = __get_df__(json_filepath, "json") if df is not None: num_upserted = conn.upsertVertexDataframe(df=df, vertexType=vertex_type, v_id=vertex_id_col, attributes=vertex_attributes) else: cli.terminate( message="No vertices loaded. Please specify a data source.") cli.print_to_console( f"Vertex load success. {num_upserted} vertices added.")
def load_edges( # Basic config config_name: str = typer.Argument(None, help=CONFIG_ARG_HELP), graph_name: str = typer.Argument(None, help=GRAPH_ARG_HELP), # Required items source_vertex_type: str = typer.Option( ..., "--source-type", help="Type name of the source vertex", prompt="Source vertex type"), source_vertex_id_col: str = typer.Option( ..., "--source-id", help="Column name for the source vertex ID", prompt="Source vertex ID column name"), target_vertex_type: str = typer.Option( ..., "--target-type", help="Type name of the target vertex", prompt="Target vertex type"), target_vertex_id_col: str = typer.Option( ..., "--target-id", help="Column name for the target vertex ID", prompt="Target vertex ID column name"), edge_type: str = typer.Option(..., "--edge-type", help="Type name of the edge", prompt="Edge type"), # No prompt here - must be provided via CLI (string split into chars because of typer processing) edge_attrs: List[str] = typer. Option( [], "--edge-attr", help= "Column name of an edge attribute, multiple can be specified by using the flag multiple times. " "If none are provided, all columns except for the source and target vertex ID columns are used.", ), # Data sources csv_filepath: Path = typer.Option( None, "--csv", help="CSV filepath to load vertices from.", exists=True, file_okay=True, dir_okay=False, readable=True, resolve_path=True), pickle_filepath: Path = typer.Option( None, "--pickle", help="Pickle filepath to load vertices from.", exists=True, file_okay=True, dir_okay=False, readable=True, resolve_path=True), json_filepath: Path = typer.Option( None, "--json", help="JSON filepath to load vertices from.", exists=True, file_okay=True, dir_okay=False, readable=True, resolve_path=True)): """Loads a set of edges from a given datasource.""" conn = get_initialized_tg_connection(config_name=config_name, graph_name=graph_name, require_graph=True) num_upserted: int = 0 df = None ignore_cols = {source_vertex_id_col, target_vertex_id_col} if csv_filepath: df = __get_df__(csv_filepath, "csv") elif pickle_filepath: df = __get_df__(pickle_filepath, "pickle") elif json_filepath: df = __get_df__(json_filepath, "json") if df is not None: edge_attributes = { val: val for val in df.columns if val not in ignore_cols } if edge_attrs: edge_attributes = {val: val for val in edge_attrs} num_upserted = conn.upsertEdgesDataframe( df=df, sourceVertexType=source_vertex_type, targetVertexType=target_vertex_type, edgeType=edge_type, from_id=source_vertex_id_col, to_id=target_vertex_id_col, attributes=edge_attributes) else: cli.terminate(message="No edges loaded. Please specify a data source.") cli.print_to_console(f"Edge load success. {num_upserted} edges added.")
def get_edges( # Basic config config_name: str = typer.Argument(None, help=CONFIG_ARG_HELP), graph_name: str = typer.Argument(None, help=GRAPH_ARG_HELP), # Required items source_vertex_type: str = typer.Option( ..., "--from-type", help="Type of the source vertex."), source_vertex_id: str = typer.Option(..., "--from-id", help="ID of the source vertex."), # Filter by target target_vertex_id: str = typer.Option(None, "--to-id", help="ID of the target vertex"), target_vertex_type: str = typer. Option( None, "--to-type", help="Type of the target vertex. Required if '--to-id' is specified."), edge_type: str = typer. Option( None, "--edge-type", help= "Type of the edge. Required if '--to-id' and '--to-type' are specified." ), # Generic query params attributes: List[str] = typer. Option( [], '--attr', help= "Attributes to return for each edge, multiple can be specified by using the flag multiple times. " "See https://docs.tigergraph.com/dev/restpp-api/built-in-endpoints#select." ), where: List[str] = typer. Option( [], '--where', help="A condition to match for returned edges, " "multiple can be specified by using the flag multiple times. " "Multiple conditions are joined with AND. " "See https://docs.tigergraph.com/dev/restpp-api/built-in-endpoints#filter. " "For string conditions, the literal can be escaped like so: '--where=gender=\\\"male\\\"'. " "Alternatively, string escapes can be replaced by the URL-encoded string '%22'." ), sort_by_attrs: List[str] = typer. Option( [], '--sort', help= "Attribute name to sort results by, multiple can be specified by using the flag multiple times. " "See https://docs.tigergraph.com/dev/restpp-api/built-in-endpoints#sort." ), limit: int = typer.Option( 10, '--limit', help="Maximum number of results to retrieve."), timeout: int = typer.Option(60, '--timeout', help="Timeout in seconds.")): """Get a set of edges""" conn = get_initialized_tg_connection(config_name=config_name, graph_name=graph_name, require_graph=True) if target_vertex_id and (not target_vertex_type or not edge_type): cli.terminate( message= "Target vertex ID is specified but target vertex type or edge type isn't.", is_err=True) output = conn.getEdges(sourceVertexType=source_vertex_type, sourceVertexId=source_vertex_id, targetVertexType=target_vertex_type, targetVertexId=target_vertex_id, edgeType=edge_type, select=preprocess_list_query(attributes), where=preprocess_list_query(where), sort=preprocess_list_query(sort_by_attrs), limit=limit, timeout=timeout) cli.print_to_console(output)