Ejemplo n.º 1
0
def test_list_profiles_in():
    # No need to remove these directories and files, as they will get nuked in
    # the module-level teardown.
    td = tempfile.mkdtemp(dir=TMP_TEST_DIR)
    td = py3compat.str_to_unicode(td)
    for name in ('profile_foo', 'profile_hello', 'not_a_profile'):
        os.mkdir(os.path.join(td, name))
    if dec.unicode_paths:
        os.mkdir(os.path.join(td, 'profile_ünicode'))

    with open(os.path.join(td, 'profile_file'), 'w') as f:
        f.write("I am not a profile directory")
    profiles = list_profiles_in(td)
    
    # unicode normalization can turn u'ünicode' into u'u\0308nicode',
    # so only check for *nicode, and that creating a ProfileDir from the
    # name remains valid
    found_unicode = False
    for p in list(profiles):
        if p.endswith('nicode'):
            pd = ProfileDir.find_profile_dir_by_name(td, p)
            profiles.remove(p)
            found_unicode = True
            break
    if dec.unicode_paths:
        nt.assert_true(found_unicode)
    nt.assert_equal(set(profiles), set(['foo', 'hello']))
Ejemplo n.º 2
0
 def eval(self, line):
     """Evaluate a line or block of code in R
     
     Parameters
     ----------
     line : str
         The code to execute
     
     Examples
     --------
     >>> r.eval('''
     ... x = 1:5
     ... df = data.frame(x=x, y=x^2)
     ... print(df)
     ... ''')
       x  y
     1 1  1
     2 2  4
     3 3  9
     4 4 16
     5 5 25
     """
     old_writeconsole = ri.get_writeconsole()
     ri.set_writeconsole(self._write_console)
     try:
         value = ri.baseenv['eval'](ri.parse(line))
     except (ri.RRuntimeError, ValueError) as exception:
         warning_or_other_msg = self._flush() # otherwise next return seems to have copy of error
         raise RInterpreterError(line, str_to_unicode(str(exception)), warning_or_other_msg)
     text_output = self._flush()
     ri.set_writeconsole(old_writeconsole)
     
     if text_output:
         sys.stdout.write(unicode_to_str(text_output, 'utf-8'))
Ejemplo n.º 3
0
    def eval(self, code):
        '''
        Parse and evaluate a line of R code with rpy2.
        Returns the output to R's stdout() connection,
        the value generated by evaluating the code, and a
        boolean indicating whether the return value would be
        visible if the line of code were evaluated in an R REPL.

        R Code evaluation and visibility determination are done via an R call of
        the form withVisible(code_string), and this entire expression needs to
        be evaluated in R (we can't use rpy2 function proxies here, as
        withVisible is a LISPy R function).

        '''
        old_writeconsole_regular = ri.get_writeconsole_regular()
        ri.set_writeconsole_regular(self.write_console_regular)
        try:
            # Need the newline in case the last line in code is a comment
            value, visible = ro.r("withVisible({%s\n})" % code)
        except (ri.RRuntimeError, ValueError) as exception:
            warning_or_other_msg = self.flush() # otherwise next return seems to have copy of error
            raise RInterpreterError(code, str_to_unicode(str(exception)), warning_or_other_msg)
        text_output = self.flush()
        ri.set_writeconsole_regular(old_writeconsole_regular)
        return text_output, value, visible[0]
Ejemplo n.º 4
0
 def flush(self):
     '''
     Flush R's stdout cache to a string, returning the string.
     '''
     value = ''.join([str_to_unicode(s, 'utf-8') for s in self.Rstdout_cache])
     self.Rstdout_cache = []
     return value
Ejemplo n.º 5
0
 def flush(self):
     """
     Flush R's stdout cache to a string, returning the string.
     """
     value = "".join([str_to_unicode(s, "utf-8") for s in self.Rstdout_cache])
     self.Rstdout_cache = []
     return value
Ejemplo n.º 6
0
    def raw_input(self, prompt=''):
        """Write a prompt and read a line.

        The returned line does not include the trailing newline.
        When the user enters the EOF key sequence, EOFError is raised.

        Parameters
        ----------

        prompt : str, optional
          A string to be printed to prompt the user.
        """
        # raw_input expects str, but we pass it unicode sometimes
        prompt = py3compat.cast_bytes_py2(prompt)

        try:
            line = py3compat.str_to_unicode(self.raw_input_original(prompt))
        except ValueError:
            warn("\n********\nYou or a %run:ed script called sys.stdin.close()"
                 " or sys.stdout.close()!\nExiting IPython!\n")
            self.ask_exit()
            return ""

        # Try to be reasonably smart about not re-indenting pasted input more
        # than necessary.  We do this by trimming out the auto-indent initial
        # spaces, if the user's actual input started itself with whitespace.
        if self.autoindent:
            if num_ini_spaces(line) > self.indent_current_nsp:
                line = line[self.indent_current_nsp:]
                self.indent_current_nsp = 0

        return line
Ejemplo n.º 7
0
 def eval(self, line):
     '''
     Parse and evaluate a line of R code with rpy2.
     Returns the output to R's stdout() connection, 
     the value generated by evaluating the code, and a
     boolean indicating whether the return value would be
     visible if the line of code were evaluated in an R REPL.
     
     R Code evaluation and visibility determination are
     done via an R call of the form withVisible({<code>})
     
     '''
     old_writeconsole = ri.get_writeconsole()
     ri.set_writeconsole(self.write_console)
     try:
         res = ro.r("withVisible({%s})" % line)
         value = res[0]  #value (R object)
         visible = ro.conversion.ri2py(res[1])[0]  #visible (boolean)
     except (ri.RRuntimeError, ValueError) as exception:
         warning_or_other_msg = self.flush(
         )  # otherwise next return seems to have copy of error
         raise RInterpreterError(line, str_to_unicode(str(exception)),
                                 warning_or_other_msg)
     text_output = self.flush()
     ri.set_writeconsole(old_writeconsole)
     return text_output, value, visible
Ejemplo n.º 8
0
 def flush(self):
     '''
     Flush R's stdout cache to a string, returning the string.
     '''
     value = ''.join([str_to_unicode(s, 'utf-8') for s in self.Rstdout_cache])
     self.Rstdout_cache = []
     return value
Ejemplo n.º 9
0
    def eval(self, code):
        '''
        Parse and evaluate a line of R code with rpy2.
        Returns the output to R's stdout() connection,
        the value generated by evaluating the code, and a
        boolean indicating whether the return value would be
        visible if the line of code were evaluated in an R REPL.

        R Code evaluation and visibility determination are done via an R call of
        the form withVisible(code_string), and this entire expression needs to
        be evaluated in R (we can't use rpy2 function proxies here, as
        withVisible is a LISPy R function).

        '''
        old_writeconsole_regular = ri.get_writeconsole_regular()
        ri.set_writeconsole_regular(self.write_console_regular)
        try:
            # Need the newline in case the last line in code is a comment
            value, visible = ro.r("withVisible({%s\n})" % code)
        except (ri.RRuntimeError, ValueError) as exception:
            warning_or_other_msg = self.flush(
            )  # otherwise next return seems to have copy of error
            raise RInterpreterError(code, str_to_unicode(str(exception)),
                                    warning_or_other_msg)
        text_output = self.flush()
        ri.set_writeconsole_regular(old_writeconsole_regular)
        return text_output, value, visible[0]
