Exemple #1
0
 def __init__(self, completekey='tab', stdin=None, stdout=None, ctx=None):
     super(Shell, self).__init__(completekey=completekey,
                                 stdin=stdin,
                                 stdout=stdout)
     self.execer = Execer()
     env = builtins.__xonsh_env__
     if ctx is not None:
         self.ctx = ctx
     else:
         rc = env.get('XONSHRC', None)
         self.ctx = xonshrc_context(rcfile=rc, execer=self.execer)
     self.ctx['__name__'] = '__main__'
     self.completer = Completer()
     self.buffer = []
     self.need_more_lines = False
     self.mlprompt = None
     setup_readline()
    def __init__(self, debug_level=0, session_id=None, config=None, **kwargs):
        """
        Parameters
        ----------
        debug_level : int, optional
            Integer from 0 (no debugging) to 3 (all debugging), default: 0.
        session_id : str or None, optional
            Unique string id representing the kernel session. If None, this will
            be replaced with a random UUID.
        config : dict or None, optional
            Configuration dictionary to start server with. BY default will
            search the command line for options (if given) or use default
            configuration.
        """
        self.debug_level = debug_level
        self.session_id = str(uuid.uuid4()) if session_id is None else session_id
        self._parser = None
        self.config = self.make_default_config() if config is None else config

        self.exiting = False
        self.execution_count = 1
        self.completer = Completer()
Exemple #3
0
 def __init__(self, **kwargs):
     self.completer = Completer()
     super().__init__(**kwargs)
Exemple #4
0
class XonshKernel(MetaKernel):
    implementation = 'Calysto Xonsh Kernel'
    implementation_version = __version__
    language = 'xonsh'
    language_version = version
    banner = 'Xonsh - the Python-ish, BASHwards-looking shell'
    language_info = {'name': 'xonsh',
                     'pygments_lexer': 'xonsh',
                     'codemirror_mode': 'shell',
                     'mimetype': 'text/x-sh',
                     'file_extension': '.xsh',
                     'version': __version__
                     }

    def __init__(self, **kwargs):
        self.completer = Completer()
        super().__init__(**kwargs)

    def do_execute_direct(self, code, silent=False):
        out, err, interrupted = self._do_execute_direct(code)
        hist = builtins.__xonsh_history__
        if not silent:  # stdout response
            if out:
                self._respond_in_chunks('stdout', out.strip())
            if err:
                self._respond_in_chunks('stderr', err.strip())
            if hasattr(builtins, '_') and builtins._ is not None:
                # rely on sys.displayhook functionality
                self._respond_in_chunks('stdout', pformat(builtins._))
                builtins._ = None
            if len(hist) > 0 and not out and not err:
                return hist.outs[-1]

    def _do_execute_direct(self, code):
        shell = builtins.__xonsh_shell__
        env = builtins.__xonsh_env__
        out = io.StringIO()
        err = io.StringIO()
        enc = env.get('XONSH_ENCODING')
        out = SpooledTemporaryFile(max_size=MAX_SIZE, mode='w+t',
                                   encoding=enc, newline='\n')
        err = SpooledTemporaryFile(max_size=MAX_SIZE, mode='w+t',
                                   encoding=enc, newline='\n')
        try:
            with redirect_stdout(out), redirect_stderr(err), \
                 swap(builtins, '__xonsh_stdout_uncaptured__', out), \
                 swap(builtins, '__xonsh_stderr_uncaptured__', err), \
                 env.swap({'XONSH_STORE_STDOUT': False}):
                shell.default(code)
            interrupted = False
        except KeyboardInterrupt:
            interrupted = True
        output, error = '', ''
        if out.tell() > 0:
            out.seek(0)
            output = out.read()
        if err.tell() > 0:
            err.seek(0)
            error = err.read()
        out.close()
        err.close()
        return output, error, interrupted

    def _respond_in_chunks(self, name, s, chunksize=1024):
        if s is None:
            return
        n = len(s)
        if n == 0:
            return
        lower = range(0, n, chunksize)
        upper = range(chunksize, n+chunksize, chunksize)
        for l, u in zip(lower, upper):
            if name == 'stderr':
                self.Error(s[l:u])
            else:
                self.Print(s[l:u])

    def do_complete(self, code, pos):
        """Get completions."""
        shell = builtins.__xonsh_shell__
        line = code.split('\n')[-1]
        prefix = line.split(' ')[-1]
        endidx = pos
        begidx = pos - len(prefix)
        rtn, _ = self.completer.complete(prefix, line, begidx,
                                         endidx, shell.ctx)
        message = {'matches': rtn, 'cursor_start': begidx, 'cursor_end': endidx,
                   'metadata': {}, 'status': 'ok'}
        return message

    def get_kernel_help_on(self, info, level=0, none_on_fail=False):
        obj = info.get('help_obj', '')
        if not obj or len(obj.split()) > 1:
            if none_on_fail:
                return None
            else:
                return ""
        output = ''
        if ON_POSIX:
            output, _, _ = self._do_execute_direct('man %s' % obj)
            if output.startswith('No manual entry for'):
                output = ''
        else:
            output, _, _, = self._do_execute_direct('help %s' % obj)
            if output.startswith('This command is not supported'):
                output = ''
        if not output:
            output, _, _ = self._do_execute_direct('help(%s)' % obj)
        return output
