Пример #1
0
 def _repl_new(self):
     repl = replwrap.python()
     # replay all successfull commands so far
     for cmd in chain(self._prelude_cmds, self._user_cmds):
         output = repl.run_command(cmd)
     # return init REPL
     return repl
Пример #2
0
    def test_python(self):
        if platform.python_implementation() == 'PyPy':
            raise unittest.SkipTest(skip_pypy)

        p = replwrap.python()
        res = p.run_command('4+7')
        assert res.strip() == '11'

        res = p.run_command('for a in range(3): print(a)\n')
        assert res.strip().splitlines() == ['0', '1', '2']
Пример #3
0
    def test_python(self):
        if platform.python_implementation() == 'PyPy':
            raise unittest.SkipTest("This test fails on PyPy because of REPL differences")

        p = replwrap.python()
        res = p.run_command('4+7')
        assert res.strip() == '11'

        res = p.run_command('for a in range(3): print(a)\n')
        assert res.strip().splitlines() == ['0', '1', '2']
Пример #4
0
    def test_python(self):
        if platform.python_implementation() == "PyPy":
            raise unittest.SkipTest(skip_pypy)

        p = replwrap.python()
        res = p.run_command("4+7")
        assert res.strip() == "11"

        res = p.run_command("for a in range(3): print(a)\n")
        assert res.strip().splitlines() == ["0", "1", "2"]
    def test_python(self):
        if platform.python_implementation() == 'PyPy':
            raise unittest.SkipTest("This test fails on PyPy because of REPL differences")

        p = replwrap.python()
        res = p.run_command('4+7')
        assert res.strip() == '11'

        res = p.run_command('for a in range(3): print(a)\n')
        assert res.strip().splitlines() == ['0', '1', '2']
Пример #6
0
    def test_python(self):
        if platform.python_implementation() == 'PyPy':
            raise unittest.SkipTest(skip_pypy)

        p = replwrap.python()
        res = p.run_command('4+7')
        assert res.strip() == '11'

        res = p.run_command('for a in range(3): print(a)\n')
        assert res.strip().splitlines() == ['0', '1', '2']
