Exemple #1
0
def run_cell(kc, cell):
    iopub = kc.iopub_channel
    shell = kc.shell_channel

    kc.execute(cell.source)
    shell.get_msg(timeout=20)

    outs = []

    while True:
        try:
            msg = iopub.get_msg(timeout=0.2)
        except Empty:
            break

        msg_type = msg['msg_type']

        if msg_type in ('status', 'pyin'):
            continue
        elif msg_type == 'clear_output':
            outs = []
            continue

        content = msg['content']
        out = NotebookNode(output_type=msg_type)

        if msg_type == 'stream':
            out.stream = content['name']
            out.text = content['data']
        elif msg_type in ('display_data', 'execute_result'):
            for mime, data in iteritems(content['data']):
                attr = mime.split('/')[-1].lower()
                # this gets most right, but fix svg+html, plain
                attr = attr.replace('+xml', '').replace('plain', 'text')
                setattr(out, attr, data)
            if msg_type == 'execute_result':
                out.prompt_number = content['execution_count']
        elif msg_type == 'error':
            out.ename = content['ename']
            out.evalue = content['evalue']
            out.traceback = content['traceback']
        elif msg_type == 'execute_input':
            pass
        else:
            print("unhandled iopub msg:", msg_type)

        outs.append(out)
    return outs
Exemple #2
0
def run_cell(kc, cell):
    iopub = kc.iopub_channel
    shell = kc.shell_channel

    kc.execute(cell.source)
    shell.get_msg(timeout=20)

    outs = []

    while True:
        try:
            msg = iopub.get_msg(timeout=0.2)
        except Empty:
            break

        msg_type = msg['msg_type']

        if msg_type in ('status', 'pyin'):
            continue
        elif msg_type == 'clear_output':
            outs = []
            continue

        content = msg['content']
        out = NotebookNode(output_type=msg_type)

        if msg_type == 'stream':
            out.stream = content['name']
            out.text = content['data']
        elif msg_type in ('display_data', 'execute_result'):
            for mime, data in iteritems(content['data']):
                attr = mime.split('/')[-1].lower()
                # this gets most right, but fix svg+html, plain
                attr = attr.replace('+xml', '').replace('plain', 'text')
                setattr(out, attr, data)
            if msg_type == 'execute_result':
                out.prompt_number = content['execution_count']
        elif msg_type == 'error':
            out.ename = content['ename']
            out.evalue = content['evalue']
            out.traceback = content['traceback']
        elif msg_type == 'execute_input':
            pass
        else:
            print("unhandled iopub msg:", msg_type)

        outs.append(out)
    return outs