class XonshKernel:
    """Xonsh xernal for Jupyter"""

    implementation = "Xonsh " + version
    implementation_version = version
    language = "xonsh"
    language_version = version.split(".")[:3]
    banner = "Xonsh - Python-powered, cross-platform shell"
    language_info = {
        "name": "xonsh",
        "version": version,
        "pygments_lexer": "xonsh",
        "codemirror_mode": "shell",
        "mimetype": "text/x-sh",
        "file_extension": ".xsh",
    }
    signature_schemes = {"hmac-sha256": hashlib.sha256}

    def __init__(self, debug_level=0, session_id=None, config=None, **kwargs):
        """
        Parameters
        ----------
        debug_level : int, optional
            Integer from 0 (no debugging) to 3 (all debugging), default: 0.
        session_id : str or None, optional
            Unique string id representing the kernel session. If None, this will
            be replaced with a random UUID.
        config : dict or None, optional
            Configuration dictionary to start server with. BY default will
            search the command line for options (if given) or use default
            configuration.
        """
        self.debug_level = debug_level
        self.session_id = str(uuid.uuid4()) if session_id is None else session_id
        self._parser = None
        self.config = self.make_default_config() if config is None else config

        self.exiting = False
        self.execution_count = 1
        self.completer = Completer()

    @property
    def parser(self):
        if self._parser is None:
            p = ArgumentParser("jupyter_kerenel")
            p.add_argument("-f", dest="config_file", default=None)
            self._parser = p
        return self._parser

    def make_default_config(self):
        """Provides default configuration"""
        ns, unknown = self.parser.parse_known_args(sys.argv)
        if ns.config_file is None:
            self.dprint(1, "Starting xonsh kernel with default args...")
            config = {
                "control_port": 0,
                "hb_port": 0,
                "iopub_port": 0,
                "ip": "127.0.0.1",
                "key": str(uuid.uuid4()),
                "shell_port": 0,
                "signature_scheme": "hmac-sha256",
                "stdin_port": 0,
                "transport": "tcp",
            }
        else:
            self.dprint(1, "Loading simple_kernel with args:", sys.argv)
            self.dprint(1, "Reading config file {!r}...".format(ns.config_file))
            with open(ns.config_file) as f:
                config = json.load(f)
        return config

    def iopub_handler(self, message):
        """Handles iopub requests."""
        self.dprint(2, "iopub received:", message)

    def control_handler(self, wire_message):
        """Handles control requests"""
        self.dprint(1, "control received:", wire_message)
        identities, msg = self.deserialize_wire_message(wire_message)
        if msg["header"]["msg_type"] == "shutdown_request":
            self.shutdown()

    def stdin_handler(self, message):
        self.dprint(2, "stdin received:", message)

    def start(self):
        """Starts the server"""
        ioloop.install()
        connection = self.config["transport"] + "://" + self.config["ip"]
        secure_key = self.config["key"].encode()
        digestmod = self.signature_schemes[self.config["signature_scheme"]]
        self.auth = hmac.HMAC(secure_key, digestmod=digestmod)

        # Heartbeat
        ctx = zmq.Context()
        self.heartbeat_socket = ctx.socket(zmq.REP)
        self.config["hb_port"] = bind(
            self.heartbeat_socket, connection, self.config["hb_port"]
        )

        # IOPub/Sub, aslo called SubSocketChannel in IPython sources
        self.iopub_socket = ctx.socket(zmq.PUB)
        self.config["iopub_port"] = bind(
            self.iopub_socket, connection, self.config["iopub_port"]
        )
        self.iopub_stream = zmqstream.ZMQStream(self.iopub_socket)
        self.iopub_stream.on_recv(self.iopub_handler)

        # Control
        self.control_socket = ctx.socket(zmq.ROUTER)
        self.config["control_port"] = bind(
            self.control_socket, connection, self.config["control_port"]
        )
        self.control_stream = zmqstream.ZMQStream(self.control_socket)
        self.control_stream.on_recv(self.control_handler)

        # Stdin:
        self.stdin_socket = ctx.socket(zmq.ROUTER)
        self.config["stdin_port"] = bind(
            self.stdin_socket, connection, self.config["stdin_port"]
        )
        self.stdin_stream = zmqstream.ZMQStream(self.stdin_socket)
        self.stdin_stream.on_recv(self.stdin_handler)

        # Shell
        self.shell_socket = ctx.socket(zmq.ROUTER)
        self.config["shell_port"] = bind(
            self.shell_socket, connection, self.config["shell_port"]
        )
        self.shell_stream = zmqstream.ZMQStream(self.shell_socket)
        self.shell_stream.on_recv(self.shell_handler)

        # start up configurtation
        self.dprint(2, "Config:", json.dumps(self.config))
        self.dprint(1, "Starting loops...")
        self.hb_thread = threading.Thread(target=self.heartbeat_loop)
        self.hb_thread.daemon = True
        self.hb_thread.start()
        self.dprint(1, "Ready! Listening...")
        ioloop.IOLoop.instance().start()

    def shutdown(self):
        """Shutsdown the kernel"""
        self.exiting = True
        ioloop.IOLoop.instance().stop()

    def dprint(self, level, *args, **kwargs):
        """Print but with debug information."""
        if level <= self.debug_level:
            print("DEBUG" + str(level) + ":", file=sys.__stdout__, *args, **kwargs)
            sys.__stdout__.flush()

    def sign(self, messages):
        """Sign a message list with a secure signature."""
        h = self.auth.copy()
        for m in messages:
            h.update(m)
        return h.hexdigest().encode("ascii")

    def new_header(self, message_type):
        """Make a new header"""
        return {
            "date": datetime.datetime.now().isoformat(),
            "msg_id": str(uuid.uuid4()),
            "username": "******",
            "session": self.session_id,
            "msg_type": message_type,
            "version": "5.0",
        }

    def send(
        self,
        stream,
        message_type,
        content=None,
        parent_header=None,
        metadata=None,
        identities=None,
    ):
        """Send data to the client via a stream"""
        header = self.new_header(message_type)
        if content is None:
            content = {}
        if parent_header is None:
            parent_header = {}
        if metadata is None:
            metadata = {}

        messages = list(map(dump_bytes, [header, parent_header, metadata, content]))
        signature = self.sign(messages)
        parts = [DELIM, signature] + messages
        if identities:
            parts = identities + parts
        self.dprint(3, "send parts:", parts)
        stream.send_multipart(parts)
        if isinstance(stream, zmqstream.ZMQStream):
            stream.flush()

    def deserialize_wire_message(self, wire_message):
        """Split the routing prefix and message frames from a message on the wire"""
        delim_idx = wire_message.index(DELIM)
        identities = wire_message[:delim_idx]
        m_signature = wire_message[delim_idx + 1]
        msg_frames = wire_message[delim_idx + 2 :]

        keys = ("header", "parent_header", "metadata", "content")
        m = {k: load_bytes(v) for k, v in zip(keys, msg_frames)}
        check_sig = self.sign(msg_frames)
        if check_sig != m_signature:
            raise ValueError("Signatures do not match")
        return identities, m

    def run_thread(self, loop, name):
        """Run main thread"""
        self.dprint(2, "Starting loop for {name!r}...".format(name=name))
        while not self.exiting:
            self.dprint(2, "{} Loop!".format(name))
            try:
                loop.start()
            except ZMQError as e:
                self.dprint(1, "{} ZMQError!\n  {}".format(name, e))
                if e.errno == errno.EINTR:
                    continue
                else:
                    raise
            except Exception:
                self.dprint(2, "{} Exception!".format(name))
                if self.exiting:
                    break
                else:
                    raise
            else:
                self.dprint(2, "{} Break!".format(name))
                break

    def heartbeat_loop(self):
        """Run heartbeat"""
        self.dprint(2, "Starting heartbeat loop...")
        while not self.exiting:
            self.dprint(3, ".", end="")
            try:
                zmq.device(zmq.FORWARDER, self.heartbeat_socket, self.heartbeat_socket)
            except zmq.ZMQError as e:
                if e.errno == errno.EINTR:
                    continue
                else:
                    raise
            else:
                break

    def shell_handler(self, message):
        """Dispatch shell messages to their handlers"""
        self.dprint(1, "received:", message)
        identities, msg = self.deserialize_wire_message(message)
        handler = getattr(self, "handle_" + msg["header"]["msg_type"], None)
        if handler is None:
            self.dprint(0, "unknown message type:", msg["header"]["msg_type"])
            return
        handler(msg, identities)

    def handle_execute_request(self, message, identities):
        """Handle execute request messages."""
        self.dprint(2, "Xonsh Kernel Executing:", pformat(message["content"]["code"]))
        # Start by sending busy signal
        content = {"execution_state": "busy"}
        self.send(self.iopub_stream, "status", content, parent_header=message["header"])

        # confirm the input that we are executing
        content = {
            "execution_count": self.execution_count,
            "code": message["content"]["code"],
        }
        self.send(
            self.iopub_stream, "execute_input", content, parent_header=message["header"]
        )

        # execute the code
        metadata = {
            "dependencies_met": True,
            "engine": self.session_id,
            "status": "ok",
            "started": datetime.datetime.now().isoformat(),
        }
        content = self.do_execute(parent_header=message["header"], **message["content"])
        self.send(
            self.shell_stream,
            "execute_reply",
            content,
            metadata=metadata,
            parent_header=message["header"],
            identities=identities,
        )
        self.execution_count += 1

        # once we are done, send a signal that we are idle
        content = {"execution_state": "idle"}
        self.send(self.iopub_stream, "status", content, parent_header=message["header"])

    def do_execute(
        self,
        code="",
        silent=False,
        store_history=True,
        user_expressions=None,
        allow_stdin=False,
        parent_header=None,
        **kwargs
    ):
        """Execute user code."""
        if len(code.strip()) == 0:
            return {
                "status": "ok",
                "execution_count": self.execution_count,
                "payload": [],
                "user_expressions": {},
            }
        shell = builtins.__xonsh__.shell
        hist = builtins.__xonsh__.history
        try:
            shell.default(code, self, parent_header)
            interrupted = False
        except KeyboardInterrupt:
            interrupted = True

        if interrupted:
            return {"status": "abort", "execution_count": self.execution_count}

        rtn = 0 if (hist is None or len(hist) == 0) else hist.rtns[-1]
        if 0 < rtn:
            message = {
                "status": "error",
                "execution_count": self.execution_count,
                "ename": "",
                "evalue": str(rtn),
                "traceback": [],
            }
        else:
            message = {
                "status": "ok",
                "execution_count": self.execution_count,
                "payload": [],
                "user_expressions": {},
            }
        return message

    def _respond_in_chunks(self, name, s, chunksize=1024, parent_header=None):
        if s is None:
            return
        n = len(s)
        if n == 0:
            return
        lower = range(0, n, chunksize)
        upper = range(chunksize, n + chunksize, chunksize)
        for l, u in zip(lower, upper):
            response = {"name": name, "text": s[l:u]}
            self.send(
                self.iopub_socket, "stream", response, parent_header=parent_header
            )

    def handle_complete_request(self, message, identities):
        """Handles kernel info requests."""
        content = self.do_complete(
            message["content"]["code"], message["content"]["cursor_pos"]
        )
        self.send(
            self.shell_stream,
            "complete_reply",
            content,
            parent_header=message["header"],
            identities=identities,
        )

    def do_complete(self, code, pos):
        """Get completions."""
        shell = builtins.__xonsh__.shell
        line = code.split("\n")[-1]
        line = builtins.aliases.expand_alias(line)
        prefix = line.split(" ")[-1]
        endidx = pos
        begidx = pos - len(prefix)
        rtn, _ = self.completer.complete(prefix, line, begidx, endidx, shell.ctx)
        if isinstance(rtn, Set):
            rtn = list(rtn)
        message = {
            "matches": rtn,
            "cursor_start": begidx,
            "cursor_end": endidx,
            "metadata": {},
            "status": "ok",
        }
        return message

    def handle_kernel_info_request(self, message, identities):
        """Handles kernel info requests."""
        content = {
            "protocol_version": "5.0",
            "ipython_version": [1, 1, 0, ""],
            "language": self.language,
            "language_version": self.language_version,
            "implementation": self.implementation,
            "implementation_version": self.implementation_version,
            "language_info": self.language_info,
            "banner": self.banner,
        }
        self.send(
            self.shell_stream,
            "kernel_info_reply",
            content,
            parent_header=message["header"],
            identities=identities,
        )