Ejemplo n.º 10
0
 def write(self, nb, fp, **kwargs):
     """Write a notebook to a file like object"""
     nbs = self.writes(nb,**kwargs)
     if not py3compat.PY3 and not isinstance(nbs, unicode):
         # this branch is likely only taken for JSON on Python 2
         nbs = py3compat.str_to_unicode(nbs)
     return fp.write(nbs)
Ejemplo n.º 11
0
    def raw_input(self, prompt=''):
        """Write a prompt and read a line.

        The returned line does not include the trailing newline.
        When the user enters the EOF key sequence, EOFError is raised.

        Parameters
        ----------

        prompt : str, optional
          A string to be printed to prompt the user.
        """
        # raw_input expects str, but we pass it unicode sometimes
        prompt = py3compat.cast_bytes_py2(prompt)

        try:
            line = py3compat.str_to_unicode(self.raw_input_original(prompt))
        except ValueError:
            warn("\n********\nYou or a %run:ed script called sys.stdin.close()"
                 " or sys.stdout.close()!\nExiting IPython!\n")
            self.ask_exit()
            return ""

        # Try to be reasonably smart about not re-indenting pasted input more
        # than necessary.  We do this by trimming out the auto-indent initial
        # spaces, if the user's actual input started itself with whitespace.
        if self.autoindent:
            if num_ini_spaces(line) > self.indent_current_nsp:
                line = line[self.indent_current_nsp:]
                self.indent_current_nsp = 0

        return line
Ejemplo n.º 12
0
    def complete_request(self, text):
        line = str_to_unicode(readline.get_line_buffer())
        byte_cursor_pos = readline.get_endidx()

        # get_endidx is a byte offset
        # account for multi-byte characters to get correct cursor_pos
        bytes_before_cursor = cast_bytes(line)[:byte_cursor_pos]
        cursor_pos = len(cast_unicode(bytes_before_cursor))

        # send completion request to kernel
        # Give the kernel up to 5s to respond
        msg_id = self.client.complete(
            code=line,
            cursor_pos=cursor_pos,
        )

        msg = self.client.shell_channel.get_msg(timeout=self.timeout)
        if msg['parent_header']['msg_id'] == msg_id:
            content = msg['content']
            cursor_start = content['cursor_start']
            matches = [line[:cursor_start] + m for m in content['matches']]
            if content["cursor_end"] < cursor_pos:
                extra = line[content["cursor_end"]:cursor_pos]
                matches = [m + extra for m in matches]
            matches = [unicode_to_str(m) for m in matches]
            return matches
        return []
Ejemplo n.º 13
0
    def eval(self, line):
        '''
        Parse and evaluate a line of R code with rpy2.
        Returns the output to R's stdout() connection, 
        the value generated by evaluating the code, and a
        boolean indicating whether the return value would be
        visible if the line of code were evaluated in an R REPL.

        R Code evaluation and visibility determination are
        done via an R call of the form withVisible({<code>})

        '''
        old_writeconsole = ri.get_writeconsole()
        ri.set_writeconsole(self.write_console)
        try:
            res = ro.r("withVisible({%s\n})" % line)
            value = res[0]  # value (R object)
            visible = ro.conversion.ri2py(res[1])[0]  # visible (boolean)
        except (ri.RRuntimeError, ValueError) as exception:
            # otherwise next return seems to have copy of error
            warning_or_other_msg = self.flush()
            raise RInterpreterError(
                line, str_to_unicode(str(exception)), warning_or_other_msg)
        text_output = self.flush()
        ri.set_writeconsole(old_writeconsole)
        return text_output, value, visible
Ejemplo n.º 14
0
 def complete_request(self, text):
     line = str_to_unicode(readline.get_line_buffer())
     byte_cursor_pos = readline.get_endidx()
     
     # get_endidx is a byte offset
     # account for multi-byte characters to get correct cursor_pos
     bytes_before_cursor = cast_bytes(line)[:byte_cursor_pos]
     cursor_pos = len(cast_unicode(bytes_before_cursor))
     
     # send completion request to kernel
     # Give the kernel up to 5s to respond
     msg_id = self.client.complete(
         code=line,
         cursor_pos=cursor_pos,
     )
 
     msg = self.client.shell_channel.get_msg(timeout=self.timeout)
     if msg['parent_header']['msg_id'] == msg_id:
         content = msg['content']
         cursor_start = content['cursor_start']
         matches = [ line[:cursor_start] + m for m in content['matches'] ]
         if content["cursor_end"] < cursor_pos:
             extra = line[content["cursor_end"]: cursor_pos]
             matches = [m + extra for m in matches]
         matches = [ unicode_to_str(m) for m in matches ]
         return matches
     return []
Ejemplo n.º 15
0
def writes_cell(cell, **kwargs):
    kwargs['cls'] = BytesEncoder
    kwargs['indent'] = 3
    kwargs['sort_keys'] = True
    kwargs['separators'] = (',', ': ')
    if kwargs.pop('split_lines', True):
        cell = split_lines_cell(copy.deepcopy(cell))
    return py3compat.str_to_unicode(json.dumps(cell, **kwargs), 'utf-8')
Ejemplo n.º 16
0
def writes_cell(cell, **kwargs):
    kwargs["cls"] = BytesEncoder
    kwargs["indent"] = 3
    kwargs["sort_keys"] = True
    kwargs["separators"] = (",", ": ")
    if kwargs.pop("split_lines", True):
        cell = split_lines_cell(copy.deepcopy(cell))
    return py3compat.str_to_unicode(json.dumps(cell, **kwargs), "utf-8")
Ejemplo n.º 17
0
def writes_cell(cell, **kwargs):
    kwargs['cls'] = BytesEncoder
    kwargs['indent'] = 3
    kwargs['sort_keys'] = True
    kwargs['separators'] = (',', ': ')
    if kwargs.pop('split_lines', True):
        cell = split_lines_cell(copy.deepcopy(cell))
    return py3compat.str_to_unicode(json.dumps(cell, **kwargs), 'utf-8')
Ejemplo n.º 18
0
def test_extlibs():
    code = py3compat.str_to_unicode("""
from libc.math cimport sin
x = sin(0.0)
    """)
    ip.user_ns['x'] = 1
    ip.run_cell_magic('cython', '-l m', code)
    nt.assert_equal(ip.user_ns['x'], 0)
