"""Top-level import of class PyGraphistry as "Graphistry". Used to connect to the Graphistry server and then create a base plotter.""" from __future__ import absolute_import from __future__ import print_function from future import standard_library standard_library.install_aliases() from builtins import bytes, object, str from past.utils import old_div from past.builtins import basestring import calendar, gzip, io, json, os, numpy, pandas, requests, sched, sys, time, warnings from datetime import datetime from distutils.util import strtobool from .arrow_uploader import ArrowUploader from . import util from . import bolt_util import logging logger = logging.getLogger(__name__) EnvVarNames = { 'api_key': 'GRAPHISTRY_API_KEY', #'api_token': 'GRAPHISTRY_API_TOKEN', #'username': 'GRAPHISTRY_USERNAME', #'password': 'GRAPHISTRY_PASSWORD', 'api_version': 'GRAPHISTRY_API_VERSION', 'dataset_prefix': 'GRAPHISTRY_DATASET_PREFIX', 'hostname': 'GRAPHISTRY_HOSTNAME', 'protocol': 'GRAPHISTRY_PROTOCOL', 'client_protocol_hostname': 'GRAPHISTRY_CLIENT_PROTOCOL_HOSTNAME', 'certificate_validation': 'GRAPHISTRY_CERTIFICATE_VALIDATION' } config_paths = [ os.path.join('/etc/graphistry', '.pygraphistry'), os.path.join(os.path.expanduser('~'), '.pygraphistry'), os.environ.get('PYGRAPHISTRY_CONFIG', '') ] default_config = { 'api_key': None, # Dummy key 'api_token': None, 'api_token_refresh_ms': None, 'api_version': 1, 'dataset_prefix': 'PyGraphistry/', 'hostname': 'hub.graphistry.com', 'protocol': 'https', 'client_protocol_hostname': None, 'certificate_validation': True, 'store_token_creds_in_memory': False } def _get_initial_config(): config = default_config.copy() for path in config_paths: try: with open(path) as config_file: config.update(json.load(config_file)) except ValueError as e: util.warn('Syntax error in %s, skipping. (%s)' % (path, e.message)) pass except IOError: pass env_config = {k: os.environ.get(v) for k, v in EnvVarNames.items()} env_override = {k: v for k, v in env_config.items() if v != None} config.update(env_override) if not config['certificate_validation']: requests.packages.urllib3.disable_warnings() return config class PyGraphistry(object): _config = _get_initial_config() _tag = util.fingerprint() _is_authenticated = False @staticmethod def authenticate(): """Authenticate via already provided configuration (api=1,2). This is called once automatically per session when uploading and rendering a visualization. In api=3, if token_refresh_ms > 0 (defaults to 10min), this starts an automatic refresh loop. In that case, note that a manual .login() is still required every 24hr by default. """ if PyGraphistry.api_version() == 3: if not (PyGraphistry.api_token() is None): PyGraphistry.refresh() else: key = PyGraphistry.api_key() #Mocks may set to True, so bypass in that case if (key is None) and PyGraphistry._is_authenticated == False: util.error('In api=1 / api=2 mode, API key not set explicitly in `register()` or available at ' + EnvVarNames['api_key']) if not PyGraphistry._is_authenticated: PyGraphistry._check_key_and_version() PyGraphistry._is_authenticated = True @staticmethod def not_implemented_thunk(): raise Exception('Must call login() first') relogin = lambda: PyGraphistry.not_implemented_thunk() @staticmethod def login(username, password, fail_silent=False): """Authenticate and set token for reuse (api=3). If token_refresh_ms (default: 10min), auto-refreshes token. By default, must be reinvoked within 24hr.""" if PyGraphistry._config['store_token_creds_in_memory']: PyGraphistry.relogin = lambda: PyGraphistry.login(username, password, fail_silent) token = ArrowUploader( server_base_path=PyGraphistry.protocol() + '://' + PyGraphistry.server(), certificate_validation=PyGraphistry.certificate_validation())\ .login(username, password).token PyGraphistry.api_token(token) PyGraphistry._is_authenticated = True #starts auth loop PyGraphistry.authenticate() return PyGraphistry.api_token() @staticmethod def refresh(token=None, fail_silent=False): """Use self or provided JWT token to get a fresher one. If self token, internalize upon refresh.""" using_self_token = token is None try: if PyGraphistry.store_token_creds_in_memory(): logger.debug('JWT refresh via creds') return PyGraphistry.relogin() logger.debug('JWT refresh via token') if using_self_token: PyGraphistry._is_authenticated = False token = ArrowUploader( server_base_path=PyGraphistry.protocol() + '://' + PyGraphistry.server(), certificate_validation=PyGraphistry.certificate_validation())\ .refresh(PyGraphistry.api_token() if using_self_token else token).token if using_self_token: PyGraphistry.api_token(token) PyGraphistry._is_authenticated = True return PyGraphistry.api_token() except Exception as e: if not fail_silent: util.error('Failed to refresh token: %s' % str(e)) @staticmethod def verify_token(token=None, fail_silent=False) -> bool: """Return True iff current or provided token is still valid""" using_self_token = token is None try: logger.debug('JWT refresh') if using_self_token: PyGraphistry._is_authenticated = False ok = ArrowUploader( server_base_path=PyGraphistry.protocol() + '://' + PyGraphistry.server(), certificate_validation=PyGraphistry.certificate_validation())\ .verify(PyGraphistry.api_token() if using_self_token else token) if using_self_token: PyGraphistry._is_authenticated = ok return ok except Exception as e: if not fail_silent: util.error('Failed to verify token: %s' % str(e)) @staticmethod def server(value=None): """Get the hostname of the server or set the server using hostname or aliases. Also set via environment variable GRAPHISTRY_HOSTNAME.""" if value is None: return PyGraphistry._config['hostname'] # setter shortcuts = {} if value in shortcuts: resolved = shortcuts[value] PyGraphistry._config['hostname'] = resolved util.warn('Resolving alias %s to %s' % (value, resolved)) else: PyGraphistry._config['hostname'] = value @staticmethod def store_token_creds_in_memory(value=None): """Cache credentials for JWT token access. Default off due to not being safe.""" if value is None: return PyGraphistry._config['store_token_creds_in_memory'] else: PyGraphistry._config['store_token_creds_in_memory'] = value @staticmethod def client_protocol_hostname(value=None): """Get/set the client protocol+hostname for when display urls (distinct from uploading). Also set via environment variable GRAPHISTRY_CLIENT_PROTOCOL_HOSTNAME. Defaults to hostname and no protocol (reusing environment protocol)""" if value is None: cfg_client_protocol_hostname = PyGraphistry._config['client_protocol_hostname'] #skip doing protocol by default to match notebook's protocol cph = ('//' + PyGraphistry.server()) if cfg_client_protocol_hostname is None else cfg_client_protocol_hostname return cph else: PyGraphistry._config['client_protocol_hostname'] = value @staticmethod def api_key(value=None): """Set or get the API key. Also set via environment variable GRAPHISTRY_API_KEY.""" if value is None: return PyGraphistry._config['api_key'] # setter if value is not PyGraphistry._config['api_key']: PyGraphistry._config['api_key'] = value.strip() PyGraphistry._is_authenticated = False @staticmethod def api_token(value=None): """Set or get the API token. Also set via environment variable GRAPHISTRY_API_TOKEN.""" if value is None: return PyGraphistry._config['api_token'] # setter if value is not PyGraphistry._config['api_token']: PyGraphistry._config['api_token'] = value.strip() PyGraphistry._is_authenticated = False @staticmethod def api_token_refresh_ms(value=None): """Set or get the API token refresh interval in milliseconds. None and 0 interpreted as no refreshing.""" if value is None: return PyGraphistry._config['api_token_refresh_ms'] # setter if value is not PyGraphistry._config['api_token_refresh_ms']: PyGraphistry._config['api_token_refresh_ms'] = int(value) @staticmethod def protocol(value=None): """Set or get the protocol ('http' or 'https'). Set automatically when using a server alias. Also set via environment variable GRAPHISTRY_PROTOCOL.""" if value is None: return PyGraphistry._config['protocol'] # setter PyGraphistry._config['protocol'] = value @staticmethod def api_version(value=None): """Set or get the API version: 1 or 2 for 1.0 (deprecated), 3 for 2.0 Also set via environment variable GRAPHISTRY_API_VERSION.""" if value is None: return PyGraphistry._config['api_version'] # setter PyGraphistry._config['api_version'] = value @staticmethod def certificate_validation(value=None): """Enable/Disable SSL certificate validation (True, False). Also set via environment variable GRAPHISTRY_CERTIFICATE_VALIDATION.""" if value is None: return PyGraphistry._config['certificate_validation'] # setter v = bool(strtobool(value)) if isinstance(value, basestring) else value if v == False: requests.packages.urllib3.disable_warnings() PyGraphistry._config['certificate_validation'] = v @staticmethod def set_bolt_driver(driver=None): PyGraphistry._config['bolt_driver'] = bolt_util.to_bolt_driver(driver) @staticmethod def register(key=None, username=None, password=None, token=None, server=None, protocol=None, api=None, certificate_validation=None, bolt=None, token_refresh_ms=10*60*1000, store_token_creds_in_memory=None, client_protocol_hostname=None): """API key registration and server selection Changing the key effects all derived Plotter instances. Provide one of key (api=1,2) or username/password (api=3) or token (api=3). :param key: API key (1.0 API). :type key: Optional string. :param username: Account username (2.0 API). :type username: Optional string. :param password: Account password (2.0 API). :type password: Optional string. :param token: Valid Account JWT token (2.0). Provide token, or username/password, but not both. :type token: Optional string. :param server: URL of the visualization server. :type server: Optional string. :param certificate_validation: Override default-on check for valid TLS certificate by setting to True. :type certificate_validation: Optional bool. :param bolt: Neo4j bolt information. :type bolt: Optional driver or named constructor arguments for instantiating a new one. :param protocol: Protocol used to contact visualization server, defaults to "https". :type protocol: Optional string. :param token_refresh_ms: Ignored for now; JWT token auto-refreshed on plot() calls. :type token_refresh_ms: :param store_token_creds_in_memory: Store username/password in-memory for JWT token refreshes. Unsafe; not recommended. :type store_token_creds_in_memory: Optional bool. :param client_protocol_hostname: Override protocol and host shown in browser. Defaults to protocol/server or envvar GRAPHISTRY_CLIENT_PROTOCOL_HOSTNAME. :type client_protocol_hostname: Optional string. :returns: None. :rtype: None. **Example: Standard (2.0 api by username/password)** :: import graphistry graphistry.register(api=3, protocol='http', server='200.1.1.1', username='person', password='pwd') **Example: Standard (2.0 api by token)** :: import graphistry graphistry.register(api=3, protocol='http', server='200.1.1.1', token='abc') **Example: Remote browser to Graphistry-provided notebook server (2.0)** :: import graphistry graphistry.register(api=3, protocol='http', server='nginx', client_protocol_hostname='https://my.site.com', token='abc') **Example: Standard (1.0)** :: import graphistry graphistry.register(api=1, key="my api key") """ PyGraphistry.api_version(api) PyGraphistry.api_token_refresh_ms(token_refresh_ms) PyGraphistry.api_key(key) PyGraphistry.server(server) PyGraphistry.protocol(protocol) PyGraphistry.client_protocol_hostname(client_protocol_hostname) PyGraphistry.certificate_validation(certificate_validation) if not (store_token_creds_in_memory is None): PyGraphistry.store_token_creds_in_memory(bool(store_token_creds_in_memory)) if not (username is None) and not (password is None): PyGraphistry.login(username, password) PyGraphistry.api_token(token or PyGraphistry._config['api_token']) PyGraphistry.authenticate() PyGraphistry.set_bolt_driver(bolt) @staticmethod def hypergraph(raw_events, entity_types=None, opts={}, drop_na=True, drop_edge_attrs=False, verbose=True, direct=False): """Transform a dataframe into a hypergraph. :param Dataframe raw_events: Dataframe to transform :param List entity_types: Optional list of columns (strings) to turn into nodes, None signifies all :param Dict opts: See below :param bool drop_edge_attrs: Whether to include each row's attributes on its edges, defaults to False (include) :param bool verbose: Whether to print size information :param bool direct: Omit hypernode and instead strongly connect nodes in an event Create a graph out of the dataframe, and return the graph components as dataframes, and the renderable result Plotter. It reveals relationships between the rows and between column values. This transform is useful for lists of events, samples, relationships, and other structured high-dimensional data. The transform creates a node for every row, and turns a row's column entries into node attributes. If direct=False (default), every unique value within a column is also turned into a node. Edges are added to connect a row's nodes to each of its column nodes, or if direct=True, to one another. Nodes are given the attribute 'type' corresponding to the originating column name, or in the case of a row, 'EventID'. Consider a list of events. Each row represents a distinct event, and each column some metadata about an event. If multiple events have common metadata, they will be transitively connected through those metadata values. The layout algorithm will try to cluster the events together. Conversely, if an event has unique metadata, the unique metadata will turn into nodes that only have connections to the event node, and the clustering algorithm will cause them to form a ring around the event node. Best practice is to set EVENTID to a row's unique ID, SKIP to all non-categorical columns (or entity_types to all categorical columns), and CATEGORY to group columns with the same kinds of values. The optional ``opts={...}`` configuration options are: * 'EVENTID': Column name to inspect for a row ID. By default, uses the row index. * 'CATEGORIES': Dictionary mapping a category name to inhabiting columns. E.g., {'IP': ['srcAddress', 'dstAddress']}. If the same IP appears in both columns, this makes the transform generate one node for it, instead of one for each column. * 'DELIM': When creating node IDs, defines the separator used between the column name and node value * 'SKIP': List of column names to not turn into nodes. For example, dates and numbers are often skipped. * 'EDGES': For direct=True, instead of making all edges, pick column pairs. E.g., {'a': ['b', 'd'], 'd': ['d']} creates edges between columns a->b and a->d, and self-edges d->d. :returns: {'entities': DF, 'events': DF, 'edges': DF, 'nodes': DF, 'graph': Plotter} :rtype: Dictionary **Example** :: import graphistry h = graphistry.hypergraph(my_df) g = h['graph'].plot() """ from . import hyper return hyper.Hypergraph().hypergraph(PyGraphistry, raw_events, entity_types, opts, drop_na, drop_edge_attrs, verbose, direct) @staticmethod def bolt(driver = None): """ :param driver: Neo4j Driver or arguments for GraphDatabase.driver(**{...})** :return: Plotter w/neo4j Call this to create a Plotter with an overridden neo4j driver. **Example** :: import graphistry g = graphistry.bolt({ server: 'bolt://...', auth: ('<username>', '<password>') }) :: import neo4j import graphistry driver = neo4j.GraphDatabase.driver(...) g = graphistry.bolt(driver) """ from . import plotter return plotter.Plotter().bolt(driver) @staticmethod def cypher(query, params = {}): """ :param query: a cypher query :param params: cypher query arguments :return: Plotter with data from a cypher query. This call binds `source`, `destination`, and `node`. Call this to immediately execute a cypher query and store the graph in the resulting Plotter. :: import graphistry g = graphistry.bolt({ query='MATCH (a)-[r:PAYMENT]->(b) WHERE r.USD > 7000 AND r.USD < 10000 RETURN r ORDER BY r.USD DESC', params={ "AccountId": 10 }) """ from . import plotter return plotter.Plotter().cypher(query, params) @staticmethod def nodexl(xls_or_url, source='default', engine=None, verbose=False): """ :param xls_or_url: file/http path string to a nodexl-generated xls, or a pandas ExcelFile() object :param source: optionally activate binding by string name for a known nodexl data source ('twitter', 'wikimedia') :param engine: optionally set a pandas Excel engine :param verbose: optionally enable printing progress by overriding to True """ if not (engine is None): print('WARNING: Engine currently ignored, please contact if critical') from . import plotter return plotter.Plotter().nodexl(xls_or_url, source, engine, verbose) @staticmethod def name(name): """Upload name :param name: Upload name :type name: str""" from . import plotter return plotter.Plotter().name(name) @staticmethod def description(description): """Upload description :param description: Upload description :type description: str""" from . import plotter return plotter.Plotter().description(description) @staticmethod def bind(node=None, source=None, destination=None, edge_title=None, edge_label=None, edge_color=None, edge_weight=None, edge_icon=None, edge_size=None, edge_opacity=None, edge_source_color=None, edge_destination_color=None, point_title=None, point_label=None, point_color=None, point_weight=None, point_icon=None, point_size=None, point_opacity=None, point_x=None, point_y=None): """Create a base plotter. Typically called at start of a program. For parameters, see ``plotter.bind()`` . :returns: Plotter. :rtype: Plotter. **Example** :: import graphistry g = graphistry.bind() """ from . import plotter return plotter.Plotter().bind(source=source, destination=destination, node=node, \ edge_title=edge_title, edge_label=edge_label, edge_color=edge_color, edge_size=edge_size, edge_weight=edge_weight, edge_icon=edge_icon, edge_opacity=edge_opacity, edge_source_color=edge_source_color, edge_destination_color=edge_destination_color, point_title=point_title, point_label=point_label, point_color=point_color, point_size=point_size, point_weight=point_weight, point_icon=point_icon, point_opacity=point_opacity, point_x=point_x, point_y=point_y) @staticmethod def tigergraph( protocol = 'http', server = 'localhost', web_port = 14240, api_port = 9000, db = None, user = 'tigergraph', pwd = 'tigergraph', verbose = False ): """Register Tigergraph connection setting defaults :param protocol: Protocol used to contact the database. :type protocol: Optional string. :param server: Domain of the database :type server: Optional string. :param web_port: :type web_port: Optional integer. :param api_port: :type api_port: Optional integer. :param db: Name of the database :type db: Optional string. :param user: :type user: Optional string. :param pwd: :type pwd: Optional string. :param verbose: Whether to print operations :type verbose: Optional bool. :returns: Plotter. :rtype: Plotter. **Example: Standard** :: import graphistry tg = graphistry.tigergraph(protocol='https', server='acme.com', db='my_db', user='alice', pwd='tigergraph2') """ from . import plotter return plotter.Plotter().tigergraph(protocol, server, web_port, api_port, db, user, pwd, verbose) @staticmethod def gsql_endpoint(self, method_name, args = {}, bindings = None, db = None, dry_run = False): """Invoke Tigergraph stored procedure at a user-definend endpoint and return transformed Plottable :param method_name: Stored procedure name :type method_name: String. :param args: Named endpoint arguments :type args: Optional dictionary. :param bindings: Mapping defining names of returned 'edges' and/or 'nodes', defaults to @@nodeList and @@edgeList :type bindings: Optional dictionary. :param db: Name of the database, defaults to value set in .tigergraph(...) :type db: Optional string. :param dry_run: Return target URL without running :type dry_run: Bool, defaults to False :returns: Plotter. :rtype: Plotter. **Example: Minimal** :: import graphistry tg = graphistry.tigergraph(db='my_db') tg.gsql_endpoint('neighbors').plot() **Example: Full** :: import graphistry tg = graphistry.tigergraph() tg.gsql_endpoint('neighbors', {'k': 2}, {'edges': 'my_edge_list'}, 'my_db').plot() **Example: Read data** :: import graphistry tg = graphistry.tigergraph() out = tg.gsql_endpoint('neighbors') (nodes_df, edges_df) = (out._nodes, out._edges) """ from . import plotter return plotter.Plotter().gsql_endpoint(method_name, args, bindings, db, dry_run) @staticmethod def gsql(query, bindings = None, dry_run = False): """Run Tigergraph query in interpreted mode and return transformed Plottable :param query: Code to run :type query: String. :param bindings: Mapping defining names of returned 'edges' and/or 'nodes', defaults to @@nodeList and @@edgeList :type bindings: Optional dictionary. :param dry_run: Return target URL without running :type dry_run: Bool, defaults to False :returns: Plotter. :rtype: Plotter. **Example: Minimal** :: import graphistry tg = graphistry.tigergraph() tg.gsql(\"\"\" INTERPRET QUERY () FOR GRAPH Storage { OrAccum<BOOL> @@stop; ListAccum<EDGE> @@edgeList; SetAccum<vertex> @@set; @@set += to_vertex("61921", "Pool"); Start = @@set; while Start.size() > 0 and @@stop == false do Start = select t from Start:s-(:e)-:t where e.goUpper == TRUE accum @@edgeList += e having t.type != "Service"; end; print @@edgeList; } \"\"\").plot() **Example: Full** :: import graphistry tg = graphistry.tigergraph() tg.gsql(\"\"\" INTERPRET QUERY () FOR GRAPH Storage { OrAccum<BOOL> @@stop; ListAccum<EDGE> @@edgeList; SetAccum<vertex> @@set; @@set += to_vertex("61921", "Pool"); Start = @@set; while Start.size() > 0 and @@stop == false do Start = select t from Start:s-(:e)-:t where e.goUpper == TRUE accum @@edgeList += e having t.type != "Service"; end; print @@my_edge_list; } \"\"\", {'edges': 'my_edge_list'}).plot() """ from . import plotter return plotter.Plotter().gsql(query, bindings, dry_run) @staticmethod def nodes(nodes): from . import plotter return plotter.Plotter().nodes(nodes) @staticmethod def edges(edges): from . import plotter return plotter.Plotter().edges(edges) @staticmethod def graph(ig): from . import plotter return plotter.Plotter().graph(ig) @staticmethod def settings(height=None, url_params={}, render=None): from . import plotter return plotter.Plotter().settings(height, url_params, render) @staticmethod def _etl_url(): hostname = PyGraphistry._config['hostname'] protocol = PyGraphistry._config['protocol'] return '%s://%s/etl' % (protocol, hostname) @staticmethod def _check_url(): hostname = PyGraphistry._config['hostname'] protocol = PyGraphistry._config['protocol'] return '%s://%s/api/check' % (protocol, hostname) @staticmethod def _viz_url(info, url_params): splash_time = int(calendar.timegm(time.gmtime())) + 15 extra = '&'.join([ k + '=' + str(v) for k,v in list(url_params.items())]) cph = PyGraphistry.client_protocol_hostname() pattern = '%s/graph/graph.html?dataset=%s&type=%s&viztoken=%s&usertag=%s&splashAfter=%s&%s' return pattern % (cph, info['name'], info['type'], info['viztoken'], PyGraphistry._tag, splash_time, extra) @staticmethod def _coerce_str(v): try: return str(v) except UnicodeDecodeError: print('UnicodeDecodeError') print('=', v, '=') x = v.decode('utf-8') print('x', x) return x @staticmethod def _get_data_file(dataset, mode): out_file = io.BytesIO() if mode == 'json': json_dataset = None try: json_dataset = json.dumps(dataset, ensure_ascii=False, cls=NumpyJSONEncoder) except TypeError: warnings.warn("JSON: Switching from NumpyJSONEncoder to str()") json_dataset = json.dumps(dataset, default=PyGraphistry._coerce_str) with gzip.GzipFile(fileobj=out_file, mode='w', compresslevel=9) as f: if sys.version_info < (3,0) and isinstance(json_dataset, bytes): f.write(json_dataset) else: f.write(json_dataset.encode('utf8')) elif mode == 'vgraph': bin_dataset = dataset.SerializeToString() with gzip.GzipFile(fileobj=out_file, mode='w', compresslevel=9) as f: f.write(bin_dataset) else: raise ValueError('Unknown mode:', mode) size = old_div(len(out_file.getvalue()), 1024) if size >= 5 * 1024: print('Uploading %d kB. This may take a while...' % size) sys.stdout.flush() elif size > 50 * 1024: util.error('Dataset is too large (%d kB)!' % size) return out_file @staticmethod def _etl1(dataset): PyGraphistry.authenticate() headers = {'Content-Encoding': 'gzip', 'Content-Type': 'application/json'} params = {'usertag': PyGraphistry._tag, 'agent': 'pygraphistry', 'apiversion' : '1', 'agentversion': sys.modules['graphistry'].__version__, 'key': PyGraphistry.api_key()} out_file = PyGraphistry._get_data_file(dataset, 'json') response = requests.post(PyGraphistry._etl_url(), out_file.getvalue(), headers=headers, params=params, verify=PyGraphistry._config['certificate_validation']) response.raise_for_status() jres = response.json() if jres['success'] is not True: raise ValueError('Server reported error:', jres['msg']) else: return {'name': jres['dataset'], 'viztoken': jres['viztoken'], 'type': 'vgraph'} @staticmethod def _etl2(dataset): PyGraphistry.authenticate() vg = dataset['vgraph'] encodings = dataset['encodings'] attributes = dataset['attributes'] metadata = { 'name': dataset['name'], 'datasources': [ { 'type': 'vgraph', 'url': 'data0' } ], 'nodes': [ { 'count': vg.vertexCount, 'encodings': encodings['nodes'], 'attributes': attributes['nodes'] } ], 'edges': [ { 'count': vg.edgeCount, 'encodings': encodings['edges'], 'attributes': attributes['edges'] } ] } out_file = PyGraphistry._get_data_file(vg, 'vgraph') metadata_json = json.dumps(metadata, ensure_ascii=False, cls=NumpyJSONEncoder) parts = { 'metadata': ('metadata', metadata_json, 'application/json'), 'data0': ('data0', out_file.getvalue(), 'application/octet-stream') } params = {'usertag': PyGraphistry._tag, 'agent': 'pygraphistry', 'apiversion' : '2', 'agentversion': sys.modules['graphistry'].__version__, 'key': PyGraphistry.api_key()} response = requests.post(PyGraphistry._etl_url(), files=parts, params=params, verify=PyGraphistry._config['certificate_validation']) response.raise_for_status() jres = response.json() if jres['success'] is not True: raise ValueError('Server reported error:', jres['msg'] if 'msg' in jres else 'No Message') else: return {'name': jres['dataset'], 'viztoken': jres['viztoken'], 'type': 'jsonMeta'} @staticmethod def _check_key_and_version(): params = {'text': PyGraphistry.api_key()} try: response = requests.get(PyGraphistry._check_url(), params=params, timeout=(3,3), verify=PyGraphistry._config['certificate_validation']) response.raise_for_status() jres = response.json() cver = sys.modules['graphistry'].__version__ if 'pygraphistry' in jres and 'minVersion' in jres['pygraphistry'] and 'latestVersion' in jres['pygraphistry']: mver = jres['pygraphistry']['minVersion'] lver = jres['pygraphistry']['latestVersion'] if util.compare_versions(mver, cver) > 0: util.warn('Your version of PyGraphistry is no longer supported (installed=%s latest=%s). Please upgrade!' % (cver, lver)) elif util.compare_versions(lver, cver) > 0: print('A new version of PyGraphistry is available (installed=%s latest=%s).' % (cver, lver)) if jres['success'] is not True: util.warn(jres['error']) except Exception as e: util.warn('Could not contact %s. Are you connected to the Internet?' % PyGraphistry._config['hostname']) client_protocol_hostname = PyGraphistry.client_protocol_hostname store_token_creds_in_memory = PyGraphistry.store_token_creds_in_memory server = PyGraphistry.server protocol = PyGraphistry.protocol register = PyGraphistry.register login = PyGraphistry.login refresh = PyGraphistry.refresh api_token = PyGraphistry.api_token verify_token = PyGraphistry.verify_token bind = PyGraphistry.bind name = PyGraphistry.name description = PyGraphistry.description edges = PyGraphistry.edges nodes = PyGraphistry.nodes graph = PyGraphistry.graph settings = PyGraphistry.settings hypergraph = PyGraphistry.hypergraph bolt = PyGraphistry.bolt cypher = PyGraphistry.cypher nodexl = PyGraphistry.nodexl tigergraph = PyGraphistry.tigergraph gsql_endpoint = PyGraphistry.gsql_endpoint gsql = PyGraphistry.gsql class NumpyJSONEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, numpy.ndarray) and obj.ndim == 1: return obj.tolist() elif isinstance(obj, numpy.generic): return obj.item() elif isinstance(obj, type(pandas.NaT)): return None elif isinstance(obj, datetime): return obj.isoformat() return json.JSONEncoder.default(self, obj)