Exemple #6
0
class XonshKernel(Kernel):
    """Xonsh xernal for Jupyter"""
    implementation = 'Xonsh ' + version
    implementation_version = version
    language = 'xonsh'
    language_version = version
    banner = 'Xonsh - the Python-ish, BASHwards-looking shell'
    language_info = {'name': 'xonsh',
                     'pygments_lexer': 'xonsh',
                     'codemirror_mode': 'shell',
                     'mimetype': 'text/x-sh',
                     'file_extension': '.xsh',
                     }

    def __init__(self, **kwargs):
        self.completer = Completer()
        super().__init__(**kwargs)

    def do_execute(self, code, silent, store_history=True, user_expressions=None,
                   allow_stdin=False):
        """Execute user code."""
        if len(code.strip()) == 0:
            return {'status': 'ok', 'execution_count': self.execution_count,
                    'payload': [], 'user_expressions': {}}
        env = builtins.__xonsh_env__
        shell = builtins.__xonsh_shell__
        hist = builtins.__xonsh_history__
        enc = env.get('XONSH_ENCODING')
        out = SpooledTemporaryFile(max_size=MAX_SIZE, mode='w+t',
                                   encoding=enc, newline='\n')
        err = SpooledTemporaryFile(max_size=MAX_SIZE, mode='w+t',
                                   encoding=enc, newline='\n')
        try:
            with redirect_stdout(out), redirect_stderr(err), \
                 swap(builtins, '__xonsh_stdout_uncaptured__', out), \
                 swap(builtins, '__xonsh_stderr_uncaptured__', err), \
                 env.swap({'XONSH_STORE_STDOUT': False}):
                shell.default(code)
            interrupted = False
        except KeyboardInterrupt:
            interrupted = True

        if not silent:  # stdout response
            if out.tell() > 0:
                out.seek(0)
                self._respond_in_chunks('stdout', out.read())
            if err.tell() > 0:
                err.seek(0)
                self._respond_in_chunks('stderr', err.read())
            if hasattr(builtins, '_') and builtins._ is not None:
                # rely on sys.displayhook functionality
                self._respond_in_chunks('stdout', pformat(builtins._))
                builtins._ = None
            if hist is not None and len(hist) > 0 and out.tell() == 0 and err.tell() == 0:
                self._respond_in_chunks('stdout', hist.outs[-1])

        out.close()
        err.close()

        if interrupted:
            return {'status': 'abort', 'execution_count': self.execution_count}

        rtn = 0 if (hist is None or len(hist) == 0) else hist.rtns[-1]
        if 0 < rtn:
            message = {'status': 'error', 'execution_count': self.execution_count,
                       'ename': '', 'evalue': str(rtn), 'traceback': []}
        else:
            message = {'status': 'ok', 'execution_count': self.execution_count,
                       'payload': [], 'user_expressions': {}}
        return message

    def _respond_in_chunks(self, name, s, chunksize=1024):
        if s is None:
            return
        n = len(s)
        if n == 0:
            return
        lower = range(0, n, chunksize)
        upper = range(chunksize, n+chunksize, chunksize)
        for l, u in zip(lower, upper):
            response = {'name': name, 'text': s[l:u]}
            self.send_response(self.iopub_socket, 'stream', response)

    def do_complete(self, code, pos):
        """Get completions."""
        shell = builtins.__xonsh_shell__
        line = code.split('\n')[-1]
        line = builtins.aliases.expand_alias(line)
        prefix = line.split(' ')[-1]
        endidx = pos
        begidx = pos - len(prefix)
        rtn, _ = self.completer.complete(prefix, line, begidx,
                                         endidx, shell.ctx)
        message = {'matches': rtn, 'cursor_start': begidx, 'cursor_end': endidx,
                   'metadata': {}, 'status': 'ok'}
        return message