Ejemplo n.º 19
0
    def _save_to_file(self, path, identifier, content, debug=False):
        pypath = os.path.splitext(path)[0] + '.py'
        code_identifier = "# -- ==%s== --" % identifier
        new_content = []
        if not os.path.isfile(pypath):
            # The file does not exist, so simple create a new one
            if debug:
                print("Created new file: %s" % pypath)
            new_content.extend([
                u'# -*- coding: utf-8 -*-\n\n', code_identifier, content,
                code_identifier
            ])
        else:
            # If file exist, read in the content and either replace the code or append it
            in_code_block = False
            included_new = False
            lineno = 0
            with io.open(pypath, 'r', encoding='utf-8') as f:
                for line in f:
                    if line[-1] == "\n":
                        line = line[:-1]
                    lineno += 1
                    if line.strip() == code_identifier:
                        if included_new and not in_code_block:
                            # we found a third one -> Error!
                            raise Exception(
                                "Found more than two lines with identifiers in file '%s' in line %s. "
                                "Please fix the file so that the identifier is included exactly two times."
                                % (pypath, lineno))
                        # Now we are either in the codeblock or just outside
                        # Switch the state to either "in our codeblock" or outside again
                        in_code_block = True if not in_code_block else False
                        if not included_new:
                            # The code was not included yet, so add it here...
                            # No need to add a code indentifier to the end as we just add the ending indentifier from the last
                            # time when the state is switched again.
                            new_content.extend([code_identifier, content])
                            included_new = True
                    # This is something from other code cells, so just include it. All code
                    # "in_code_block" is replace, so do not include it
                    if not in_code_block:
                        new_content.append(line)
            # And if we didn't include out code yet, lets append it to the end...
            if not included_new:
                new_content.extend(
                    ["\n", code_identifier, content, code_identifier, "\n"])

        new_content = unicode(u'\n'.join(new_content))

        #Now write the complete code back to the file
        self.ensure_dir(pypath)
        with io.open(pypath, 'w', encoding='utf-8') as f:
            if not py3compat.PY3 and not isinstance(new_content, unicode):
                # this branch is likely only taken for JSON on Python 2
                new_content = py3compat.str_to_unicode(new_content)
            f.write(new_content)
            if debug:
                print("Wrote cell to file: %s" % pypath)
Ejemplo n.º 20
0
def quote(s):
    """unicode-safe quote
    
    - Python 2 requires str, not unicode
    - always return unicode
    """
    s = py3compat.cast_bytes_py2(s)
    quoted = stdlib_quote(s)
    return py3compat.str_to_unicode(quoted)
Ejemplo n.º 21
0
def url_unescape(path):
    """Unescape special characters in a URL path
    
    Turns '/foo%20bar/' into '/foo bar/'
    """
    return u'/'.join([
        py3compat.str_to_unicode(unquote(p), encoding='utf8')
        for p in py3compat.unicode_to_str(path, encoding='utf8').split('/')
    ])
Ejemplo n.º 22
0
def quote(s):
    """unicode-safe quote
    
    - Python 2 requires str, not unicode
    - always return unicode
    """
    s = py3compat.cast_bytes_py2(s)
    quoted = stdlib_quote(s)
    return py3compat.str_to_unicode(quoted)
Ejemplo n.º 23
0
def url_unescape(path):
    """Unescape special characters in a URL path

    Turns '/foo%20bar/' into '/foo bar/'
    """
    return u'/'.join([
        py3compat.str_to_unicode(unquote(p))
        for p in py3compat.unicode_to_str(path).split('/')
    ])
Ejemplo n.º 24
0
    def _save_to_file(self, path, identifier, content, debug=False):
            pypath = os.path.splitext(path)[0] + '.py'
            code_identifier = "# -- ==%s== --" % identifier
            new_content = []
            if not os.path.isfile(pypath):
                # The file does not exist, so simple create a new one
                if debug:
                    print("Created new file: %s" % pypath)
                new_content.extend([u'# -*- coding: utf-8 -*-\n\n', code_identifier , content, code_identifier])
            else:
                # If file exist, read in the content and either replace the code or append it
                in_code_block = False
                included_new = False
                lineno = 0
                with io.open(pypath, 'r', encoding='utf-8') as f:
                    for line in f:
                        if line[-1] == "\n":
                            line = line[:-1]
                        lineno += 1
                        if line.strip() == code_identifier:
                            if included_new and not in_code_block:
                                # we found a third one -> Error!
                                raise Exception("Found more than two lines with identifier '%s' in file '%s' in line %s. "
                                    "Please fix the file so that the identifier is included exactly two times." % (code_identifier, pypath, lineno))
                            # Now we are either in the codeblock or just outside
                            # Switch the state to either "in our codeblock" or outside again
                            in_code_block = True if not in_code_block else False
                            if not included_new:
                                # The code was not included yet, so add it here...
                                # No need to add a code indentifier to the end as we just add the ending indentifier from the last
                                # time when the state is switched again.
                                new_content.extend([code_identifier, content])
                                included_new = True
                        # This is something from other code cells, so just include it. All code
                        # "in_code_block" is replaced, so do not include it
                        if not in_code_block:
                            new_content.append(line)
                # the file is finished, ensure we didn't see only one identifier, but not the second one
                if in_code_block:
                    raise Exception("Found only one line with identifier '%s' in file '%s'. "
                                    "Please fix the file so that the identifier is included exactly two times." % (code_identifier, pypath))
                # And if we didn't include our code yet, lets append it to the end...
                if not included_new:
                    new_content.extend(["\n", code_identifier, content, code_identifier, "\n"])

            new_content = py3compat.cast_unicode(u'\n'.join(new_content))

            #Now write the complete code back to the file
            self.ensure_dir(pypath)
            with io.open(pypath,'w', encoding='utf-8') as f:
                if not py3compat.PY3 and not isinstance(new_content, unicode):
                    # this branch is likely only taken for JSON on Python 2
                    new_content = py3compat.str_to_unicode(new_content)
                f.write(new_content)
                if debug:
                    print("Wrote cell to file: %s" % pypath)
Ejemplo n.º 25
0
 def string2json(self, string):
     """Convert json into its string representation.
     Used for writing outputs to markdown."""
     kwargs = {
         'cls': BytesEncoder,  # use the IPython bytes encoder
         'indent': 1,
         'sort_keys': True,
         'separators': (',', ': '),
     }
     return py3compat.str_to_unicode(json.dumps(string, **kwargs), 'utf-8')
Ejemplo n.º 26
0
 def _check_created(self, resp, path, type='notebook'):
     self.assertEqual(resp.status_code, 201)
     location_header = py3compat.str_to_unicode(resp.headers['Location'])
     self.assertEqual(location_header, url_escape(url_path_join(u'/api/contents', path)))
     rjson = resp.json()
     self.assertEqual(rjson['name'], path.rsplit('/', 1)[-1])
     self.assertEqual(rjson['path'], path)
     self.assertEqual(rjson['type'], type)
     isright = self.isdir if type == 'directory' else self.isfile
     assert isright(path)
Ejemplo n.º 27
0
 def _check_nb_created(self, resp, name, path):
     self.assertEqual(resp.status_code, 201)
     location_header = py3compat.str_to_unicode(resp.headers['Location'])
     self.assertEqual(location_header, url_escape(url_path_join(u'/api/notebooks', path, name)))
     self.assertEqual(resp.json()['name'], name)
     assert os.path.isfile(pjoin(
         self.notebook_dir.name,
         path.replace('/', os.sep),
         name,
     ))
Ejemplo n.º 28
0
 def writes(self, nb, **kwargs):
     kwargs['cls'] = BytesEncoder
     kwargs['indent'] = 1
     kwargs['sort_keys'] = True
     kwargs['separators'] = (',', ': ')
     nb = copy.deepcopy(nb)
     nb = strip_transient(nb)
     if kwargs.pop('split_lines', True):
         nb = split_lines(nb)
     return py3compat.str_to_unicode(json.dumps(nb, **kwargs), 'utf-8')
Ejemplo n.º 29
0
 def string2json(self, string):
     """Convert json into its string representation.
     Used for writing outputs to markdown."""
     kwargs = {
         'cls': BytesEncoder,  # use the IPython bytes encoder
         'indent': 1,
         'sort_keys': True,
         'separators': (',', ': '),
     }
     return py3compat.str_to_unicode(json.dumps(string, **kwargs), 'utf-8')