Exemple #3
0
    def run_cell(self, cell):
        """Run a notebook cell and update the output of that cell in-place."""
        logging.info('Running cell:\n%s\n', cell.input)
        self.kc.execute(cell.input)
        reply = self.kc.get_shell_msg()
        status = reply['content']['status']
        traceback_text = ''
        if status == 'error':
            traceback_text = 'Cell raised uncaught exception: \n' + \
                '\n'.join(reply['content']['traceback'])
            logging.info(traceback_text)
        else:
            logging.info('Cell returned')

        outs = list()
        while True:
            try:
                msg = self.kc.get_iopub_msg(timeout=1)
                if msg['msg_type'] == 'status':
                    if msg['content']['execution_state'] == 'idle':
                        break
            except Empty:
                # execution state should return to idle
                # before the queue becomes empty,
                # if it doesn't, something bad has happened
                raise

            content = msg['content']
            msg_type = msg['msg_type']

            # IPython 3.0.0-dev writes pyerr/pyout in the notebook format
            # but uses error/execute_result in the message spec. This does the
            # translation needed for tests to pass with IPython 3.0.0-dev
            notebook3_format_conversions = {
                'error': 'pyerr',
                'execute_result': 'pyout'
            }
            msg_type = notebook3_format_conversions.get(msg_type, msg_type)

            out = NotebookNode(output_type=msg_type)

            if 'execution_count' in content:
                cell['prompt_number'] = content['execution_count']
                out.prompt_number = content['execution_count']

            if msg_type in ('status', 'pyin', 'execute_input'):
                continue
            elif msg_type == 'stream':
                out.stream = content['name']
                # in msgspec 5, this is name, text
                # in msgspec 4, this is name, data
                if 'text' in content:
                    out.text = content['text']
                else:
                    out.text = content['data']
            elif msg_type in ('display_data', 'pyout'):
                for mime, data in content['data'].items():
                    try:
                        attr = self.MIME_MAP[mime]
                    except KeyError:
                        raise NotImplementedError(
                            'unhandled mime type: %s' % mime
                        )

                    # In notebook version <= 3 JSON data is stored as a string
                    # Evaluation of IPython2's JSON gives strings directly
                    # Therefore do not encode for IPython versions prior to 3
                    json_encode = (
                            IPython.version_info[0] >= 3 and
                            mime == "application/json")

                    data_out = data if not json_encode else json.dumps(data)
                    setattr(out, attr, data_out)
            elif msg_type == 'pyerr':
                out.ename = content['ename']
                out.evalue = content['evalue']
                out.traceback = content['traceback']
            elif msg_type == 'clear_output':
                outs = list()
                continue
            else:
                raise NotImplementedError(
                    'unhandled iopub message: %s' % msg_type
                )
            outs.append(out)
        cell['outputs'] = outs
        logging.info('Cell output:\n%s\n', outs)
        if status == 'error':
            raise NotebookError(traceback_text)
    def run(self, cell, timeout=None):
        """
        Run a notebook cell in the IPythonKernel

        Parameters
        ----------
        cell : IPython.notebook.Cell
            the cell to be run
        timeout : int or None (default)
            the time in seconds after which a cell is stopped and assumed to
            have timed out. If set to None the value in `default_timeout`
            is used

        Returns
        -------
        list of outs
            a list of NotebookNodes of the returned types. This is
            similar to the list of outputs generated when a cell is run
        """

        use_timeout = self.default_timeout

        if timeout is not None:
            use_timeout = timeout

        if hasattr(cell, 'input'):
            self.kc.execute(cell.input)
        elif hasattr(cell, 'source'):
            self.kc.execute(cell.source)
        else:
            raise AttributeError('No source/input key')

        self.shell.get_msg(timeout=use_timeout)
        outs = []

        while True:
            try:
                msg = self.iopub.get_msg(timeout=0.5)
            except Empty:
                break
            msg_type = msg['msg_type']
            if msg_type in ('status', 'pyin', 'execute_input'):
                continue
            elif msg_type == 'clear_output':
                outs = []
                continue

            content = msg['content']
            out = NotebookNode(output_type=msg_type)

            if msg_type == 'stream':
                out.name = content['name']
                out.text = content['text']
            elif msg_type in ('display_data', 'pyout', 'execute_result'):
                if hasattr(content, 'execution_count'):
                    out['execution_count'] = content['execution_count']
                else:
                    out['execution_count'] = None
                out['data'] = content['data']
                out['metadata'] = content['metadata']

            elif msg_type == 'error':
                out.ename = content['ename']
                out.evalue = content['evalue']
                out.traceback = content['traceback']
            else:
                print "unhandled iopub msg:", msg_type

            outs.append(out)

        return outs
    def runtest(self):
        """
        Run all the cell tests in one kernel without restarting.
        It is very common for ipython notebooks to run through assuming a
        single kernel.
        """
        # Execute the code from the current cell and get the msg_id
        # of the shell process.
        msg_id = self.parent.kernel.execute_cell_input(
            self.cell.source, allow_stdin=False)

        # Time for the reply of the cell execution
        timeout = 2000

        # This list stores the output information for the entire cell
        outs = []

        # Wait for the execution reply (we can see this in the msg_type)
        # This execution produces a dictionary where a status string can be
        # obtained: 'ok' OR 'error' OR 'abort'
        # We can also get how many cells have been executed
        # until here, with the 'execution_count' entry
        # self.parent.kernel.kc.get_shell_msg(timeout=timeout)

        while True:
            """
            The messages from the cell contain information such
            as input code, outputs generated
            and other messages. We iterate through each message
            until we reach the end of the cell.
            """
            try:
                # Get one message at a time, per code block inside the cell
                msg = self.parent.get_kernel_message(timeout=1.)

            except Empty:
                # This is not working: ! The code will not be checked
                # if the time is out (when the cell stops to be executed?)
                # raise NbCellError("Timeout of %d seconds exceeded"
                #                      " executing cell: %s" (timeout,
                #                                             self.cell.input))
                # Just break the loop when the output is empty
                break

            """
            Now that we have the output from a piece of code
            inside the cell,
            we want to compare the outputs of the messages
            to a reference output (the ones that are present before
            the notebook was executed)
            """

            # print msg

            # Firstly, get the msg type from the cell to know if
            # the output comes from a code
            # It seems that the type 'stream' is irrelevant
            msg_type = msg['msg_type']
            reply = msg['content']

            # REF:
            # execute_input: To let all frontends know what code is
            # being executed at any given time, these messages contain a
            # re-broadcast of the code portion of an execute_request,
            # along with the execution_count.
            if msg_type == 'status':
                if reply['execution_state'] == 'idle':
                    break
                else:
                    continue
            elif msg_type == 'execute_input':
                continue
            elif msg_type.startswith('comm'):
                continue
            elif msg_type == 'execute_reply':
                # print msg
                continue
            # If there is no more output, continue with the executions
            # (it will break if it is empty, with the previous statements)
            #
            # REF:
            # This message type is used to clear the output that is
            # visible on the frontend
            # elif msg_type == 'clear_output':
            #     outs = []
            #     continue

            # I added the msg_type 'idle' condition (when the cell stops)
            # so we get a complete cell output
            # REF:
            # When the kernel starts to execute code, it will enter the 'busy'
            # state and when it finishes, it will enter the 'idle' state.
            # The kernel will publish state 'starting' exactly
            # once at process startup.
            # elif (msg_type == 'clear_output'
            #       and msg_type['execution_state'] == 'idle'):
            #     outs = []
            #     continue

            # WE COULD ADD HERE a condition for the 'error' message type
            # Making the test to fail

            """
            Now we get the reply from the piece of code executed
            and analyse the outputs
            """
            reply = msg['content']
            out = NotebookNode(output_type=msg_type)

            # print '---------------------------- CELL ----------------------'
            # print msg_type
            # print reply
            # print '---------------------------- CELL ORIGINAL----------------'
            # print self.cell.outputs

            # Now check what type of output it is
            if msg_type == 'stream':
                out.stream = reply['name']
                out.text = reply['text']

            # REF:
            # 'execute_result' is equivalent to a display_data message.
            # The object being displayed is passed to the display
            # hook, i.e. the *result* of the execution.
            # The only difference is that 'execute_result' has an
            # 'execution_count' number which does not seems useful
            # (we will filter it in the sanitize function)
            #
            # When the reply is display_data or execute_count,
            # the dictionary contains
            # a 'data' sub-dictionary with the 'text' AND the 'image/png'
            # picture (in hexadecimal). There is also a 'metadata' entry
            # but currently is not of much use, sometimes there is information
            # as height and width of the image (CHECK the documentation)
            # Thus we iterate through the keys (mimes) 'data' sub-dictionary
            # to obtain the 'text' and 'image/png' information
            #
            # We NO longer replace 'image/png' by 'png' since the last version
            # of the notebook format is more consistent. We also DO NOT
            # replace any .xml string, it's not neccesary

            # elif msg_type in ('display_data', 'execute_result'):
            elif msg_type in ('display_data', 'execute_result'):
                out['metadata'] = reply['metadata']
                for mime, data in reply['data'].iteritems():
                # This could be useful for reference or backward compatibility
                #     attr = mime.split('/')[-1].lower()
                #     attr = attr.replace('+xml', '').replace('plain', 'text')
                #     setattr(out, attr, data)

                # Return the relevant entries from data:
                # plain/text, image/png, execution_count, etc
                # We coul use a mime types list for this (MAYBE)
                    setattr(out, mime, data)

                # if msg_type == 'execute_result':
                #     out.prompt_number = reply['execution_count']

            else:
                print("unhandled iopub msg:", msg_type)

            outs.append(out)

        """
        This message is the last message of the cell, which contains no output.
        It only indicates whether the entire cell ran successfully or if there
        was an error.
        """
        # reply = msg['content']

        failed = False

        # THIS COMPARISON IS ONLY WHEN THE OUTPUT DICTIONARIES
        # ARE DIFFERENT, WHICH IS A DIFFERENT ERROR, not
        # from the output in the notebook
        #
        # SINCE WE SANITIZE AND COMPARE, IF THERE ARE DIFFERENT
        # NUMBER OF LINES, this error will be reported
        #
        # Compare if the outputs have the same number of lines
        # and throw an error if it fails
        # if len(outs) != len(self.cell.outputs):
        #     self.diff_number_outputs(outs, self.cell.outputs)
        #     failed = True

        # If the outputs are the same, compare them line by line
        # else:
        # for out, ref in zip(outs, self.cell.outputs):
        if not self.compare_outputs(outs, self.cell.outputs):
            failed = True

        # if reply['status'] == 'error':
        # Traceback is only when an error is raised (?)

        # We usually get an exception because traceback is not defined
        if failed:  # Use this to make the test fail
            """
            The pytest exception will be raised if there are any
            errors in the notebook cells. Now we check that
            the outputs produced from running each cell
            matches the outputs in the existing notebook.
            This code is taken from [REF].
            """
            raise NbCellError(self.cell_num,
                              # Still needs correction. We could
                              # add a description
                              "Error with cell",
                              self.cell.source,
                              # Here we must put the traceback output:
                              '\n'.join(self.comparisons))