Exemple #7
0
class Shell(Cmd):
    """The xonsh shell."""

    def __init__(self, completekey='tab', stdin=None, stdout=None, ctx=None):
        super(Shell, self).__init__(completekey=completekey,
                                    stdin=stdin,
                                    stdout=stdout)
        self.execer = Execer()
        env = builtins.__xonsh_env__
        if ctx is not None:
            self.ctx = ctx
        else:
            rc = env.get('XONSHRC', None)
            self.ctx = xonshrc_context(rcfile=rc, execer=self.execer)
        builtins.__xonsh_ctx__ = self.ctx
        self.ctx['__name__'] = '__main__'
        self.completer = Completer()
        self.buffer = []
        self.stdout = StringIO()
        self.stderr = StringIO()
        self.last = ""
        self.need_more_lines = False
        self.mlprompt = None
        setup_readline()

    def __del__(self):
        teardown_readline()

    def emptyline(self):
        """Called when an empty line has been entered."""
        self.need_more_lines = False
        self.default('')

    def parseline(self, line):
        """Overridden to no-op."""
        return '', line, line

    def precmd(self, line):
        return line if self.need_more_lines else line.lstrip()

    def default(self, line):
        """Implements code execution."""
        line = line if line.endswith('\n') else line + '\n'
        code = self.push(line)
        if code is None:
            return
        try:
            # Temporarily redirect stdout and stderr to save results in
            # history.
            with redirect_stdout(self.stdout), redirect_stderr(self.stderr):
                self.execer.exec(code, mode='single', glbs=self.ctx)  # no locals
            self.stdout.seek(0)
            self.stderr.seek(0)
            sys.stdout.write(self.stdout.read())
            sys.stderr.write(self.stderr.read())
            cmd = {}
            cmd['cmd']  = self.last
            self.stdout.seek(0)
            cmd['stdout'] = self.stdout.read()
            self.stderr.seek(0)
            cmd['stderr'] = self.stderr.read()
            self.stdout.seek(0)
            self.stdout.truncate()
            self.stderr.seek(0)
            self.stderr.truncate()
            builtins.__history__.add(cmd)
        except XonshError as e:
            print(e.args[0], file=sys.stderr, end='')
        except:
            traceback.print_exc()
        if builtins.__xonsh_exit__:
            return True

    def push(self, line):
        """Pushes a line onto the buffer and compiles the code in a way that
        enables multiline input.
        """
        code = None
        self.buffer.append(line)
        if self.need_more_lines:
            return code
        src = ''.join(self.buffer)
        try:
            code = self.execer.compile(src,
                                       mode='single',
                                       glbs=None,
                                       locs=self.ctx)
            self.last = ''.join(filter(lambda x: x != '\n', self.buffer))
            self.reset_buffer()
        except SyntaxError:
            if line == '\n':
                self.reset_buffer()
                traceback.print_exc()
                return None
            self.need_more_lines = True
        return code

    def reset_buffer(self):
        """Resets the line buffer."""
        self.buffer.clear()
        self.need_more_lines = False
        self.mlprompt = None

    def completedefault(self, text, line, begidx, endidx):
        """Implements tab-completion for text."""
        rl_completion_suppress_append()  # this needs to be called each time
        return self.completer.complete(text, line,
                                       begidx, endidx,
                                       ctx=self.ctx)

    # tab complete on first index too
    completenames = completedefault

    def cmdloop(self, intro=None):
        while not builtins.__xonsh_exit__:
            try:
                super(Shell, self).cmdloop(intro=intro)
            except KeyboardInterrupt:
                print()  # Gives a newline
                self.reset_buffer()
                intro = None
        builtins.__history__.close_history()

    def settitle(self):
        env = builtins.__xonsh_env__
        term = env.get('TERM', None)
        if term is None or term == 'linux':
            return
        if 'TITLE' in env:
            t = env['TITLE']
        else:
            return
        t = format_prompt(t)
        sys.stdout.write("\x1b]2;{0}\x07".format(t))

    @property
    def prompt(self):
        """Obtains the current prompt string."""
        global RL_LIB, RL_CAN_RESIZE
        if RL_CAN_RESIZE:
            # This is needed to support some system where line-wrapping doesn't
            # work. This is a bug in upstream Python, or possibly readline.
            RL_LIB.rl_reset_screen_size()
        if self.need_more_lines:
            if self.mlprompt is None:
                self.mlprompt = multiline_prompt()
            return self.mlprompt
        env = builtins.__xonsh_env__
        if 'PROMPT' in env:
            p = env['PROMPT']
            p = format_prompt(p)
        else:
            p = "set '$PROMPT = ...' $ "
        self.settitle()
        return p