Ejemplo n.º 30
0
 def _check_created(self, resp, path, type="notebook"):
     self.assertEqual(resp.status_code, 201)
     location_header = py3compat.str_to_unicode(resp.headers["Location"])
     self.assertEqual(location_header, url_escape(url_path_join(u"/api/contents", path)))
     rjson = resp.json()
     self.assertEqual(rjson["name"], path.rsplit("/", 1)[-1])
     self.assertEqual(rjson["path"], path)
     self.assertEqual(rjson["type"], type)
     isright = os.path.isdir if type == "directory" else os.path.isfile
     assert isright(pjoin(self.notebook_dir.name, path.replace("/", os.sep)))
Ejemplo n.º 31
0
 def _check_nb_created(self, resp, name, path):
     self.assertEqual(resp.status_code, 201)
     location_header = py3compat.str_to_unicode(resp.headers['Location'])
     self.assertEqual(location_header, url_escape(url_path_join(u'/api/notebooks', path, name)))
     self.assertEqual(resp.json()['name'], name)
     assert os.path.isfile(pjoin(
         self.notebook_dir.name,
         path.replace('/', os.sep),
         name,
     ))
Ejemplo n.º 32
0
 def _check_created(self, resp, path, type='notebook'):
     self.assertEqual(resp.status_code, 201)
     location_header = py3compat.str_to_unicode(resp.headers['Location'])
     self.assertEqual(location_header, url_escape(url_path_join(u'/api/contents', path)))
     rjson = resp.json()
     self.assertEqual(rjson['name'], path.rsplit('/', 1)[-1])
     self.assertEqual(rjson['path'], path)
     self.assertEqual(rjson['type'], type)
     isright = self.isdir if type == 'directory' else self.isfile
     assert isright(path)
Ejemplo n.º 33
0
 def writes(self, nb, **kwargs):
     kwargs['cls'] = BytesEncoder
     kwargs['indent'] = 1
     kwargs['sort_keys'] = True
     kwargs['separators'] = (',', ': ')
     nb = copy.deepcopy(nb)
     nb = strip_transient(nb)
     if kwargs.pop('split_lines', True):
         nb = split_lines(nb)
     return py3compat.str_to_unicode(json.dumps(nb, **kwargs), 'utf-8')
Ejemplo n.º 34
0
def safe_unicode(e):
    """unicode(e) with various fallbacks. Used for exceptions, which may not be
    safe to call unicode() on.
    """
    try:
        return unicode(e)
    except UnicodeError:
        pass

    try:
        return py3compat.str_to_unicode(str(e))
    except UnicodeError:
        pass

    try:
        return py3compat.str_to_unicode(repr(e))
    except UnicodeError:
        pass

    return u'Unrecoverably corrupt evalue'
Ejemplo n.º 35
0
def safe_unicode(e):
    """unicode(e) with various fallbacks. Used for exceptions, which may not be
    safe to call unicode() on.
    """
    try:
        return unicode(e)
    except UnicodeError:
        pass

    try:
        return py3compat.str_to_unicode(str(e))
    except UnicodeError:
        pass

    try:
        return py3compat.str_to_unicode(repr(e))
    except UnicodeError:
        pass

    return u'Unrecoverably corrupt evalue'
Ejemplo n.º 36
0
 def writes(self, nb, **kwargs):
     """Serialize a NotebookNode object as a JSON string"""
     kwargs['cls'] = BytesEncoder
     kwargs['indent'] = 1
     kwargs['sort_keys'] = True
     kwargs['separators'] = (',', ': ')
     # don't modify in-memory dict
     nb = copy.deepcopy(nb)
     if kwargs.pop('split_lines', True):
         nb = split_lines(nb)
     nb = strip_transient(nb)
     return py3compat.str_to_unicode(json.dumps(nb, **kwargs), 'utf-8')
Ejemplo n.º 37
0
 def writes(self, nb, **kwargs):
     kwargs['cls'] = BytesEncoder
     kwargs['indent'] = 1
     kwargs['sort_keys'] = True
     kwargs['separators'] = (',',': ')
     nb = copy.deepcopy(nb)
     # don't write transient values to disk
     for key in ('orig_nbformat', 'orig_nbformat_minor'):
         nb.pop(key, None)
     if kwargs.pop('split_lines', True):
         nb = split_lines(nb)
     return py3compat.str_to_unicode(json.dumps(nb, **kwargs), 'utf-8')
Ejemplo n.º 38
0
 def writes(self, nb, **kwargs):
     """Serialize a NotebookNode object as a JSON string"""
     kwargs['cls'] = BytesEncoder
     kwargs['indent'] = 1
     kwargs['sort_keys'] = True
     kwargs['separators'] = (',',': ')
     # don't modify in-memory dict
     nb = copy.deepcopy(nb)
     if kwargs.pop('split_lines', True):
         nb = split_lines(nb)
     nb = strip_transient(nb)
     return py3compat.str_to_unicode(json.dumps(nb, **kwargs), 'utf-8')
Ejemplo n.º 39
0
 def _check_created(self, resp, name, path, type='notebook'):
     self.assertEqual(resp.status_code, 201)
     location_header = py3compat.str_to_unicode(resp.headers['Location'])
     self.assertEqual(location_header, url_escape(url_path_join(u'/api/contents', path, name)))
     rjson = resp.json()
     self.assertEqual(rjson['name'], name)
     self.assertEqual(rjson['path'], path)
     self.assertEqual(rjson['type'], type)
     isright = os.path.isdir if type == 'directory' else os.path.isfile
     assert isright(pjoin(
         self.notebook_dir.name,
         path.replace('/', os.sep),
         name,
     ))
Ejemplo n.º 40
0
    def log_write(self, data, kind="input"):
        """Write data to the log file, if active"""

        # print 'data: %r' % data # dbg
        if self.log_active and data:
            write = self.logfile.write
            if kind == "input":
                if self.timestamp:
                    write(str_to_unicode(time.strftime("# %a, %d %b %Y %H:%M:%S\n", time.localtime())))
                write(data)
            elif kind == "output" and self.log_output:
                odata = "\n".join(["#[Out]# %s" % s for s in data.splitlines()])
                write("%s\n" % odata)
            self.logfile.flush()
Ejemplo n.º 41
0
    def writes(self, notebook):
        body, resources = self.exporter.from_notebook_node(notebook)
        self.resources = resources

        if self.write_outputs:
            self.write_resources(resources)

        # remove any blank lines added at start and end by template
        text = re.sub(r'\A\s*\n|^\s*\Z', '', body)

        if not py3compat.PY3 and not isinstance(text, unicode_type):
            # this branch is likely only taken for JSON on Python 2
            text = py3compat.str_to_unicode(text)

        return text
Ejemplo n.º 42
0
 def perm_to_403(self, os_path=''):
     """context manager for turning permission errors into 403"""
     try:
         yield
     except OSError as e:
         if e.errno in {errno.EPERM, errno.EACCES}:
             # make 403 error message without root prefix
             # this may not work perfectly on unicode paths on Python 2,
             # but nobody should be doing that anyway.
             if not os_path:
                 os_path = str_to_unicode(e.filename or 'unknown file')
             path = to_api_path(os_path, self.root_dir)
             raise web.HTTPError(403, u'Permission denied: %s' % path)
         else:
             raise