Пример #7
0
class CypherKernel(Kernel):
    implementation = 'Cypher'
    implementation_version = '0.1'
    language = 'cypher'
    language_version = '0.1'
    language_info = {
        # Switched that to cypher, see
        # https://github.com/jupyter/help/issues/301
        'name': 'cypher',
        'mimetype': 'text/cypher',
        'file_extension': '.cql',
    }
    banner = "Cypher kernel - Neo4j in Jupyter Notebooks"

    # Got the keywords from:
    # http://neo4j.com/docs/developer-manual/current/cypher/syntax/reserved/
    keywords = [
        'CALL', 'CREATE', 'DELETE', 'DETACH', 'EXISTS', 'FOREACH', 'LOAD',
        'MATCH', 'MERGE', 'OPTIONAL', 'REMOVE', 'RETURN', 'SET', 'START',
        'UNION', 'UNWIND', 'WITH', 'LIMIT', 'ORDER', 'SKIP', 'WHERE', 'YIELD',
        'ASC', 'ASCENDING', 'ASSERT', 'BY', 'CSV', 'DESC', 'DESCENDING', 'ON',
        'ALL', 'CASE', 'ELSE', 'END', 'THEN', 'WHEN', 'AND', 'AS', 'CONTAINS',
        'DISTINCT', 'ENDS', 'IN', 'IS', 'NOT', 'OR', 'STARTS', 'XOR',
        'CONSTRAINT', 'CREATE', 'DROP', 'EXISTS', 'INDEX', 'NODE', 'KEY',
        'UNIQUE', 'INDEX', 'JOIN', 'PERIODIC', 'COMMIT', 'SCAN', 'USING',
        'false', 'null', 'true', 'ADD', 'DO', 'FOR', 'MANDATORY', 'OF',
        'REQUIRE', 'SCALAR', 'EXPLAIN', 'PROFILE'
    ]

    global_node_colors = {}

    my_python = python(command='python')
    my_python.run_command("""import ast
import pandas as pd
import networkx as nx
G = nx.Graph()
df = pd.DataFrame()""")

    if platform.system() == 'Windows':
        # TODO: what shall I do on Windows here???
        # my_shell = ...
        pass
    else:
        my_shell = bash(command='bash')

    @property
    def cfg(self):
        cfg = CypherKernel._parse_config()
        return cfg

    @property
    def user(self):
        return self.cfg['user']

    @property
    def pwd(self):
        return self.cfg['pwd']

    @property
    def host(self):
        return self.cfg['host']

    @property
    def connect_result_nodes(self):
        return self.cfg['connect_result_nodes']

    @property
    def cmd_timeout(self):
        return self.cfg['cmd_timeout']

    def start_cypher_shell(self):
        if platform.system() == 'Windows':
            cypher_shell_bin = os.path.join('java', 'cypher-shell.bat')
        else:
            cypher_shell_bin = 'java/cypher-shell'
        cypher_shell_bin = os.path.join(
            os.path.dirname(os.path.abspath(__file__)), cypher_shell_bin)
        cypher = REPLWrapper(
            f'{cypher_shell_bin} -u {self.user} -p {self.pwd} --format verbose',
            'neo4j> ',
            None,
            continuation_prompt='  ...: ')
        return cypher

    def __init__(self, **kwargs):
        Kernel.__init__(self, **kwargs)
        self.cypher_shell = self.start_cypher_shell()

    @staticmethod
    def _parse_config():
        """
        Parses spawn YAML command options from the default Jupyter configuration directory.
        http://jupyter.readthedocs.io/en/latest/projects/jupyter-directories.html#configuration-files
        """
        config_dir = os.environ.get('JUPYTER_CONFIG_DIR')
        if not config_dir:
            config_dir = '.jupyter'
        config_path = os.path.join(os.path.expanduser('~'), config_dir,
                                   'cypher_config.yml')
        default_config = {
            'user': '******',
            'pwd': 'neo4j',
            'host': 'localhost:7474',
            'connect_result_nodes': False,
            'cmd_timeout': None
        }
        try:
            config = yaml.load(open(config_path))
            if len([
                    k for k in
                ['user', 'pwd', 'host', 'connect_result_nodes', 'cmd_timeout']
                    if k in config.keys()
            ]) == 5:
                return config
        except FileNotFoundError:
            # Using default configuration
            return default_config
        return default_config

    def _response_to_js_graph(self,
                              nodes,
                              relations,
                              elemen_id,
                              node_types=[]):
        # TODO: Make this use the local version of the package!
        # if platform == 'Windows':
        #     vis_bin = os.path.join('js', 'vis.min')
        # else:
        #     vis_bin = 'js/vis.min'
        # vis_bin = os.path.join(os.path.dirname(os.path.abspath(__file__)),
        #                        vis_bin)
        # require.config({
        # paths: {
        #     vis: '{{vis_path}}'
        #   }
        # });
        template_str = '''require(["https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.js"], function(vis) {
  var nodes = new vis.DataSet([
    {% for n in nodes %}{ id: {{ n.id }}, label: "{{ n.label }}", title: "{{ n.properties_long }}", color: 'rgba({{node_colors[n.label]}})'},
    {% endfor %}
  ]);

  // create an array with edges
  var edges = new vis.DataSet([
    {% for r in rels %}{ from: {{ r.start_node }},to: {{ r.end_node }}, arrows:'to', title: "{{ r.properties_long }}" },
    {% endfor %}
  ]);

  // create a network
  var container = document.getElementById('{{elemen_id}}');
  var data = {
    nodes: nodes,
    edges: edges
  };

  var options = {
    edges: {
      arrows: {
        to: {
          scaleFactor: 0.5
        }
      }
    },
    width: '100%',
    height: '500px',
    interaction: {hover: true}
  };

  var network = new vis.Network(container, data, options);});
'''
        template = Template(template_str)
        graphJS = template.render(nodes=nodes,
                                  rels=relations,
                                  elemen_id=elemen_id,
                                  node_colors=self.global_node_colors)

        return graphJS

    def _send_query_to_cypher_shell(self, code):

        # # Prepare input, remove newline characters as cypher-shell does not
        # # seem to be able to handle it...
        # code = ' '.join(code.splitlines())
        if not code.endswith(';'):
            # It cannot handle strings without semicolon either
            code += ';'

        res = self.cypher_shell.run_command(
            code, timeout=self.cmd_timeout).splitlines()
        # res[0] = res[0].replace('\x1b[m', '')
        content_idx = find_start_of_output(res)
        if content_idx > 0:
            content_idx = content_idx - 1
        return res, '\n'.join(res[content_idx:-1])

    def _color_nodes(self, nodes):
        for n in nodes:
            if not n.label in self.global_node_colors.keys():
                rgb = [str(random.randint(0, 255)) for _ in range(3)]
                rgba = rgb + ['0.5']
                self.global_node_colors[n.label] = ','.join(rgba)

    def _clean_input(self, code):
        lines = code.splitlines()
        clean_input = '\n'.join([l for l in lines if l])
        return clean_input

    def _is_magic(self, code):
        magic_lines = code.splitlines()
        magic_line = magic_lines[0].strip()
        if magic_line.startswith('%%'):
            return magic_line.replace('%%', ''), '\n'.join(magic_lines[1:])
        else:
            return None, None

    def _send_to_bash(self, code):
        res = self.my_shell.run_command(code, timeout=self.cmd_timeout)
        return res

    def _send_to_python(self, code):
        res = self.my_python.run_command(code, timeout=self.cmd_timeout)
        return res

    def _push_to_python_env(self, header, content):
        code = '''header = ast.literal_eval("""{}""")
content = ast.literal_eval("""{}""")
df = pd.DataFrame(content, columns=header)
df'''.format(
            str(header).replace('\'', '\\\''),
            str(content).replace('\'', '\\\''))
        res = self._send_to_python(code)
        return res

    def do_execute(self,
                   code,
                   silent,
                   store_history=True,
                   user_expressions=None,
                   allow_stdin=False):

        clean_input = self._clean_input(code)
        magic, magic_code = self._is_magic(code)
        if magic == 'bash' and magic_code:
            response = self._send_to_bash(magic_code)
            if not silent:
                result = {
                    'data': {
                        'text/plain': response
                    },
                    'execution_count': self.execution_count
                }
                self.send_response(self.iopub_socket, 'execute_result', result)

            exec_result = {
                'status': 'ok',
                'execution_count': self.execution_count,
                'payload': [],
                'user_expressions': {}
            }

            return exec_result
        elif magic == 'python':
            # TODO! implement me, convert latest cypher query to networkx graph
            response = self._send_to_python(magic_code)
            if not silent:
                result = {
                    'data': {
                        'text/plain': response
                    },
                    'execution_count': self.execution_count
                }
                self.send_response(self.iopub_socket, 'execute_result', result)

            exec_result = {
                'status': 'ok',
                'execution_count': self.execution_count,
                'payload': [],
                'user_expressions': {}
            }
            return exec_result
        elif magic:
            # TODO: implement an error for any other magic
            exec_result = {
                'status': 'error',
                'execution_count': self.execution_count,
                'payload': [],
                'user_expressions': {}
            }
            return exec_result

        # then it is a query to Cypher
        line_response, text_response = self._send_query_to_cypher_shell(code)
        error, parse_result = parse_output(line_response)
        df_header, df_content = parse_output_to_python(text_response)
        if df_header and df_content:
            _ = self._push_to_python_env(df_header, df_content)

        if error:
            pass
        else:
            nodes, relations = parse_result
            self._color_nodes(nodes)

            if not silent and nodes:
                # Only return the visual output when there are actually nodes and relations, as long as auto connection is not implemented also put it there when only nodes exist
                element_id = uuid.uuid4()
                graphJS = self._response_to_js_graph(nodes, relations,
                                                     element_id)

                graph_HTML_tmpl = """<link href="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.css" rel="stylesheet" type="text/css">
                <div id="{{ element_id }}"></div>
                """
                html_template = Template(graph_HTML_tmpl)
                graph_HTML = html_template.render(element_id=element_id)

                html_msg = {
                    'data': {
                        'text/html': graph_HTML
                    },
                    'execution_count': self.execution_count
                }
                js_msg = {'data': {'application/javascript': graphJS}}
                self.send_response(self.iopub_socket, 'display_data', js_msg)
                self.send_response(self.iopub_socket, 'display_data', html_msg)

        if not silent:
            # No matter what, this is the text response
            result = {
                'data': {
                    'text/plain': text_response
                },
                'execution_count': self.execution_count
            }
            self.send_response(self.iopub_socket, 'execute_result', result)

        exec_result = {
            'status': 'ok',
            'execution_count': self.execution_count,
            'payload': [],
            'user_expressions': {}
        }

        return exec_result

    def do_complete(self, code, cursor_pos):
        space_idxs = [i for i, l in enumerate(code) if l == ' ']
        low_idxs = [s for s in space_idxs if s < cursor_pos]
        if low_idxs:
            low_cp = max([s for s in space_idxs if s < cursor_pos]) + 1
            key_start = code[low_cp:cursor_pos]
        else:
            low_cp = 0
            key_start = code[:cursor_pos]

        matches = [k for k in self.keywords if k.startswith(key_start)]
        content = {
            'matches': matches,
            'cursor_start': low_cp,
            'cursor_end': cursor_pos,
            'metadata': {},
            'status': 'ok'
        }
        return content
Пример #8
0
 def my_python(self):
     my_python = python(command='python')
     my_python.run_command('import networkx as nx;G = nx.Graph()')
     return my_python