Exemple #8
0
class XonshKernel(Kernel):
    """Xonsh xernal for Jupyter"""
    implementation = 'Xonsh ' + version
    implementation_version = version
    language = 'xonsh'
    language_version = version
    banner = 'Xonsh - Python-powered, cross-platform shell'
    language_info = {'name': 'xonsh',
                     'version': version,
                     'pygments_lexer': 'xonsh',
                     'codemirror_mode': 'shell',
                     'mimetype': 'text/x-sh',
                     'file_extension': '.xsh',
                     }

    def __init__(self, **kwargs):
        self.completer = Completer()
        super().__init__(**kwargs)

    def do_execute(self, code, silent, store_history=True, user_expressions=None,
                   allow_stdin=False):
        """Execute user code."""
        if len(code.strip()) == 0:
            return {'status': 'ok', 'execution_count': self.execution_count,
                    'payload': [], 'user_expressions': {}}
        shell = builtins.__xonsh_shell__
        hist = builtins.__xonsh_history__
        try:
            shell.default(code)
            interrupted = False
        except KeyboardInterrupt:
            interrupted = True

        if not silent:  # stdout response
            if hasattr(builtins, '_') and builtins._ is not None:
                # rely on sys.displayhook functionality
                self._respond_in_chunks('stdout', pformat(builtins._))
                builtins._ = None
            if hist is not None and len(hist) > 0:
                self._respond_in_chunks('stdout', hist.outs[-1])

        if interrupted:
            return {'status': 'abort', 'execution_count': self.execution_count}

        rtn = 0 if (hist is None or len(hist) == 0) else hist.rtns[-1]
        if 0 < rtn:
            message = {'status': 'error', 'execution_count': self.execution_count,
                       'ename': '', 'evalue': str(rtn), 'traceback': []}
        else:
            message = {'status': 'ok', 'execution_count': self.execution_count,
                       'payload': [], 'user_expressions': {}}
        return message

    def _respond_in_chunks(self, name, s, chunksize=1024):
        if s is None:
            return
        n = len(s)
        if n == 0:
            return
        lower = range(0, n, chunksize)
        upper = range(chunksize, n+chunksize, chunksize)
        for l, u in zip(lower, upper):
            response = {'name': name, 'text': s[l:u], }
            self.send_response(self.iopub_socket, 'stream', response)

    def do_complete(self, code, pos):
        """Get completions."""
        shell = builtins.__xonsh_shell__
        line = code.split('\n')[-1]
        line = builtins.aliases.expand_alias(line)
        prefix = line.split(' ')[-1]
        endidx = pos
        begidx = pos - len(prefix)
        rtn, _ = self.completer.complete(prefix, line, begidx,
                                         endidx, shell.ctx)
        message = {'matches': rtn, 'cursor_start': begidx, 'cursor_end': endidx,
                   'metadata': {}, 'status': 'ok'}
        return message