Ejemplo n.º 43
0
 def perm_to_403(self, os_path=''):
     """context manager for turning permission errors into 403"""
     try:
         yield
     except OSError as e:
         if e.errno in {errno.EPERM, errno.EACCES}:
             # make 403 error message without root prefix
             # this may not work perfectly on unicode paths on Python 2,
             # but nobody should be doing that anyway.
             if not os_path:
                 os_path = str_to_unicode(e.filename or 'unknown file')
             path = to_api_path(os_path, self.root_dir)
             raise web.HTTPError(403, u'Permission denied: %s' % path)
         else:
             raise
Ejemplo n.º 44
0
    def writes(self, notebook):
        body, resources = self.exporter.from_notebook_node(notebook)
        self.resources = resources

        if self.write_outputs:
            self.write_resources(resources)

        # remove any blank lines added at start and end by template
        text = re.sub(r'\A\s*\n|^\s*\Z', '', body)

        if not py3compat.PY3 and not isinstance(text, unicode_type):
            # this branch is likely only taken for JSON on Python 2
            text = py3compat.str_to_unicode(text)

        return text
Ejemplo n.º 45
0
 def eval(self, line):
     '''
     Parse and evaluate a line with rpy2.
     Returns the output to R's stdout() connection
     and the value of eval(parse(line)).
     '''
     old_writeconsole = ri.get_writeconsole()
     ri.set_writeconsole(self.write_console)
     try:
         value = ri.baseenv['eval'](ri.parse(line))
     except (ri.RRuntimeError, ValueError) as exception:
         warning_or_other_msg = self.flush() # otherwise next return seems to have copy of error
         raise RInterpreterError(line, str_to_unicode(str(exception)), warning_or_other_msg)
     text_output = self.flush()
     ri.set_writeconsole(old_writeconsole)
     return text_output, value
Ejemplo n.º 46
0
    def log_write(self, data, kind='input'):
        """Write data to the log file, if active"""

        #print 'data: %r' % data # dbg
        if self.log_active and data:
            write = self.logfile.write
            if kind=='input':
                if self.timestamp:
                    write(str_to_unicode(time.strftime('# %a, %d %b %Y %H:%M:%S\n',
                                        time.localtime())))
                write(data)
            elif kind=='output' and self.log_output:
                odata = u'\n'.join([u'#[Out]# %s' % s
                                   for s in data.splitlines()])
                write(u'%s\n' % odata)
            self.logfile.flush()
Ejemplo n.º 47
0
    def log_write(self, data, kind='input'):
        """Write data to the log file, if active"""

        #print 'data: %r' % data # dbg
        if self.log_active and data:
            write = self.logfile.write
            if kind=='input':
                if self.timestamp:
                    write(str_to_unicode(time.strftime('# %a, %d %b %Y %H:%M:%S\n',
                                        time.localtime())))
                write(data)
            elif kind=='output' and self.log_output:
                odata = '\n'.join(['#[Out]# %s' % s
                                   for s in data.splitlines()])
                write('%s\n' % odata)
            self.logfile.flush()
Ejemplo n.º 48
0
 def eval(self, line):
     '''
     Parse and evaluate a line with rpy2.
     Returns the output to R's stdout() connection
     and the value of eval(parse(line)).
     '''
     old_writeconsole = ri.get_writeconsole()
     ri.set_writeconsole(self.write_console)
     try:
         value = ri.baseenv['eval'](ri.parse(line))
     except (ri.RRuntimeError, ValueError) as exception:
         warning_or_other_msg = self.flush() # otherwise next return seems to have copy of error
         raise RMagicError(unicode_to_str('parsing and evaluating line "%s".\nR error message: "%s"\n R stdout:"%s"\n' %
                                          (line, str_to_unicode(exception.message, 'utf-8'), warning_or_other_msg)))
     text_output = self.flush()
     ri.set_writeconsole(old_writeconsole)
     return text_output, value
Ejemplo n.º 49
0
 def _check_created(self, resp, name, path, type='notebook'):
     self.assertEqual(resp.status_code, 201)
     location_header = py3compat.str_to_unicode(resp.headers['Location'])
     self.assertEqual(
         location_header,
         url_escape(url_path_join(u'/api/contents', path, name)))
     rjson = resp.json()
     self.assertEqual(rjson['name'], name)
     self.assertEqual(rjson['path'], path)
     self.assertEqual(rjson['type'], type)
     isright = os.path.isdir if type == 'directory' else os.path.isfile
     assert isright(
         pjoin(
             self.notebook_dir.name,
             path.replace('/', os.sep),
             name,
         ))
Ejemplo n.º 50
0
 def eval(self, line):
     '''
     Parse and evaluate a line with rpy2.
     Returns the output to R's stdout() connection
     and the value of eval(parse(line)).
     '''
     old_writeconsole = ri.get_writeconsole()
     ri.set_writeconsole(self.write_console)
     try:
         value = ri.baseenv['eval'](ri.parse(line))
     except (ri.RRuntimeError, ValueError) as exception:
         warning_or_other_msg = self.flush(
         )  # otherwise next return seems to have copy of error
         raise RInterpreterError(line, str_to_unicode(str(exception)),
                                 warning_or_other_msg)
     text_output = self.flush()
     ri.set_writeconsole(old_writeconsole)
     return text_output, value
Ejemplo n.º 51
0
def get_pasted_lines(sentinel, l_input=py3compat.input, quiet=False):
    """ Yield pasted lines until the user enters the given sentinel value.
    """
    if not quiet:
        print("Pasting code; enter '%s' alone on the line to stop or use Ctrl-D." \
              % sentinel)
        prompt = ":"
    else:
        prompt = ""
    while True:
        try:
            l = py3compat.str_to_unicode(l_input(prompt))
            if l == sentinel:
                return
            else:
                yield l
        except EOFError:
            print('<EOF>')
            return
Ejemplo n.º 52
0
    def raw_input(self, prompt=''):
        """Write a prompt and read a line.

        The returned line does not include the trailing newline.
        When the user enters the EOF key sequence, EOFError is raised.

        Optional inputs:

          - prompt(''): a string to be printed to prompt the user.

          - continue_prompt(False): whether this line is the first one or a
          continuation in a sequence of inputs.
        """
        # Code run by the user may have modified the readline completer state.
        # We must ensure that our completer is back in place.

        if self.has_readline:
            self.set_readline_completer()

        # raw_input expects str, but we pass it unicode sometimes
        prompt = py3compat.cast_bytes_py2(prompt)

        try:
            line = py3compat.str_to_unicode(self.raw_input_original(prompt))
        except ValueError:
            warn("\n********\nYou or a %run:ed script called sys.stdin.close()"
                 " or sys.stdout.close()!\nExiting IPython!\n")
            self.ask_exit()
            return ""

        # Try to be reasonably smart about not re-indenting pasted input more
        # than necessary.  We do this by trimming out the auto-indent initial
        # spaces, if the user's actual input started itself with whitespace.
        if self.autoindent:
            if num_ini_spaces(line) > self.indent_current_nsp:
                line = line[self.indent_current_nsp:]
                self.indent_current_nsp = 0

        return line