Exemple #6
0
    def run_cell(self, cell):
        """Run a notebook cell and update the output of that cell in-place."""
        logging.info('Running cell:\n%s\n', cell.input)
        self.kc.execute(cell.input)
        reply = self.kc.get_shell_msg()
        status = reply['content']['status']
        traceback_text = ''
        if status == 'error':
            traceback_text = 'Cell raised uncaught exception: \n' + \
                '\n'.join(reply['content']['traceback'])
            logging.info(traceback_text)
        else:
            logging.info('Cell returned')

        outs = list()
        while True:
            try:
                msg = self.kc.get_iopub_msg(timeout=1)
                if msg['msg_type'] == 'status':
                    if msg['content']['execution_state'] == 'idle':
                        break
            except Empty:
                # execution state should return to idle
                # before the queue becomes empty,
                # if it doesn't, something bad has happened
                raise

            content = msg['content']
            msg_type = msg['msg_type']

            # IPython 3.0.0-dev writes pyerr/pyout in the notebook format
            # but uses error/execute_result in the message spec. This does the
            # translation needed for tests to pass with IPython 3.0.0-dev
            notebook3_format_conversions = {
                'error': 'pyerr',
                'execute_result': 'pyout'
            }
            msg_type = notebook3_format_conversions.get(msg_type, msg_type)

            out = NotebookNode(output_type=msg_type)

            if 'execution_count' in content:
                cell['prompt_number'] = content['execution_count']
                out.prompt_number = content['execution_count']

            if msg_type in ('status', 'pyin', 'execute_input'):
                continue
            elif msg_type == 'stream':
                out.stream = content['name']
                # in msgspec 5, this is name, text
                # in msgspec 4, this is name, data
                if 'text' in content:
                    out.text = content['text']
                else:
                    out.text = content['data']
            elif msg_type in ('display_data', 'pyout'):
                for mime, data in content['data'].items():
                    try:
                        attr = self.MIME_MAP[mime]
                    except KeyError:
                        raise NotImplementedError(
                            'unhandled mime type: %s' % mime
                        )

                    setattr(out, attr, data)
            elif msg_type == 'pyerr':
                out.ename = content['ename']
                out.evalue = content['evalue']
                out.traceback = content['traceback']
            elif msg_type == 'clear_output':
                outs = list()
                continue
            else:
                raise NotImplementedError(
                    'unhandled iopub message: %s' % msg_type
                )
            outs.append(out)
        cell['outputs'] = outs

        if status == 'error':
            raise NotebookError(traceback_text)