Exemple #9
0
 def __init__(self, **kwargs):
     self.completer = Completer()
     super().__init__(**kwargs)
Exemple #10
0
class XonshKernel(Kernel):
    """Xonsh xernal for Jupyter"""
    implementation = 'Xonsh ' + version
    implementation_version = version
    language = 'xonsh'
    language_version = version
    banner = 'Xonsh - Python-powered, cross-platform shell'
    language_info = {
        'name': 'xonsh',
        'version': version,
        'pygments_lexer': 'xonsh',
        'codemirror_mode': 'shell',
        'mimetype': 'text/x-sh',
        'file_extension': '.xsh',
    }

    def __init__(self, **kwargs):
        self.completer = Completer()
        super().__init__(**kwargs)

    def do_execute(self,
                   code,
                   silent,
                   store_history=True,
                   user_expressions=None,
                   allow_stdin=False):
        """Execute user code."""
        if len(code.strip()) == 0:
            return {
                'status': 'ok',
                'execution_count': self.execution_count,
                'payload': [],
                'user_expressions': {}
            }
        shell = builtins.__xonsh_shell__
        hist = builtins.__xonsh_history__
        try:
            shell.default(code)
            interrupted = False
        except KeyboardInterrupt:
            interrupted = True

        if not silent:  # stdout response
            if hasattr(builtins, '_') and builtins._ is not None:
                # rely on sys.displayhook functionality
                self._respond_in_chunks('stdout', pformat(builtins._))
                builtins._ = None
            if hist is not None and len(hist) > 0:
                self._respond_in_chunks('stdout', hist.outs[-1])

        if interrupted:
            return {'status': 'abort', 'execution_count': self.execution_count}

        rtn = 0 if (hist is None or len(hist) == 0) else hist.rtns[-1]
        if 0 < rtn:
            message = {
                'status': 'error',
                'execution_count': self.execution_count,
                'ename': '',
                'evalue': str(rtn),
                'traceback': []
            }
        else:
            message = {
                'status': 'ok',
                'execution_count': self.execution_count,
                'payload': [],
                'user_expressions': {}
            }
        return message

    def _respond_in_chunks(self, name, s, chunksize=1024):
        if s is None:
            return
        n = len(s)
        if n == 0:
            return
        lower = range(0, n, chunksize)
        upper = range(chunksize, n + chunksize, chunksize)
        for l, u in zip(lower, upper):
            response = {
                'name': name,
                'text': s[l:u],
            }
            self.send_response(self.iopub_socket, 'stream', response)

    def do_complete(self, code, pos):
        """Get completions."""
        shell = builtins.__xonsh_shell__
        line = code.split('\n')[-1]
        line = builtins.aliases.expand_alias(line)
        prefix = line.split(' ')[-1]
        endidx = pos
        begidx = pos - len(prefix)
        rtn, _ = self.completer.complete(prefix, line, begidx, endidx,
                                         shell.ctx)
        message = {
            'matches': rtn,
            'cursor_start': begidx,
            'cursor_end': endidx,
            'metadata': {},
            'status': 'ok'
        }
        return message
Exemple #11
0
def completer_obj():
    return Completer()