Ejemplo n.º 53
0
    def eval(self, line):
        '''
        Parse and evaluate a line of R code with rpy2.
        Returns the output to R's stdout() connection, 
        the value generated by evaluating the code, and a
        boolean indicating whether the return value would be
        visible if the line of code were evaluated in an R REPL.

        R Code evaluation and visibility determination are done via an R call of
        the form withVisible(eval(parse(code_string)))

        '''
        old_writeconsole = ri.get_writeconsole()
        ri.set_writeconsole(self.write_console)
        try:
            value, visible = ro.r.withVisible(ro.r.eval(ro.r.parse(text=line)))
        except (ri.RRuntimeError, ValueError) as exception:
            warning_or_other_msg = self.flush(
            )  # otherwise next return seems to have copy of error
            raise RInterpreterError(line, str_to_unicode(str(exception)),
                                    warning_or_other_msg)
        text_output = self.flush()
        ri.set_writeconsole(old_writeconsole)
        return text_output, value, visible[0]
Ejemplo n.º 54
0
# -*- coding: utf-8 -*-
"""Tests for the Cython magics extension."""

import os
import nose.tools as nt

from IPython.testing import decorators as dec
from IPython.utils import py3compat

code = py3compat.str_to_unicode("""def f(x):
    return 2*x
""")

try:
    import Cython
except:
    __test__ = False

ip = get_ipython()


def setup():
    ip.extension_manager.load_extension('cythonmagic')


def test_cython_inline():
    ip.ex('a=10; b=20')
    result = ip.run_cell_magic('cython_inline','','return a+b')
    nt.assert_equal(result, 30)