def runtest(cell, iopub):
    """
    Run all the cell tests in one kernel without restarting.
    It is very common for ipython notebooks to run through assuming a
    single kernel.
    """
    # Execute the code from the current cell and get the msg_id
    # of the shell process.
    msg_id = execute_cell_input(kc, cell.source, allow_stdin=False)

    # Time for the reply of the cell execution
    timeout = 2000

    # This list stores the output information for the entire cell
    outs = []

    while True:
        """
        The messages from the cell contain information such
        as input code, outputs generated
        and other messages. We iterate through each message
        until we reach the end of the cell.
        """
        try:
            # Get one message at a time, per code block inside the cell
            msg = get_message(iopub, timeout=1.)

        except Empty:
            break

        # Firstly, get the msg type from the cell to know if
        # the output comes from a code
        # It seems that the type 'stream' is irrelevant
        msg_type = msg['msg_type']
        reply = msg['content']

        # REF:
        # execute_input: To let all frontends know what code is
        # being executed at any given time, these messages contain a
        # re-broadcast of the code portion of an execute_request,
        # along with the execution_count.
        if msg_type == 'status':
            if reply['execution_state'] == 'idle':
                break
            else:
                continue
        elif msg_type == 'execute_input':
            continue
        elif msg_type.startswith('comm'):
            continue
        elif msg_type == 'execute_reply':
            # print msg
            continue
        # If there is no more output, continue with the executions
        # (it will break if it is empty, with the previous statements)
        #
        # REF:
        # This message type is used to clear the output that is
        # visible on the frontend
        # elif msg_type == 'clear_output':
        #     outs = []
        #     continue

        # I added the msg_type 'idle' condition (when the cell stops)
        # so we get a complete cell output
        # REF:
        # When the kernel starts to execute code, it will enter the 'busy'
        # state and when it finishes, it will enter the 'idle' state.
        # The kernel will publish state 'starting' exactly
        # once at process startup.
        # elif (msg_type == 'clear_output'
        #       and msg_type['execution_state'] == 'idle'):
        #     outs = []
        #     continue

        # WE COULD ADD HERE a condition for the 'error' message type
        # Making the test to fail

        """
        Now we get the reply from the piece of code executed
        and analyse the outputs
        """
        reply = msg['content']
        out = NotebookNode(output_type=msg_type)

        # Now check what type of output it is
        if msg_type == 'stream':
            out.stream = reply['name']
            out.text = reply['text']

        elif msg_type in ('display_data', 'execute_result'):
            # REF:
            # data and metadata are identical to a display_data message.
            # the object being displayed is that passed to the display
            #  hook, i.e. the *result* of the execution.
            out['metadata'] = reply['metadata']
            # for mime, data in reply['data'].iteritems():
                # attr = mime.split('/')[-1].lower()
                # attr = attr.replace('+xml', '').replace('plain', 'text')
                # setattr(out, attr, data)
            if msg_type == 'execute_result':
                out.prompt_number = reply['execution_count']
        else:
            print("unhandled iopub msg:", msg_type)

        outs.append(out)

        print '--------------------------- CELL --------------------------'
        print outs
        print '------------------------- ORIGINAL CELL -------------------'
        print cell.outputs