Exemple #12
0
class XonshKernel:
    """Xonsh xernal for Jupyter"""

    implementation = "Xonsh " + version
    implementation_version = version
    language = "xonsh"
    language_version = version.split(".")[:3]
    banner = "Xonsh - Python-powered, cross-platform shell"
    language_info = {
        "name": "xonsh",
        "version": version,
        "pygments_lexer": "xonsh",
        "codemirror_mode": "shell",
        "mimetype": "text/x-sh",
        "file_extension": ".xsh",
    }
    signature_schemes = {"hmac-sha256": hashlib.sha256}

    def __init__(self, debug_level=0, session_id=None, config=None, **kwargs):
        """
        Parameters
        ----------
        debug_level : int, optional
            Integer from 0 (no debugging) to 3 (all debugging), default: 0.
        session_id : str or None, optional
            Unique string id representing the kernel session. If None, this will
            be replaced with a random UUID.
        config : dict or None, optional
            Configuration dictionary to start server with. BY default will
            search the command line for options (if given) or use default
            configuration.
        """
        self.debug_level = debug_level
        self.session_id = str(
            uuid.uuid4()) if session_id is None else session_id
        self._parser = None
        self.config = self.make_default_config() if config is None else config

        self.exiting = False
        self.execution_count = 1
        self.completer = Completer()

    @property
    def parser(self):
        if self._parser is None:
            p = ArgumentParser("jupyter_kerenel")
            p.add_argument("-f", dest="config_file", default=None)
            self._parser = p
        return self._parser

    def make_default_config(self):
        """Provides default configuration"""
        ns, unknown = self.parser.parse_known_args(sys.argv)
        if ns.config_file is None:
            self.dprint(1, "Starting xonsh kernel with default args...")
            config = {
                "control_port": 0,
                "hb_port": 0,
                "iopub_port": 0,
                "ip": "127.0.0.1",
                "key": str(uuid.uuid4()),
                "shell_port": 0,
                "signature_scheme": "hmac-sha256",
                "stdin_port": 0,
                "transport": "tcp",
            }
        else:
            self.dprint(1, "Loading simple_kernel with args:", sys.argv)
            self.dprint(1,
                        "Reading config file {!r}...".format(ns.config_file))
            with open(ns.config_file) as f:
                config = json.load(f)
        return config

    def iopub_handler(self, message):
        """Handles iopub requests."""
        self.dprint(2, "iopub received:", message)

    def control_handler(self, wire_message):
        """Handles control requests"""
        self.dprint(1, "control received:", wire_message)
        identities, msg = self.deserialize_wire_message(wire_message)
        if msg["header"]["msg_type"] == "shutdown_request":
            self.shutdown()

    def stdin_handler(self, message):
        self.dprint(2, "stdin received:", message)

    def start(self):
        """Starts the server"""
        ioloop.install()
        connection = self.config["transport"] + "://" + self.config["ip"]
        secure_key = self.config["key"].encode()
        digestmod = self.signature_schemes[self.config["signature_scheme"]]
        self.auth = hmac.HMAC(secure_key, digestmod=digestmod)

        # Heartbeat
        ctx = zmq.Context()
        self.heartbeat_socket = ctx.socket(zmq.REP)
        self.config["hb_port"] = bind(self.heartbeat_socket, connection,
                                      self.config["hb_port"])

        # IOPub/Sub, aslo called SubSocketChannel in IPython sources
        self.iopub_socket = ctx.socket(zmq.PUB)
        self.config["iopub_port"] = bind(self.iopub_socket, connection,
                                         self.config["iopub_port"])
        self.iopub_stream = zmqstream.ZMQStream(self.iopub_socket)
        self.iopub_stream.on_recv(self.iopub_handler)

        # Control
        self.control_socket = ctx.socket(zmq.ROUTER)
        self.config["control_port"] = bind(self.control_socket, connection,
                                           self.config["control_port"])
        self.control_stream = zmqstream.ZMQStream(self.control_socket)
        self.control_stream.on_recv(self.control_handler)

        # Stdin:
        self.stdin_socket = ctx.socket(zmq.ROUTER)
        self.config["stdin_port"] = bind(self.stdin_socket, connection,
                                         self.config["stdin_port"])
        self.stdin_stream = zmqstream.ZMQStream(self.stdin_socket)
        self.stdin_stream.on_recv(self.stdin_handler)

        # Shell
        self.shell_socket = ctx.socket(zmq.ROUTER)
        self.config["shell_port"] = bind(self.shell_socket, connection,
                                         self.config["shell_port"])
        self.shell_stream = zmqstream.ZMQStream(self.shell_socket)
        self.shell_stream.on_recv(self.shell_handler)

        # start up configurtation
        self.dprint(2, "Config:", json.dumps(self.config))
        self.dprint(1, "Starting loops...")
        self.hb_thread = threading.Thread(target=self.heartbeat_loop)
        self.hb_thread.daemon = True
        self.hb_thread.start()
        self.dprint(1, "Ready! Listening...")
        ioloop.IOLoop.instance().start()

    def shutdown(self):
        """Shutsdown the kernel"""
        self.exiting = True
        ioloop.IOLoop.instance().stop()

    def dprint(self, level, *args, **kwargs):
        """Print but with debug information."""
        if level <= self.debug_level:
            print("DEBUG" + str(level) + ":",
                  file=sys.__stdout__,
                  *args,
                  **kwargs)
            sys.__stdout__.flush()

    def sign(self, messages):
        """Sign a message list with a secure signature."""
        h = self.auth.copy()
        for m in messages:
            h.update(m)
        return h.hexdigest().encode("ascii")

    def new_header(self, message_type):
        """Make a new header"""
        return {
            "date": datetime.datetime.now().isoformat(),
            "msg_id": str(uuid.uuid4()),
            "username": "******",
            "session": self.session_id,
            "msg_type": message_type,
            "version": "5.0",
        }

    def send(
        self,
        stream,
        message_type,
        content=None,
        parent_header=None,
        metadata=None,
        identities=None,
    ):
        """Send data to the client via a stream"""
        header = self.new_header(message_type)
        if content is None:
            content = {}
        if parent_header is None:
            parent_header = {}
        if metadata is None:
            metadata = {}

        messages = list(
            map(dump_bytes, [header, parent_header, metadata, content]))
        signature = self.sign(messages)
        parts = [DELIM, signature] + messages
        if identities:
            parts = identities + parts
        self.dprint(3, "send parts:", parts)
        stream.send_multipart(parts)
        if isinstance(stream, zmqstream.ZMQStream):
            stream.flush()

    def deserialize_wire_message(self, wire_message):
        """Split the routing prefix and message frames from a message on the wire"""
        delim_idx = wire_message.index(DELIM)
        identities = wire_message[:delim_idx]
        m_signature = wire_message[delim_idx + 1]
        msg_frames = wire_message[delim_idx + 2:]

        keys = ("header", "parent_header", "metadata", "content")
        m = {k: load_bytes(v) for k, v in zip(keys, msg_frames)}
        check_sig = self.sign(msg_frames)
        if check_sig != m_signature:
            raise ValueError("Signatures do not match")
        return identities, m

    def run_thread(self, loop, name):
        """Run main thread"""
        self.dprint(2, "Starting loop for {name!r}...".format(name=name))
        while not self.exiting:
            self.dprint(2, "{} Loop!".format(name))
            try:
                loop.start()
            except ZMQError as e:
                self.dprint(1, "{} ZMQError!\n  {}".format(name, e))
                if e.errno == errno.EINTR:
                    continue
                else:
                    raise
            except Exception:
                self.dprint(2, "{} Exception!".format(name))
                if self.exiting:
                    break
                else:
                    raise
            else:
                self.dprint(2, "{} Break!".format(name))
                break

    def heartbeat_loop(self):
        """Run heartbeat"""
        self.dprint(2, "Starting heartbeat loop...")
        while not self.exiting:
            self.dprint(3, ".", end="")
            try:
                zmq.device(zmq.FORWARDER, self.heartbeat_socket,
                           self.heartbeat_socket)
            except zmq.ZMQError as e:
                if e.errno == errno.EINTR:
                    continue
                else:
                    raise
            else:
                break

    def shell_handler(self, message):
        """Dispatch shell messages to their handlers"""
        self.dprint(1, "received:", message)
        identities, msg = self.deserialize_wire_message(message)
        handler = getattr(self, "handle_" + msg["header"]["msg_type"], None)
        if handler is None:
            self.dprint(0, "unknown message type:", msg["header"]["msg_type"])
            return
        handler(msg, identities)

    def handle_execute_request(self, message, identities):
        """Handle execute request messages."""
        self.dprint(2, "Xonsh Kernel Executing:",
                    pformat(message["content"]["code"]))
        # Start by sending busy signal
        content = {"execution_state": "busy"}
        self.send(self.iopub_stream,
                  "status",
                  content,
                  parent_header=message["header"])

        # confirm the input that we are executing
        content = {
            "execution_count": self.execution_count,
            "code": message["content"]["code"],
        }
        self.send(self.iopub_stream,
                  "execute_input",
                  content,
                  parent_header=message["header"])

        # execute the code
        metadata = {
            "dependencies_met": True,
            "engine": self.session_id,
            "status": "ok",
            "started": datetime.datetime.now().isoformat(),
        }
        content = self.do_execute(parent_header=message["header"],
                                  **message["content"])
        self.send(
            self.shell_stream,
            "execute_reply",
            content,
            metadata=metadata,
            parent_header=message["header"],
            identities=identities,
        )
        self.execution_count += 1

        # once we are done, send a signal that we are idle
        content = {"execution_state": "idle"}
        self.send(self.iopub_stream,
                  "status",
                  content,
                  parent_header=message["header"])

    def do_execute(self,
                   code="",
                   silent=False,
                   store_history=True,
                   user_expressions=None,
                   allow_stdin=False,
                   parent_header=None,
                   **kwargs):
        """Execute user code."""
        if len(code.strip()) == 0:
            return {
                "status": "ok",
                "execution_count": self.execution_count,
                "payload": [],
                "user_expressions": {},
            }
        shell = builtins.__xonsh__.shell
        hist = builtins.__xonsh__.history
        try:
            shell.default(code, self, parent_header)
            interrupted = False
        except KeyboardInterrupt:
            interrupted = True

        if interrupted:
            return {"status": "abort", "execution_count": self.execution_count}

        rtn = 0 if (hist is None or len(hist) == 0) else hist.rtns[-1]
        if 0 < rtn:
            message = {
                "status": "error",
                "execution_count": self.execution_count,
                "ename": "",
                "evalue": str(rtn),
                "traceback": [],
            }
        else:
            message = {
                "status": "ok",
                "execution_count": self.execution_count,
                "payload": [],
                "user_expressions": {},
            }
        return message

    def _respond_in_chunks(self, name, s, chunksize=1024, parent_header=None):
        if s is None:
            return
        n = len(s)
        if n == 0:
            return
        lower = range(0, n, chunksize)
        upper = range(chunksize, n + chunksize, chunksize)
        for l, u in zip(lower, upper):
            response = {"name": name, "text": s[l:u]}
            self.send(self.iopub_socket,
                      "stream",
                      response,
                      parent_header=parent_header)

    def handle_complete_request(self, message, identities):
        """Handles kernel info requests."""
        content = self.do_complete(message["content"]["code"],
                                   message["content"]["cursor_pos"])
        self.send(
            self.shell_stream,
            "complete_reply",
            content,
            parent_header=message["header"],
            identities=identities,
        )

    def do_complete(self, code, pos):
        """Get completions."""
        shell = builtins.__xonsh__.shell
        line = code.split("\n")[-1]
        line = builtins.aliases.expand_alias(line)
        prefix = line.split(" ")[-1]
        endidx = pos
        begidx = pos - len(prefix)
        rtn, _ = self.completer.complete(prefix, line, begidx, endidx,
                                         shell.ctx)
        if isinstance(rtn, Set):
            rtn = list(rtn)
        message = {
            "matches": rtn,
            "cursor_start": begidx,
            "cursor_end": endidx,
            "metadata": {},
            "status": "ok",
        }
        return message

    def handle_kernel_info_request(self, message, identities):
        """Handles kernel info requests."""
        content = {
            "protocol_version": "5.0",
            "ipython_version": [1, 1, 0, ""],
            "language": self.language,
            "language_version": self.language_version,
            "implementation": self.implementation,
            "implementation_version": self.implementation_version,
            "language_info": self.language_info,
            "banner": self.banner,
        }
        self.send(
            self.shell_stream,
            "kernel_info_reply",
            content,
            parent_header=message["header"],
            identities=identities,
        )