Ejemplo n.º 55
0
class Session(Configurable):
    """Object for handling serialization and sending of messages.

    The Session object handles building messages and sending them
    with ZMQ sockets or ZMQStream objects.  Objects can communicate with each
    other over the network via Session objects, and only need to work with the
    dict-based IPython message spec. The Session will handle
    serialization/deserialization, security, and metadata.

    Sessions support configurable serialization via packer/unpacker traits,
    and signing with HMAC digests via the key/keyfile traits.

    Parameters
    ----------

    debug : bool
        whether to trigger extra debugging statements
    packer/unpacker : str : 'json', 'pickle' or import_string
        importstrings for methods to serialize message parts.  If just
        'json' or 'pickle', predefined JSON and pickle packers will be used.
        Otherwise, the entire importstring must be used.

        The functions must accept at least valid JSON input, and output *bytes*.

        For example, to use msgpack:
        packer = 'msgpack.packb', unpacker='msgpack.unpackb'
    pack/unpack : callables
        You can also set the pack/unpack callables for serialization directly.
    session : bytes
        the ID of this Session object.  The default is to generate a new UUID.
    username : unicode
        username added to message headers.  The default is to ask the OS.
    key : bytes
        The key used to initialize an HMAC signature.  If unset, messages
        will not be signed or checked.
    keyfile : filepath
        The file containing a key.  If this is set, `key` will be initialized
        to the contents of the file.

    """

    debug = Bool(False, config=True, help="""Debug output in the Session""")

    packer = DottedObjectName(
        'json',
        config=True,
        help="""The name of the packer for serializing messages.
            Should be one of 'json', 'pickle', or an import name
            for a custom callable serializer.""")

    def _packer_changed(self, name, old, new):
        if new.lower() == 'json':
            self.pack = json_packer
            self.unpack = json_unpacker
            self.unpacker = new
        elif new.lower() == 'pickle':
            self.pack = pickle_packer
            self.unpack = pickle_unpacker
            self.unpacker = new
        else:
            self.pack = import_item(str(new))

    unpacker = DottedObjectName(
        'json',
        config=True,
        help="""The name of the unpacker for unserializing messages.
        Only used with custom functions for `packer`.""")

    def _unpacker_changed(self, name, old, new):
        if new.lower() == 'json':
            self.pack = json_packer
            self.unpack = json_unpacker
            self.packer = new
        elif new.lower() == 'pickle':
            self.pack = pickle_packer
            self.unpack = pickle_unpacker
            self.packer = new
        else:
            self.unpack = import_item(str(new))

    session = CUnicode(u'',
                       config=True,
                       help="""The UUID identifying this session.""")

    def _session_default(self):
        u = unicode_type(uuid.uuid4())
        self.bsession = u.encode('ascii')
        return u

    def _session_changed(self, name, old, new):
        self.bsession = self.session.encode('ascii')

    # bsession is the session as bytes
    bsession = CBytes(b'')

    username = Unicode(
        str_to_unicode(os.environ.get('USER', 'username')),
        help="""Username for the Session. Default is your system username.""",
        config=True)

    metadata = Dict(
        {},
        config=True,
        help=
        """Metadata dictionary, which serves as the default top-level metadata dict for each message."""
    )

    # if 0, no adapting to do.
    adapt_version = Integer(0)

    # message signature related traits:

    key = CBytes(b'',
                 config=True,
                 help="""execution key, for extra authentication.""")

    def _key_changed(self):
        self._new_auth()

    signature_scheme = Unicode(
        'hmac-sha256',
        config=True,
        help="""The digest scheme used to construct the message signatures.
        Must have the form 'hmac-HASH'.""")

    def _signature_scheme_changed(self, name, old, new):
        if not new.startswith('hmac-'):
            raise TraitError(
                "signature_scheme must start with 'hmac-', got %r" % new)
        hash_name = new.split('-', 1)[1]
        try:
            self.digest_mod = getattr(hashlib, hash_name)
        except AttributeError:
            raise TraitError("hashlib has no such attribute: %s" % hash_name)
        self._new_auth()

    digest_mod = Any()

    def _digest_mod_default(self):
        return hashlib.sha256

    auth = Instance(hmac.HMAC)

    def _new_auth(self):
        if self.key:
            self.auth = hmac.HMAC(self.key, digestmod=self.digest_mod)
        else:
            self.auth = None

    digest_history = Set()
    digest_history_size = Integer(
        2**16,
        config=True,
        help="""The maximum number of digests to remember.
        
        The digest history will be culled when it exceeds this value.
        """)

    keyfile = Unicode('',
                      config=True,
                      help="""path to file containing execution key.""")

    def _keyfile_changed(self, name, old, new):
        with open(new, 'rb') as f:
            self.key = f.read().strip()

    # for protecting against sends from forks
    pid = Integer()

    # serialization traits:

    pack = Any(default_packer)  # the actual packer function

    def _pack_changed(self, name, old, new):
        if not callable(new):
            raise TypeError("packer must be callable, not %s" % type(new))

    unpack = Any(default_unpacker)  # the actual packer function

    def _unpack_changed(self, name, old, new):
        # unpacker is not checked - it is assumed to be
        if not callable(new):
            raise TypeError("unpacker must be callable, not %s" % type(new))

    # thresholds:
    copy_threshold = Integer(
        2**16,
        config=True,
        help=
        "Threshold (in bytes) beyond which a buffer should be sent without copying."
    )
    buffer_threshold = Integer(
        MAX_BYTES,
        config=True,
        help=
        "Threshold (in bytes) beyond which an object's buffer should be extracted to avoid pickling."
    )
    item_threshold = Integer(
        MAX_ITEMS,
        config=True,
        help=
        """The maximum number of items for a container to be introspected for custom serialization.
        Containers larger than this are pickled outright.
        """)

    def __init__(self, **kwargs):
        """create a Session object

        Parameters
        ----------

        debug : bool
            whether to trigger extra debugging statements
        packer/unpacker : str : 'json', 'pickle' or import_string
            importstrings for methods to serialize message parts.  If just
            'json' or 'pickle', predefined JSON and pickle packers will be used.
            Otherwise, the entire importstring must be used.

            The functions must accept at least valid JSON input, and output
            *bytes*.

            For example, to use msgpack:
            packer = 'msgpack.packb', unpacker='msgpack.unpackb'
        pack/unpack : callables
            You can also set the pack/unpack callables for serialization
            directly.
        session : unicode (must be ascii)
            the ID of this Session object.  The default is to generate a new
            UUID.
        bsession : bytes
            The session as bytes
        username : unicode
            username added to message headers.  The default is to ask the OS.
        key : bytes
            The key used to initialize an HMAC signature.  If unset, messages
            will not be signed or checked.
        signature_scheme : str
            The message digest scheme. Currently must be of the form 'hmac-HASH',
            where 'HASH' is a hashing function available in Python's hashlib.
            The default is 'hmac-sha256'.
            This is ignored if 'key' is empty.
        keyfile : filepath
            The file containing a key.  If this is set, `key` will be
            initialized to the contents of the file.
        """
        super(Session, self).__init__(**kwargs)
        self._check_packers()
        self.none = self.pack({})
        # ensure self._session_default() if necessary, so bsession is defined:
        self.session
        self.pid = os.getpid()

    @property
    def msg_id(self):
        """always return new uuid"""
        return str(uuid.uuid4())

    def _check_packers(self):
        """check packers for datetime support."""
        pack = self.pack
        unpack = self.unpack

        # check simple serialization
        msg = dict(a=[1, 'hi'])
        try:
            packed = pack(msg)
        except Exception as e:
            msg = "packer '{packer}' could not serialize a simple message: {e}{jsonmsg}"
            if self.packer == 'json':
                jsonmsg = "\nzmq.utils.jsonapi.jsonmod = %s" % jsonapi.jsonmod
            else:
                jsonmsg = ""
            raise ValueError(
                msg.format(packer=self.packer, e=e, jsonmsg=jsonmsg))

        # ensure packed message is bytes
        if not isinstance(packed, bytes):
            raise ValueError("message packed to %r, but bytes are required" %
                             type(packed))

        # check that unpack is pack's inverse
        try:
            unpacked = unpack(packed)
            assert unpacked == msg
        except Exception as e:
            msg = "unpacker '{unpacker}' could not handle output from packer '{packer}': {e}{jsonmsg}"
            if self.packer == 'json':
                jsonmsg = "\nzmq.utils.jsonapi.jsonmod = %s" % jsonapi.jsonmod
            else:
                jsonmsg = ""
            raise ValueError(
                msg.format(packer=self.packer,
                           unpacker=self.unpacker,
                           e=e,
                           jsonmsg=jsonmsg))

        # check datetime support
        msg = dict(t=datetime.now())
        try:
            unpacked = unpack(pack(msg))
            if isinstance(unpacked['t'], datetime):
                raise ValueError("Shouldn't deserialize to datetime")
        except Exception:
            self.pack = lambda o: pack(squash_dates(o))
            self.unpack = lambda s: unpack(s)

    def msg_header(self, msg_type):
        return msg_header(self.msg_id, msg_type, self.username, self.session)

    def msg(self,
            msg_type,
            content=None,
            parent=None,
            header=None,
            metadata=None):
        """Return the nested message dict.

        This format is different from what is sent over the wire. The
        serialize/deserialize methods converts this nested message dict to the wire
        format, which is a list of message parts.
        """
        msg = {}
        header = self.msg_header(msg_type) if header is None else header
        msg['header'] = header
        msg['msg_id'] = header['msg_id']
        msg['msg_type'] = header['msg_type']
        msg['parent_header'] = {} if parent is None else extract_header(parent)
        msg['content'] = {} if content is None else content
        msg['metadata'] = self.metadata.copy()
        if metadata is not None:
            msg['metadata'].update(metadata)
        return msg

    def sign(self, msg_list):
        """Sign a message with HMAC digest. If no auth, return b''.

        Parameters
        ----------
        msg_list : list
            The [p_header,p_parent,p_content] part of the message list.
        """
        if self.auth is None:
            return b''
        h = self.auth.copy()
        for m in msg_list:
            h.update(m)
        return str_to_bytes(h.hexdigest())

    def serialize(self, msg, ident=None):
        """Serialize the message components to bytes.

        This is roughly the inverse of deserialize. The serialize/deserialize
        methods work with full message lists, whereas pack/unpack work with
        the individual message parts in the message list.

        Parameters
        ----------
        msg : dict or Message
            The next message dict as returned by the self.msg method.

        Returns
        -------
        msg_list : list
            The list of bytes objects to be sent with the format::

                [ident1, ident2, ..., DELIM, HMAC, p_header, p_parent,
                 p_metadata, p_content, buffer1, buffer2, ...]

            In this list, the ``p_*`` entities are the packed or serialized
            versions, so if JSON is used, these are utf8 encoded JSON strings.
        """
        content = msg.get('content', {})
        if content is None:
            content = self.none
        elif isinstance(content, dict):
            content = self.pack(content)
        elif isinstance(content, bytes):
            # content is already packed, as in a relayed message
            pass
        elif isinstance(content, unicode_type):
            # should be bytes, but JSON often spits out unicode
            content = content.encode('utf8')
        else:
            raise TypeError("Content incorrect type: %s" % type(content))

        real_message = [
            self.pack(msg['header']),
            self.pack(msg['parent_header']),
            self.pack(msg['metadata']),
            content,
        ]

        to_send = []

        if isinstance(ident, list):
            # accept list of idents
            to_send.extend(ident)
        elif ident is not None:
            to_send.append(ident)
        to_send.append(DELIM)

        signature = self.sign(real_message)
        to_send.append(signature)

        to_send.extend(real_message)

        return to_send

    def send(self,
             stream,
             msg_or_type,
             content=None,
             parent=None,
             ident=None,
             buffers=None,
             track=False,
             header=None,
             metadata=None):
        """Build and send a message via stream or socket.

        The message format used by this function internally is as follows:

        [ident1,ident2,...,DELIM,HMAC,p_header,p_parent,p_content,
         buffer1,buffer2,...]

        The serialize/deserialize methods convert the nested message dict into this
        format.

        Parameters
        ----------

        stream : zmq.Socket or ZMQStream
            The socket-like object used to send the data.
        msg_or_type : str or Message/dict
            Normally, msg_or_type will be a msg_type unless a message is being
            sent more than once. If a header is supplied, this can be set to
            None and the msg_type will be pulled from the header.

        content : dict or None
            The content of the message (ignored if msg_or_type is a message).
        header : dict or None
            The header dict for the message (ignored if msg_to_type is a message).
        parent : Message or dict or None
            The parent or parent header describing the parent of this message
            (ignored if msg_or_type is a message).
        ident : bytes or list of bytes
            The zmq.IDENTITY routing path.
        metadata : dict or None
            The metadata describing the message
        buffers : list or None
            The already-serialized buffers to be appended to the message.
        track : bool
            Whether to track.  Only for use with Sockets, because ZMQStream
            objects cannot track messages.
            

        Returns
        -------
        msg : dict
            The constructed message.
        """
        if not isinstance(stream, zmq.Socket):
            # ZMQStreams and dummy sockets do not support tracking.
            track = False

        if isinstance(msg_or_type, (Message, dict)):
            # We got a Message or message dict, not a msg_type so don't
            # build a new Message.
            msg = msg_or_type
            buffers = buffers or msg.get('buffers', [])
        else:
            msg = self.msg(msg_or_type,
                           content=content,
                           parent=parent,
                           header=header,
                           metadata=metadata)
        if not os.getpid() == self.pid:
            io.rprint("WARNING: attempted to send message from fork")
            io.rprint(msg)
            return
        buffers = [] if buffers is None else buffers
        if self.adapt_version:
            msg = adapt(msg, self.adapt_version)
        to_send = self.serialize(msg, ident)
        to_send.extend(buffers)
        longest = max([len(s) for s in to_send])
        copy = (longest < self.copy_threshold)

        if buffers and track and not copy:
            # only really track when we are doing zero-copy buffers
            tracker = stream.send_multipart(to_send, copy=False, track=True)
        else:
            # use dummy tracker, which will be done immediately
            tracker = DONE
            stream.send_multipart(to_send, copy=copy)

        if self.debug:
            pprint.pprint(msg)
            pprint.pprint(to_send)
            pprint.pprint(buffers)

        msg['tracker'] = tracker

        return msg

    def send_raw(self, stream, msg_list, flags=0, copy=True, ident=None):
        """Send a raw message via ident path.

        This method is used to send a already serialized message.

        Parameters
        ----------
        stream : ZMQStream or Socket
            The ZMQ stream or socket to use for sending the message.
        msg_list : list
            The serialized list of messages to send. This only includes the
            [p_header,p_parent,p_metadata,p_content,buffer1,buffer2,...] portion of
            the message.
        ident : ident or list
            A single ident or a list of idents to use in sending.
        """
        to_send = []
        if isinstance(ident, bytes):
            ident = [ident]
        if ident is not None:
            to_send.extend(ident)

        to_send.append(DELIM)
        to_send.append(self.sign(msg_list))
        to_send.extend(msg_list)
        stream.send_multipart(to_send, flags, copy=copy)

    def recv(self, socket, mode=zmq.NOBLOCK, content=True, copy=True):
        """Receive and unpack a message.

        Parameters
        ----------
        socket : ZMQStream or Socket
            The socket or stream to use in receiving.

        Returns
        -------
        [idents], msg
            [idents] is a list of idents and msg is a nested message dict of
            same format as self.msg returns.
        """
        if isinstance(socket, ZMQStream):
            socket = socket.socket
        try:
            msg_list = socket.recv_multipart(mode, copy=copy)
        except zmq.ZMQError as e:
            if e.errno == zmq.EAGAIN:
                # We can convert EAGAIN to None as we know in this case
                # recv_multipart won't return None.
                return None, None
            else:
                raise
        # split multipart message into identity list and message dict
        # invalid large messages can cause very expensive string comparisons
        idents, msg_list = self.feed_identities(msg_list, copy)
        try:
            return idents, self.deserialize(msg_list,
                                            content=content,
                                            copy=copy)
        except Exception as e:
            # TODO: handle it
            raise e

    def feed_identities(self, msg_list, copy=True):
        """Split the identities from the rest of the message.

        Feed until DELIM is reached, then return the prefix as idents and
        remainder as msg_list. This is easily broken by setting an IDENT to DELIM,
        but that would be silly.

        Parameters
        ----------
        msg_list : a list of Message or bytes objects
            The message to be split.
        copy : bool
            flag determining whether the arguments are bytes or Messages

        Returns
        -------
        (idents, msg_list) : two lists
            idents will always be a list of bytes, each of which is a ZMQ
            identity. msg_list will be a list of bytes or zmq.Messages of the
            form [HMAC,p_header,p_parent,p_content,buffer1,buffer2,...] and
            should be unpackable/unserializable via self.deserialize at this
            point.
        """
        if copy:
            idx = msg_list.index(DELIM)
            return msg_list[:idx], msg_list[idx + 1:]
        else:
            failed = True
            for idx, m in enumerate(msg_list):
                if m.bytes == DELIM:
                    failed = False
                    break
            if failed:
                raise ValueError("DELIM not in msg_list")
            idents, msg_list = msg_list[:idx], msg_list[idx + 1:]
            return [m.bytes for m in idents], msg_list

    def _add_digest(self, signature):
        """add a digest to history to protect against replay attacks"""
        if self.digest_history_size == 0:
            # no history, never add digests
            return

        self.digest_history.add(signature)
        if len(self.digest_history) > self.digest_history_size:
            # threshold reached, cull 10%
            self._cull_digest_history()

    def _cull_digest_history(self):
        """cull the digest history
        
        Removes a randomly selected 10% of the digest history
        """
        current = len(self.digest_history)
        n_to_cull = max(int(current // 10), current - self.digest_history_size)
        if n_to_cull >= current:
            self.digest_history = set()
            return
        to_cull = random.sample(self.digest_history, n_to_cull)
        self.digest_history.difference_update(to_cull)

    def deserialize(self, msg_list, content=True, copy=True):
        """Unserialize a msg_list to a nested message dict.

        This is roughly the inverse of serialize. The serialize/deserialize
        methods work with full message lists, whereas pack/unpack work with
        the individual message parts in the message list.

        Parameters
        ----------
        msg_list : list of bytes or Message objects
            The list of message parts of the form [HMAC,p_header,p_parent,
            p_metadata,p_content,buffer1,buffer2,...].
        content : bool (True)
            Whether to unpack the content dict (True), or leave it packed
            (False).
        copy : bool (True)
            Whether to return the bytes (True), or the non-copying Message
            object in each place (False).

        Returns
        -------
        msg : dict
            The nested message dict with top-level keys [header, parent_header,
            content, buffers].
        """
        minlen = 5
        message = {}
        if not copy:
            for i in range(minlen):
                msg_list[i] = msg_list[i].bytes
        if self.auth is not None:
            signature = msg_list[0]
            if not signature:
                raise ValueError("Unsigned Message")
            if signature in self.digest_history:
                raise ValueError("Duplicate Signature: %r" % signature)
            self._add_digest(signature)
            check = self.sign(msg_list[1:5])
            if not compare_digest(signature, check):
                raise ValueError("Invalid Signature: %r" % signature)
        if not len(msg_list) >= minlen:
            raise TypeError(
                "malformed message, must have at least %i elements" % minlen)
        header = self.unpack(msg_list[1])
        message['header'] = extract_dates(header)
        message['msg_id'] = header['msg_id']
        message['msg_type'] = header['msg_type']
        message['parent_header'] = extract_dates(self.unpack(msg_list[2]))
        message['metadata'] = self.unpack(msg_list[3])
        if content:
            message['content'] = self.unpack(msg_list[4])
        else:
            message['content'] = msg_list[4]

        message['buffers'] = msg_list[5:]
        # adapt to the current version
        return adapt(message)

    def unserialize(self, *args, **kwargs):
        warnings.warn(
            "Session.unserialize is deprecated. Use Session.deserialize.",
            DeprecationWarning,
        )
        return self.deserialize(*args, **kwargs)
Ejemplo n.º 56
0
 def read(self, fp, **kwargs):
     """Read a notebook from a file like object"""
     nbs = fp.read()
     if not py3compat.PY3 and not isinstance(nbs, unicode):
         nbs = py3compat.str_to_unicode(nbs)
     return self.reads(nbs, **kwargs)