Exemple #8
0
    def runtest(self):
        """
        Run all the cell tests in one kernel without restarting.
        It is very common for ipython notebooks to run through assuming a
        single kernel.
        """
        # Execute the code from the current cell and get the msg_id
        # of the shell process.
        msg_id = self.parent.kernel.execute_cell_input(
            self.cell.source, allow_stdin=False)

        # Time for the reply of the cell execution
        # (maximum time, it can finish before, we could make a timeout
        # exception in the future)
        timeout = 2000

        # This list stores the output information for the entire cell
        outs = []

        # Wait for the execution reply (we can see this in the msg_type)
        # This execution produces a dictionary where a status string can be
        # obtained: 'ok' OR 'error' OR 'abort'
        # We can also get how many cells have been executed
        # until here, with the 'execution_count' entry
        # self.parent.kernel.kc.get_shell_msg(timeout=timeout)

        while True:
            """
            The messages from the cell contain information such
            as input code, outputs generated
            and other messages. We iterate through each message
            until we reach the end of the cell.
            """
            try:
                # Get one message at a time, per code block inside the cell
                msg = self.parent.get_kernel_message(timeout=timeout)

            except Empty:
                # This is not working: ! The code will not be checked
                # if the time is out (when the cell stops to be executed?)
                # raise NbCellError("Timeout of %d seconds exceeded"
                #                      " executing cell: %s" (timeout,
                #                                             self.cell.input))
                # Just break the loop when the output is empty
                break

            """
            Now that we have the output from a piece of code
            inside the cell,
            we want to compare the outputs of the messages
            to a reference output (the ones that are present before
            the notebook was executed)
            """

            # print msg

            # Firstly, get the msg type from the cell to know if
            # the output comes from a code
            # It seems that the type 'stream' is irrelevant
            msg_type = msg['msg_type']
            reply = msg['content']

            # REF:
            # execute_input: To let all frontends know what code is
            # being executed at any given time, these messages contain a
            # re-broadcast of the code portion of an execute_request,
            # along with the execution_count.
            if msg_type == 'status':
                if reply['execution_state'] == 'idle':
                    break
                else:
                    continue
            elif msg_type == 'execute_input':
                continue
            elif msg_type.startswith('comm'):
                continue
            elif msg_type == 'execute_reply':
                # print msg
                continue
            # If there is no more output, continue with the executions
            # (it will break if it is empty, with the previous statements)
            #
            # REF:
            # This message type is used to clear the output that is
            # visible on the frontend
            # elif msg_type == 'clear_output':
            #     outs = []
            #     continue

            # I added the msg_type 'idle' condition (when the cell stops)
            # so we get a complete cell output
            # REF:
            # When the kernel starts to execute code, it will enter the 'busy'
            # state and when it finishes, it will enter the 'idle' state.
            # The kernel will publish state 'starting' exactly
            # once at process startup.
            # elif (msg_type == 'clear_output'
            #       and msg_type['execution_state'] == 'idle'):
            #     outs = []
            #     continue

            # WE COULD ADD HERE a condition for the 'error' message type
            # Making the test to fail

            """
            Now we get the reply from the piece of code executed
            and analyse the outputs
            """
            reply = msg['content']
            out = NotebookNode(output_type=msg_type)

            # print '---------------------------- CELL ----------------------'
            # print msg_type
            # print reply
            # print '---------------------------- CELL ORIGINAL----------------'
            # print self.cell.outputs

            # Now check what type of output it is
            if msg_type == 'stream':
                out.stream = reply['name']
                out.text = reply['text']

            # REF:
            # 'execute_result' is equivalent to a display_data message.
            # The object being displayed is passed to the display
            # hook, i.e. the *result* of the execution.
            # The only difference is that 'execute_result' has an
            # 'execution_count' number which does not seems useful
            # (we will filter it in the sanitize function)
            #
            # When the reply is display_data or execute_count,
            # the dictionary contains
            # a 'data' sub-dictionary with the 'text' AND the 'image/png'
            # picture (in hexadecimal). There is also a 'metadata' entry
            # but currently is not of much use, sometimes there is information
            # as height and width of the image (CHECK the documentation)
            # Thus we iterate through the keys (mimes) 'data' sub-dictionary
            # to obtain the 'text' and 'image/png' information
            #
            # We NO longer replace 'image/png' by 'png' since the last version
            # of the notebook format is more consistent. We also DO NOT
            # replace any .xml string, it's not neccesary

            # elif msg_type in ('display_data', 'execute_result'):
            elif msg_type in ('display_data', 'execute_result'):
                out['metadata'] = reply['metadata']
                for mime, data in six.iteritems(reply['data']):
                # This could be useful for reference or backward compatibility
                #     attr = mime.split('/')[-1].lower()
                #     attr = attr.replace('+xml', '').replace('plain', 'text')
                #     setattr(out, attr, data)

                # Return the relevant entries from data:
                # plain/text, image/png, execution_count, etc
                # We coul use a mime types list for this (MAYBE)
                    setattr(out, mime, data)

                # if msg_type == 'execute_result':
                #     out.prompt_number = reply['execution_count']

            else:
                print("unhandled iopub msg:", msg_type)
                try:
                    # More information in case msg_type =' error'
                    print(reply['ename'])
                    print(reply['evalue'])
                except:
                    continue

            outs.append(out)

        """
        This message is the last message of the cell, which contains no output.
        It only indicates whether the entire cell ran successfully or if there
        was an error.
        """
        # reply = msg['content']

        failed = False

        # THIS COMPARISON IS ONLY WHEN THE OUTPUT DICTIONARIES
        # ARE DIFFERENT, WHICH IS A DIFFERENT ERROR, not
        # from the output in the notebook
        #
        # SINCE WE SANITIZE AND COMPARE, IF THERE ARE DIFFERENT
        # NUMBER OF LINES, this error will be reported
        #
        # Compare if the outputs have the same number of lines
        # and throw an error if it fails
        # if len(outs) != len(self.cell.outputs):
        #     self.diff_number_outputs(outs, self.cell.outputs)
        #     failed = True

        # If the outputs are the same, compare them line by line
        # else:
        # for out, ref in zip(outs, self.cell.outputs):
        if not self.compare_outputs(outs, self.cell.outputs):
            failed = True

        # if reply['status'] == 'error':
        # Traceback is only when an error is raised (?)

        # We usually get an exception because traceback is not defined
        if failed:  # Use this to make the test fail
            """
            The pytest exception will be raised if there are any
            errors in the notebook cells. Now we check that
            the outputs produced from running each cell
            matches the outputs in the existing notebook.
            This code is taken from [REF].
            """
            raise NbCellError(self.cell_num,
                              # Still needs correction. We could
                              # add a description
                              "Error with cell",
                              self.cell.source,
                              # Here we must put the traceback output:
                              '\n'.join(self.comparisons))
    def run(self, cell, timeout = None):
        """
        Run a notebook cell in the IPythonKernel

        Parameters
        ----------
        cell : IPython.notebook.Cell
            the cell to be run
        timeout : int or None (default)
            the time in seconds after which a cell is stopped and assumed to
            have timed out. If set to None the value in `default_timeout`
            is used

        Returns
        -------
        list of outs
            a list of NotebookNodes of the returned types. This is
            similar to the list of outputs generated when a cell is run
        """

        use_timeout = self.default_timeout

        if timeout is not None:
            use_timeout = timeout

        if hasattr(cell, 'input'):
            self.kc.execute(cell.input)
        elif hasattr(cell, 'source'):
            self.kc.execute(cell.source)
        else:
            raise AttributeError('No source/input key')

        self.shell.get_msg(timeout=use_timeout)
        outs = []

        while True:
            try:
                msg = self.iopub.get_msg(timeout=0.5)
            except Empty:
                break
            msg_type = msg['msg_type']
            if msg_type in ('status', 'pyin', 'execute_input'):
                continue
            elif msg_type == 'clear_output':
                outs = []
                continue

            content = msg['content']
            out = NotebookNode(output_type=msg_type)

            if msg_type == 'stream':
                out.name = content['name']
                out.text = content['text']
            elif msg_type in ('display_data', 'pyout', 'execute_result'):
                if hasattr(content, 'execution_count'):
                    out['execution_count'] = content['execution_count']
                else:
                    out['execution_count'] = None
                out['data'] = content['data']
                out['metadata'] = content['metadata']

            elif msg_type == 'error':
                out.ename = content['ename']
                out.evalue = content['evalue']
                out.traceback = content['traceback']
            else:
                print "unhandled iopub msg:", msg_type

            outs.append(out)

        return outs