Exemplo n.º 1
0
    def preprocess(self, nb, resources):

        logging.info('adding ipub defaults to notebook')

        for keys, val in flatten(self.nb_defaults).items():
            dct = nb.metadata
            for key in keys[:-1]:
                if key not in dct:
                    dct[key] = NotebookNode({})
                dct = dct[key]
            if keys[-1] not in dct:
                dct[keys[-1]] = val
            elif self.overwrite:
                dct[keys[-1]] = val

        for cell in nb.cells:
            for keys, val in flatten(self.cell_defaults).items():
                dct = cell.metadata
                for key in keys[:-1]:
                    if key not in dct:
                        dct[key] = NotebookNode({})
                    dct = dct[key]
                if keys[-1] not in dct:
                    dct[keys[-1]] = val
                elif self.overwrite:
                    dct[keys[-1]] = val

        return nb, resources
Exemplo n.º 2
0
    def preprocess_cell(self,
                        cell: NotebookNode,
                        resources: ResourcesDict,
                        cell_index: int
                        ) -> Tuple[NotebookNode, ResourcesDict]:
        # replace solution regions with the relevant stubs
        language = resources["language"]
        replaced_solution = self._replace_solution_region(cell, language)

        # determine whether the cell is a solution/grade cell
        is_solution = utils.is_solution(cell)

        # check that it is marked as a solution cell if we replaced a solution
        # region -- if it's not, then this is a problem, because the cell needs
        # to be given an id
        if not is_solution and replaced_solution:
            if self.enforce_metadata:
                raise RuntimeError(
                    "Solution region detected in a non-solution cell; please make sure "
                    "all solution regions are within solution cells."
                )

        # replace solution cells with the code/text stub -- but not if
        # we already replaced a solution region, because that means
        # there are parts of the cells that should be preserved
        if is_solution and not replaced_solution:
            if cell.cell_type == 'code':
                cell.source = self.code_stub[language]
            else:
                cell.source = self.text_stub

        return cell, resources
Exemplo n.º 3
0
 def postprocess_output(self, outputs):
     """
     Postprocesses output and maps mime types to ones accepted by R.
     """
     res = []
     for output in outputs:
         msg_type = output.output_type
         content = output
         out = NotebookNode(output_type=msg_type)
         if msg_type in ('display_data', 'execute_result'):
             for mime, data in content['data'].items():
                 try:
                     attr = self.MIME_MAP[mime]
                     if attr == 'text':
                         tmpval = RClansiconv(data)
                     else:
                         tmpval = data
                     setattr(out, attr, tmpval)
                 except KeyError:
                     raise NotImplementedError('unhandled mime type: %s' %
                                               mime)
         elif msg_type == 'stream':
             setattr(out, 'text', RClansiconv(content['text']))
         elif msg_type == 'error':
             setattr(out, 'html',
                     RClansiconv('\n'.join(content['traceback']) + '\n'))
         else:
             if _debugging: logging.info('Unsupported: ' + msg_type)
             raise NotImplementedError('unhandled result: %s' % msg_type)
         if _debugging:
             logging.info(
                 'Sending: msg_type: [{}]; HTML: [{}]; TEXT: [{}]'.format(
                     msg_type, out.get('html', ''), out.get('text', '')))
         res.append(out)
     return res  # upstream process will handle it [e.g. send as an oob message]
Exemplo n.º 4
0
 def update_cell_type(self, cell: NotebookNode, cell_type: str) -> None:
     if cell.cell_type == cell_type:
         return
     elif cell_type == 'code':
         cell.cell_type = 'code'
         cell.outputs = []
         cell.execution_count = None
         validate(cell, 'code_cell')
     elif cell_type == 'markdown':
         cell.cell_type = 'markdown'
         if 'outputs' in cell:
             del cell['outputs']
         if 'execution_count' in cell:
             del cell['execution_count']
         validate(cell, 'markdown_cell')
Exemplo n.º 5
0
 def postprocess_output(self, outputs):
     """
     Postprocesses output and maps mime types to ones accepted by R.
     """
     res = []
     for output in outputs:
       msg_type = output.output_type
       content = output
       out = NotebookNode(output_type = msg_type)
       if msg_type in ('display_data', 'execute_result'):
         for mime, data in content['data'].items():
             try:
                 attr = self.MIME_MAP[mime]
                 if attr == 'text':
                   tmpval =  RClansiconv(data) 
                 else:
                   tmpval = data
                 setattr(out, attr, tmpval)
             except KeyError:
                 raise NotImplementedError('unhandled mime type: %s' % mime)
       elif msg_type == 'stream':
           setattr(out, 'text', RClansiconv(content['text']))
       elif msg_type == 'error':
           setattr(out, 'html', RClansiconv('\n'.join(content['traceback']) + '\n'))
       else:
           if _debugging: logging.info('Unsupported: ' + msg_type)
           raise NotImplementedError('unhandled result: %s' % msg_type)
       if _debugging: logging.info('Sending: msg_type: [{}]; HTML: [{}]; TEXT: [{}]'.format(msg_type, out.get('html', ''), out.get('text', '') ))
       res.append(out)
     return res # upstream process will handle it [e.g. send as an oob message]
Exemplo n.º 6
0
    def preprocess(
            self, nb: NotebookNode,
            resources: ResourcesDict) -> Tuple[NotebookNode, ResourcesDict]:
        """Concatenates the cells from the header and footer notebooks to the
        given cells.

        """
        new_cells = []

        # header
        if self.header:
            with io.open(self.header, encoding='utf-8') as fh:
                header_nb = read_nb(fh, as_version=current_nbformat)
            new_cells.extend(header_nb.cells)

        # body
        new_cells.extend(nb.cells)

        # footer
        if self.footer:
            with io.open(self.footer, encoding='utf-8') as fh:
                footer_nb = read_nb(fh, as_version=current_nbformat)
            new_cells.extend(footer_nb.cells)

        nb.cells = new_cells
        super(IncludeHeaderFooter, self).preprocess(nb, resources)

        return nb, resources
Exemplo n.º 7
0
    def preprocess(
            self, nb: NotebookNode,
            resources: ResourcesDict) -> Tuple[NotebookNode, ResourcesDict]:
        # keep track of grade ids encountered so far
        self.grade_ids = set([])

        # reverse cell order
        nb.cells = nb.cells[::-1]

        # process each cell in reverse order
        nb, resources = super(DeduplicateIds, self).preprocess(nb, resources)

        # unreverse cell order
        nb.cells = nb.cells[::-1]

        return nb, resources
Exemplo n.º 8
0
 def new_cell(idents, filename, lineno, source=None):
     cell_types = ['markdown', 'code']
     slide_types = ['slide', 'subslide', 'fragment']
     split_types = ['split']
     cell = {'metadata': {},
             'cell_type': 'markdown'}
     if source is not None:
         if source and source[-1] == "\n":
             source = source[:-1]
         cell['source'] = source
     for ident in idents:
         if ident in cell_types:
             cell['cell_type'] = ident
             if ident == 'code':
                 cell['outputs'] = []
                 cell['execution_count'] = None
         elif ident in slide_types:
             if 'slideshow' not in cell['metadata']:
                 cell['metadata']['slideshow'] = {}
             cell['metadata']['slideshow']['slide_type'] = ident
         elif ident in split_types:
             cell['metadata']['cell_style'] = ident
         else:
             print("{}:{} - ignored directive `{}' in separator"
                   .format(filename, lineno, ident))
     return NotebookNode(cell)
Exemplo n.º 9
0
    def embed_html(self, cell, path):
        """ a new cell, based on embedded html file
        """
        logging.info('embedding html in notebook from: {}'.format(path))

        height = int(cell.metadata.ipub.embed_html.get('height', 0.5) * 100)
        width = int(cell.metadata.ipub.embed_html.get('width', 0.5) * 100)
        embed_code = """
        <iframe style="display:block; margin: 0 auto; height:{height}vh; width:{width}vw; overflow:auto; resize:both" {src}="{path}" frameborder="0" allowfullscreen></iframe>
        """.format(src=self.src_name, path=path, height=height, width=width)

        # add to the exising output or create a new one
        if cell.outputs:
            cell.outputs[0]["data"]["text/html"] = embed_code
        else:
            cell.outputs.append(
                NotebookNode({
                    "data": {
                        "text/html": embed_code
                    },
                    "execution_count": 0,
                    "metadata": {},
                    "output_type": "execute_result"
                }))

        return cell
Exemplo n.º 10
0
    def preprocess_cell(self, cell, resources, cell_index, store_history=True):
        """
            Need to override preprocess_cell to check reply for errors
            """
        # Copied from nbconvert ExecutePreprocessor
        if cell.cell_type != 'code' or not cell.source.strip():
            return cell, resources

        reply, outputs = self.run_cell(cell, cell_index, store_history)
        # Backwards compatibility for processes that wrap run_cell
        cell.outputs = outputs

        cell_allows_errors = (self.allow_errors
                              or "raises-exception" in cell.metadata.get(
                                  "tags", []))

        if self.force_raise_errors or not cell_allows_errors:
            if (reply is not None) and reply['content']['status'] == 'error':
                raise CellExecutionError.from_cell_and_msg(
                    cell, reply['content'])

        # Ensure errors are recorded to prevent false positives when autograding
        if (reply is None) or reply['content']['status'] == 'error':
            error_recorded = False
            for output in cell.outputs:
                if output.output_type == 'error':
                    error_recorded = True
            if not error_recorded:
                error_output = NotebookNode(output_type='error')
                if reply is None:
                    # Occurs when
                    # IPython.core.interactiveshell.InteractiveShell.showtraceback
                    # = None
                    error_output.ename = "CellTimeoutError"
                    error_output.evalue = ""
                    error_output.traceback = ["ERROR: No reply from kernel"]
                else:
                    # Occurs when
                    # IPython.core.interactiveshell.InteractiveShell.showtraceback
                    # = lambda *args, **kwargs : None
                    error_output.ename = reply['content']['ename']
                    error_output.evalue = reply['content']['evalue']
                    error_output.traceback = reply['content']['traceback']
                    if error_output.traceback == []:
                        error_output.traceback = [
                            "ERROR: An error occurred while"
                            " showtraceback was disabled"
                        ]
                cell.outputs.append(error_output)

        return cell, resources
Exemplo n.º 11
0
    def _replace_solution_region(self, cell: NotebookNode,
                                 language: str) -> bool:
        """Find a region in the cell that is delimeted by
        `self.begin_solution_delimeter` and `self.end_solution_delimeter` (e.g.
        ### BEGIN SOLUTION and ### END SOLUTION). Replace that region either
        with the code stub or text stub, depending the cell type.

        This modifies the cell in place, and then returns True if a
        solution region was replaced, and False otherwise.

        """
        # pull out the cell input/source
        lines = cell.source.split("\n")
        if cell.cell_type == "code":
            stub_lines = self.code_stub[language].split("\n")
        else:
            stub_lines = self.text_stub.split("\n")

        new_lines = []
        in_solution = False
        replaced_solution = False

        for line in lines:
            # begin the solution area
            if self.begin_solution_delimeter in line:

                # check to make sure this isn't a nested BEGIN
                # SOLUTION region
                if in_solution:
                    raise RuntimeError(
                        "encountered nested begin solution statements")

                in_solution = True
                replaced_solution = True

                # replace it with the stub, indented as necessary
                indent = re.match(r"\s*", line).group(0)
                for stub_line in stub_lines:
                    new_lines.append(indent + stub_line)

            # end the solution area
            elif self.end_solution_delimeter in line:
                in_solution = False

            # add lines as long as it's not in the solution area
            elif not in_solution:
                new_lines.append(line)

        # we finished going through all the lines, but didn't find a
        # matching END SOLUTION statment
        if in_solution:
            raise RuntimeError("no end solution statement found")

        # replace the cell source
        cell.source = "\n".join(new_lines)

        return replaced_solution
Exemplo n.º 12
0
    def preprocess(self, nb, resources):
                
        logging.info('extracting caption cells') 
        
        # extract captions
        final_cells = []
        captions = {}
        for cell in nb.cells:
            if hasattr(cell.metadata, 'ipub'):
                
                if hasattr(cell.metadata.ipub.get('equation',False),'get'):
                    if hasattr(cell.metadata.ipub.equation.get('environment',False),'startswith'):
                        if cell.metadata.ipub.equation.environment.startswith('breqn'):
                            if "ipub" not in nb.metadata:
                                nb.metadata["ipub"] = NotebookNode({'enable_breqn':True})
                            else:
                                nb.metadata.ipub['enable_breqn'] = True
                
                if hasattr(cell.metadata.ipub, 'caption'):
                                        
                    if cell.cell_type == 'markdown':
                        capt = cell.source.split(r'\n')[0]
                        captions[cell.metadata.ipub.caption] = capt
                        continue
                    elif cell.cell_type == 'code':
                        if not cell.outputs:
                            pass
                        elif "text/latex" in cell.outputs[0].get('data',{}):
                            capt = cell.outputs[0].data["text/latex"].split(r'\n')[0]
                            captions[cell.metadata.ipub.caption] = capt
                            continue
                        elif "text/plain" in cell.outputs[0].get('data',{}):
                            capt = cell.outputs[0].data["text/plain"].split(r'\n')[0]
                            captions[cell.metadata.ipub.caption] = capt
                            continue

            final_cells.append(cell)
        nb.cells = final_cells  
        
        # replace captions
        for cell in nb.cells:
            if hasattr(cell.metadata, 'ipub'):
                for key in cell.metadata.ipub:
                    if hasattr(cell.metadata.ipub[key], 'label'):
                        if cell.metadata.ipub[key]['label'] in captions:
                            logging.debug('replacing caption for: {}'.format(cell.metadata.ipub[key]['label']))
                            cell.metadata.ipub[key]['caption'] = captions[cell.metadata.ipub[key]['label']]
                            
                    # add float type/number prefix to caption, if required
                    if self.add_prefix:
                        if hasattr(cell.metadata.ipub[key], 'caption'):
                            if hasattr(cell.metadata.ipub[key], 'caption_prefix'):                    
                                newcaption = cell.metadata.ipub[key].caption_prefix + cell.metadata.ipub[key].caption
                                cell.metadata.ipub[key].caption = newcaption
                    
        
        return nb, resources
Exemplo n.º 13
0
 def mkdcell(self, source, metadata, slidetype):
     meta = copy.deepcopy(metadata)
     meta.ipyslides = slidetype
     self.append(
         NotebookNode({
             "cell_type": "markdown",
             "source": '\n'.join(source),
             "metadata": meta
         }))
Exemplo n.º 14
0
    def preprocess_cell(self,
                        cell: NotebookNode,
                        resources: ResourcesDict,
                        cell_index: int
                        ) -> Tuple[NotebookNode, ResourcesDict]:
        grade_id = cell.metadata.get('nbgrader', {}).get('grade_id', None)
        if grade_id is None:
            return cell, resources

        try:
            source_cell = self.gradebook.find_source_cell(
                grade_id,
                self.notebook_id,
                self.assignment_id)
        except MissingEntry:
            self.log.warning("Cell '{}' does not exist in the database".format(grade_id))
            del cell.metadata.nbgrader['grade_id']
            return cell, resources

        # check that the cell type hasn't changed
        if cell.cell_type != source_cell.cell_type:
            self.report_change(grade_id, "cell_type", source_cell.cell_type, cell.cell_type)
            self.update_cell_type(cell, source_cell.cell_type)

        # check that the locked status hasn't changed
        if utils.is_locked(cell) != source_cell.locked:
            self.report_change(grade_id, "locked", source_cell.locked, utils.is_locked(cell))
            cell.metadata.nbgrader["locked"] = source_cell.locked

        # if it's a grade cell, check that the max score hasn't changed
        if utils.is_grade(cell):
            grade_cell = self.gradebook.find_graded_cell(
                grade_id,
                self.notebook_id,
                self.assignment_id)
            old_points = float(grade_cell.max_score)
            new_points = float(cell.metadata.nbgrader["points"])

            if old_points != new_points:
                self.report_change(grade_id, "points", old_points, new_points)
                cell.metadata.nbgrader["points"] = old_points

        # always update the checksum, just in case
        cell.metadata.nbgrader["checksum"] = source_cell.checksum

        # if it's locked, check that the checksum hasn't changed
        if source_cell.locked:
            old_checksum = source_cell.checksum
            new_checksum = utils.compute_checksum(cell)
            if old_checksum != new_checksum:
                self.report_change(grade_id, "checksum", old_checksum, new_checksum)
                cell.source = source_cell.source
                # double check the the checksum is correct now
                if utils.compute_checksum(cell) != source_cell.checksum:
                    raise RuntimeError("Inconsistent checksums for cell {}".format(source_cell.name))

        return cell, resources
Exemplo n.º 15
0
    def preprocess_cell(self, cell, resources, cell_index):
        """Also extracts attachments"""
        from nbformat.notebooknode import NotebookNode

        attach_names = []

        # Just move the attachment into an output

        for k, attach in cell.get('attachments', {}).items():
            for mime_type in self.extract_output_types:
                if mime_type in attach:

                    if 'outputs' not in cell:
                        cell['outputs'] = []

                    o = NotebookNode({
                        'data': NotebookNode({mime_type: attach[mime_type]}),
                        'metadata': NotebookNode({
                            'filenames': {mime_type: k}  # Will get re-written
                        }),
                        'output_type': 'display_data'
                    })

                    cell['outputs'].append(o)

                    attach_names.append((mime_type, k))

        nb, resources = super().preprocess_cell(cell, resources, cell_index)

        output_names = list(resources.get('outputs', {}).keys())

        if attach_names:
            # We're going to assume that attachments are only on Markdown cells, and Markdown cells
            # can't generate output, so all of the outputs were added.

            # reverse + zip matches the last len(attach_names) elements from output_names

            for output_name, (mimetype, an) in zip(reversed(output_names), reversed(attach_names)):
                # We'll post process to set the final output directory
                cell.source = re.sub(r'\(attachment:{}\)'.format(an),
                                     '(__IMGDIR__/{})'.format(output_name), cell.source)

        return nb, resources
Exemplo n.º 16
0
    def preprocess(self, nb, resources):

        if not self.split:
            return nb, resources

        logging.info("splitting outputs into separate cells")

        final_cells = []
        for cell in nb.cells:

            if not cell.cell_type == "code":
                final_cells.append(cell)
                continue
            outputs = cell.pop("outputs")
            cell.outputs = []
            final_cells.append(cell)
            for output in outputs:
                meta = copy.deepcopy(cell.metadata)
                # don't need the code to output
                meta.get("ipub", NotebookNode({})).code = False
                # don't create a new slide for each output,
                # unless specified in output level metadata
                if "slide" in meta.get("ipub", NotebookNode({})):
                    if meta.ipub.slide == "new":
                        meta.ipub.slide = True
                    else:
                        meta.ipub.slide = meta.ipub.slide
                meta = merge(meta, output.get("metadata", {}))
                new = NotebookNode(
                    {
                        "cell_type": "code",
                        "source": "",
                        "execution_count": None,
                        "metadata": meta,
                        "outputs": [output],
                    }
                )
                final_cells.append(new)

        nb.cells = final_cells

        return nb, resources
Exemplo n.º 17
0
    def preprocess(self, nb, resources):

        logging.info("adding ipub defaults to notebook")

        for keys, val in flatten(self.nb_defaults).items():
            dct = nb.metadata
            for key in keys[:-1]:
                if key not in dct:
                    dct[key] = NotebookNode({})
                dct = dct[key]
            if keys[-1] not in dct:
                dct[keys[-1]] = val
            elif self.overwrite:
                dct[keys[-1]] = val

        for cell in nb.cells:

            for keys, val in flatten(self.cell_defaults).items():
                dct = cell.metadata
                leaf_not_dict = False
                for key in keys[:-1]:
                    if key not in dct:
                        dct[key] = NotebookNode({})
                    elif dct[key] is False and self.overwrite:
                        dct[key] = NotebookNode({})
                    elif dct[key] is True:
                        dct[key] = NotebookNode({})
                    elif not hasattr(dct[key], "items"):
                        leaf_not_dict = True
                        break
                    dct = dct[key]

                if leaf_not_dict:
                    pass
                elif keys[-1] not in dct:
                    dct[keys[-1]] = val
                elif self.overwrite:
                    dct[keys[-1]] = val

        return nb, resources
Exemplo n.º 18
0
 def edit_notebook(self, nb):
     """
     Inject the code needed to setup and shutdown spark and sc magic variables.
     """
     from nbformat.notebooknode import NotebookNode
     from textwrap import dedent
     preamble_node = NotebookNode(cell_type="code",
                                  source=dedent("""
         from pyspark.sql import SparkSession
         spark = SparkSession.builder.appName("NotebookTestSuite").master("local[*]").getOrCreate()
         globals()["spark"] = spark
         globals()["sc"] = spark.sparkContext
         """))
     epilogue_node = NotebookNode(cell_type="code",
                                  source=dedent("""
         try:
             spark.stop()
         except:
             pass
         """))
     nb.cells.insert(0, preamble_node)
     nb.cells.append(epilogue_node)
     return nb
Exemplo n.º 19
0
    def ensure_title(self, licence, authors, logo_path):
        """
        make sure the first cell is a author + licence cell
        """

        # the title cell has 3 parts that are equidistant
        # xxx it looks like this <style> tag somehow gets
        # trimmed away when rendered inside of edx
        # so I had to add it in nbhosting's custom.css as well

        def title_cell(licence, authors, logo_path):
            cell = ''
            cell += f'<div class="licence">\n'
            cell += f'<span>{licence}</span>\n'
            if authors:
                cell += f'<span>{" &amp; ".join(authors)}</span>\n'
            if logo_path:
                cell += f'<span><img src="{logo_path}" /></span>\n'
            cell += f'</div>'
            return cell

        # a bit rustic but good enough
        def is_title_cell(cell):
            # for legacy - notebooks tweaked with older versions
            # of this tool, we want to consider first cells that have
            # Licence as being our title cell as well
            return cell['cell_type'] == 'markdown' \
                and (cell['source'].find("title-slide") >= 0
                     or cell['source'].lower().find("licence") >= 0)

        # when opened interactively and then saved again, this is how the result looks like
        expected_title_cell = title_cell(licence, authors, logo_path)
        title_lines = [line + "\n" for line in expected_title_cell.split("\n")]
        # remove last \n
        title_lines[-1] = title_lines[-1][:-1]

        first_cell = self.cells()[0]
        # cell.source is a list of strings
        if is_title_cell(first_cell):
            # licence cell already here, just overwrite contents to latest version
            first_cell['source'] = title_lines
        else:
            self.cells().insert(
                0,
                NotebookNode({
                    "cell_type": "markdown",
                    "metadata": {},
                    "source": title_lines,
                }))
Exemplo n.º 20
0
    def upgrade_cell_metadata(self, cell: NotebookNode) -> NotebookNode:
        if 'nbgrader' not in cell.metadata:
            return cell

        if 'schema_version' not in cell.metadata['nbgrader']:
            cell.metadata['nbgrader']['schema_version'] = 0

        if cell.metadata['nbgrader']['schema_version'] == 0:
            cell = self._upgrade_v0_to_v1(cell)

        if 'nbgrader' not in cell.metadata:
            return cell

        self._remove_extra_keys(cell)
        return cell
Exemplo n.º 21
0
 def preprocess_cell(self,
                     cell: NotebookNode,
                     resources: ResourcesDict,
                     cell_index: int
                     ) -> Tuple[NotebookNode, ResourcesDict]:
     if (self.lock_solution_cells or self.lock_grade_cells) and utils.is_solution(cell) and utils.is_grade(cell):
         cell.metadata['deletable'] = False
     elif self.lock_solution_cells and utils.is_solution(cell):
         cell.metadata['deletable'] = False
     elif self.lock_grade_cells and utils.is_grade(cell):
         cell.metadata['deletable'] = False
         cell.metadata['editable'] = False
     elif self.lock_readonly_cells and utils.is_locked(cell):
         cell.metadata['deletable'] = False
         cell.metadata['editable'] = False
     elif self.lock_all_cells:
         cell.metadata['deletable'] = False
         cell.metadata['editable'] = False
     return cell, resources
Exemplo n.º 22
0
    def _remove_hidden_test_region(self, cell: NotebookNode) -> bool:
        """Find a region in the cell that is delimeted by
        `self.begin_test_delimeter` and `self.end_test_delimeter` (e.g.  ###
        BEGIN HIDDEN TESTS and ### END HIDDEN TESTS). Remove that region
        depending the cell type.

        This modifies the cell in place, and then returns True if a
        hidden test region was removed, and False otherwise.
        """
        # pull out the cell input/source
        lines = cell.source.split("\n")

        new_lines = []
        in_test = False
        removed_test = False

        for line in lines:
            # begin the test area
            if self.begin_test_delimeter in line:

                # check to make sure this isn't a nested BEGIN HIDDEN TESTS
                # region
                if in_test:
                    raise RuntimeError(
                        "Encountered nested begin hidden tests statements")
                in_test = True
                removed_test = True

            # end the solution area
            elif self.end_test_delimeter in line:
                in_test = False

            # add lines as long as it's not in the hidden tests region
            elif not in_test:
                new_lines.append(line)

        # we finished going through all the lines, but didn't find a
        # matching END HIDDEN TESTS statment
        if in_test:
            raise RuntimeError("No end hidden tests statement found")

        # replace the cell source
        cell.source = "\n".join(new_lines)

        return removed_test
Exemplo n.º 23
0
    def preprocess(
            self, nb: NotebookNode,
            resources: ResourcesDict) -> Tuple[NotebookNode, ResourcesDict]:
        # pull information from the resources
        notebook_id = resources['nbgrader']['notebook']
        assignment_id = resources['nbgrader']['assignment']
        db_url = resources['nbgrader']['db_url']

        with Gradebook(db_url) as gb:
            kernelspec = json.loads(
                gb.find_notebook(notebook_id, assignment_id).kernelspec)
            self.log.debug("Source notebook kernelspec: {}".format(kernelspec))
            self.log.debug("Submitted notebook kernelspec: {}"
                           "".format(nb.metadata.get('kernelspec', None)))
            if kernelspec:
                self.log.debug("Overwriting submitted notebook kernelspec: {}"
                               "".format(kernelspec))
                nb.metadata['kernelspec'] = kernelspec
        return nb, resources
Exemplo n.º 24
0
    def run_cmd(self, cmd, kernel_name=None):
        """
        Runs python command string.
        """

        if _debugging:
            logging.info('Running command: ' + cmd + ' using kernel: ' +
                         kernel_name)
        notebook = nbformat.v4.new_notebook()
        my_cell = nbformat.v4.new_code_cell(source=cmd)
        notebook.cells = [my_cell]
        if kernel_name:
            notebook.metadata['kernelspec'] = {'name': kernel_name}

        try:
            self.executePreprocessor.preprocess(notebook,
                                                {'metadata': {
                                                    'path': '.'
                                                }})
            if _debugging:
                logging.info('Result notebook: ' +
                             nbformat.v4.writes_json(notebook))
            if len(notebook.cells) < 1 or len(notebook.cells[0].outputs) < 1:
                return None
            return self.postprocess_output(notebook.cells[0].outputs)
        except:
            exc_type, exc_obj, exc_tb = sys.exc_info()

            msg = None
            if _debugging:
                msg = '\n'.join(
                    traceback.format_exception_only(exc_type, exc_obj) +
                    traceback.format_tb(exc_tb))
            else:
                msg = '\n'.join(
                    traceback.format_exception_only(exc_type, exc_obj))

            out = NotebookNode(output_type='error',
                               html=RClansiconv(msg + '\n'))
            return [out]
Exemplo n.º 25
0
    def _limit_stream_output(self, cell: NotebookNode) -> NotebookNode:
        if self.max_lines == -1 or cell.cell_type != "code":
            return cell

        length = 0
        new_outputs = []
        for output in cell.outputs:
            if output.output_type == 'stream':
                if length == self.max_lines:
                    continue

                text = output.text.split("\n")
                if (len(text) + length) > self.max_lines:
                    text = text[:(self.max_lines - length - 1)]
                    text.append("... Output truncated ...")

                length += len(text)
                output.text = "\n".join(text)

            new_outputs.append(output)

        cell.outputs = new_outputs
        return cell
Exemplo n.º 26
0
    def on_cell_executed(self, **kwargs):

        cell = kwargs['cell']
        cell_index = kwargs['cell_index']
        reply = kwargs['execute_reply']
        if reply['content']['status'] == 'error':
            error_recorded = False
            for output in cell.outputs:
                if output.output_type == 'error':
                    error_recorded = True
            if not error_recorded:
                # Occurs when
                # IPython.core.interactiveshell.InteractiveShell.showtraceback
                # = lambda *args, **kwargs : None
                error_output = NotebookNode(output_type='error')
                error_output.ename = reply['content']['ename']
                error_output.evalue = reply['content']['evalue']
                error_output.traceback = reply['content']['traceback']
                if error_output.traceback == []:
                    error_output.traceback = ["ERROR: An error occurred while"
                                                " showtraceback was disabled"]
                cell.outputs.append(error_output)
Exemplo n.º 27
0
    def preprocess(self, nb, resources):

        logger.info("extracting caption cells")

        # extract captions
        final_cells = []
        captions = {}
        for cell in nb.cells:
            if hasattr(cell.metadata, "ipub"):

                if hasattr(cell.metadata.ipub.get("equation", False), "get"):
                    if hasattr(
                            cell.metadata.ipub.equation.get(
                                "environment", False),
                            "startswith",
                    ):
                        if cell.metadata.ipub.equation.environment.startswith(
                                "breqn"):  # noqa: E501
                            if "ipub" not in nb.metadata:
                                nb.metadata["ipub"] = NotebookNode(
                                    {"enable_breqn": True})
                            else:
                                nb.metadata.ipub["enable_breqn"] = True

                if hasattr(cell.metadata.ipub, "caption"):

                    if cell.cell_type == "markdown":
                        capt = cell.source.split(r"\n")[0]
                        captions[cell.metadata.ipub.caption] = capt
                        continue
                    elif cell.cell_type == "code":
                        if not cell.outputs:
                            pass
                        elif "text/latex" in cell.outputs[0].get("data", {}):
                            capt = cell.outputs[0].data["text/latex"].split(
                                r"\n")[0]
                            captions[cell.metadata.ipub.caption] = capt
                            continue
                        elif "text/plain" in cell.outputs[0].get("data", {}):
                            capt = cell.outputs[0].data["text/plain"].split(
                                r"\n")[0]
                            captions[cell.metadata.ipub.caption] = capt
                            continue

            final_cells.append(cell)
        nb.cells = final_cells

        # replace captions
        for cell in nb.cells:
            if hasattr(cell.metadata, "ipub"):
                for key in cell.metadata.ipub:
                    if hasattr(cell.metadata.ipub[key], "label"):
                        if cell.metadata.ipub[key]["label"] in captions:
                            logger.debug("replacing caption for: {}".format(
                                cell.metadata.ipub[key]["label"]))
                            cell.metadata.ipub[key]["caption"] = captions[
                                cell.metadata.ipub[key]["label"]]  # noqa: E501

                    # add float type/number prefix to caption, if required
                    if self.add_prefix:
                        if hasattr(cell.metadata.ipub[key], "caption"):
                            if hasattr(cell.metadata.ipub[key],
                                       "caption_prefix"):
                                newcaption = (
                                    cell.metadata.ipub[key].caption_prefix +
                                    cell.metadata.ipub[key].caption)
                                cell.metadata.ipub[key].caption = newcaption

        return nb, resources
Exemplo n.º 28
0
    def preprocess(self, nb, resources):

        logging.info(
            'creating slides based on markdown and existing slide tags')
        latexdoc_tags = [
            'code', 'error', 'table', 'equation', 'figure', 'text'
        ]
        # break up titles
        cells_in_slide = 0
        header_levels = []
        final_cells = FinalCells(self.header_slide)
        for i, cell in enumerate(nb.cells):

            # Make sure every cell has an ipub meta tag
            cell.metadata.ipub = cell.metadata.get('ipub', NotebookNode())

            if cell.metadata.ipub.get('ignore', False):
                cell.metadata.ipyslides = 'skip'
                final_cells.append(cell)
                continue

            if cell.metadata.ipub.get('slide', False) == 'notes':
                cell.metadata.ipyslides = 'notes'
                final_cells.append(cell)
                continue

            if not cell.cell_type == "markdown":
                # TODO this doesn't test if the data is actually available to be output
                if not any([
                        cell.metadata.ipub.get(typ, False)
                        for typ in latexdoc_tags
                ]):
                    cell.metadata.ipyslides = 'skip'
                    final_cells.append(cell)
                    continue

                if cells_in_slide > self.max_cells and self.max_cells:
                    cell.metadata.ipyslides = 'verticalbreak_after'
                    cells_in_slide = 1
                elif cell.metadata.ipub.get('slide', False) == 'new':
                    cell.metadata.ipyslides = 'verticalbreak_after'
                    cells_in_slide = 1
                else:
                    cell.metadata.ipyslides = 'normal'
                    cells_in_slide += 1
                final_cells.append(cell)
                continue

            nonheader_lines = []
            for line in cell.source.split('\n'):

                if is_header(line, 0) and self.autonumbering:
                    line, header_levels = number_title(line, header_levels[:])

                if is_header(line, self.column_level):
                    if nonheader_lines and cell.metadata.ipub.get(
                            'slide', False):
                        if (cells_in_slide > self.max_cells and self.max_cells
                            ) or cell.metadata.ipub.slide == 'new':
                            final_cells.mkdcell(nonheader_lines, cell.metadata,
                                                'verticalbreak_after')
                            cells_in_slide = 1
                        else:
                            cells_in_slide += 1
                            final_cells.mkdcell(nonheader_lines, cell.metadata,
                                                'normal')
                        current_lines = []

                    if self.header_slide:
                        final_cells.mkdcell(
                            [line], cell.metadata,
                            'horizontalbreak_after_plusvertical')
                    else:
                        final_cells.mkdcell([line], cell.metadata,
                                            'horizontalbreak_after')
                    cells_in_slide = 1

                elif is_header(line, self.row_level):
                    if nonheader_lines and cell.metadata.ipub.get(
                            'slide', False):
                        if (cells_in_slide > self.max_cells and self.max_cells
                            ) or cell.metadata.ipub.slide == 'new':
                            final_cells.mkdcell(nonheader_lines, cell.metadata,
                                                'verticalbreak_after')
                            cells_in_slide = 1
                        else:
                            cells_in_slide += 1
                            final_cells.mkdcell(nonheader_lines, cell.metadata,
                                                'normal')
                        current_lines = []

                    final_cells.mkdcell([line], cell.metadata,
                                        'verticalbreak_after')
                    cells_in_slide = 1
                else:
                    nonheader_lines.append(line)

            if nonheader_lines and cell.metadata.ipub.get('slide', False):
                if (cells_in_slide > self.max_cells and
                        self.max_cells) or cell.metadata.ipub.slide == 'new':
                    final_cells.mkdcell(nonheader_lines, cell.metadata,
                                        'verticalbreak_after')
                    cells_in_slide = 1
                else:
                    cells_in_slide += 1
                    final_cells.mkdcell(nonheader_lines, cell.metadata,
                                        'normal')

        if not final_cells.finalize():
            logging.warning('no cells available for slideshow')
        nb.cells = final_cells.cells

        return nb, resources
Exemplo n.º 29
0
    def preprocess(self, nb, resources):

        logging.info(
            "creating slides based on markdown and existing slide tags")
        latexdoc_tags = [
            "code", "error", "table", "equation", "figure", "text"
        ]
        # break up titles
        cells_in_slide = 0
        final_cells = FinalCells(self.header_slide)

        header_levels = []
        try:
            base_numbering = nb.metadata.toc.base_numbering
            header_levels = list(
                map(lambda x: int(x), base_numbering.split(".")))
            header_levels[0] -= 1
            logging.debug("base_numbering = " + base_numbering)
            logging.debug("header_levels = " + str(header_levels))
        except ValueError:
            logging.warning("Invalid toc.base_numbering in notebook metadata")
        except AttributeError:
            logging.debug(
                "No toc.base_numbering in notebook metadata; starting at 1")

        for i, cell in enumerate(nb.cells):

            # Make sure every cell has an ipub meta tag
            cell.metadata.ipub = cell.metadata.get("ipub", NotebookNode())

            if cell.metadata.ipub.get("ignore", False):
                cell.metadata.ipyslides = "skip"
                final_cells.append(cell)
                continue

            if cell.metadata.ipub.get("slide", False) == "notes":
                cell.metadata.ipyslides = "notes"
                final_cells.append(cell)
                continue

            if not cell.cell_type == "markdown":
                # TODO this doesn't test if the data is actually available
                # to be output
                if not any([
                        cell.metadata.ipub.get(typ, False)
                        for typ in latexdoc_tags
                ]):
                    cell.metadata.ipyslides = "skip"
                    final_cells.append(cell)
                    continue

                if cells_in_slide > self.max_cells and self.max_cells:
                    cell.metadata.ipyslides = "verticalbreak_after"
                    cells_in_slide = 1
                elif cell.metadata.ipub.get("slide", False) == "new":
                    cell.metadata.ipyslides = "verticalbreak_after"
                    cells_in_slide = 1
                else:
                    cell.metadata.ipyslides = "normal"
                    cells_in_slide += 1
                final_cells.append(cell)
                continue

            nonheader_lines = []
            for line in cell.source.split("\n"):

                if is_header(line, 0) and self.autonumbering:
                    line, header_levels = number_title(line, header_levels[:])

                if is_header(line, self.column_level):
                    if nonheader_lines and cell.metadata.ipub.get(
                            "slide", False):
                        if (cells_in_slide > self.max_cells and self.max_cells
                            ) or cell.metadata.ipub.slide == "new":
                            final_cells.mkdcell(nonheader_lines, cell.metadata,
                                                "verticalbreak_after")
                            cells_in_slide = 1
                        else:
                            cells_in_slide += 1
                            final_cells.mkdcell(nonheader_lines, cell.metadata,
                                                "normal")
                        # current_lines = []

                    if self.header_slide:
                        final_cells.mkdcell(
                            [line], cell.metadata,
                            "horizontalbreak_after_plusvertical")
                    else:
                        final_cells.mkdcell([line], cell.metadata,
                                            "horizontalbreak_after")
                    cells_in_slide = 1

                elif is_header(line, self.row_level):
                    if nonheader_lines and cell.metadata.ipub.get(
                            "slide", False):
                        if (cells_in_slide > self.max_cells and self.max_cells
                            ) or cell.metadata.ipub.slide == "new":
                            final_cells.mkdcell(nonheader_lines, cell.metadata,
                                                "verticalbreak_after")
                            cells_in_slide = 1
                        else:
                            cells_in_slide += 1
                            final_cells.mkdcell(nonheader_lines, cell.metadata,
                                                "normal")
                        # current_lines = []

                    final_cells.mkdcell([line], cell.metadata,
                                        "verticalbreak_after")
                    cells_in_slide = 1
                else:
                    nonheader_lines.append(line)

            if nonheader_lines and cell.metadata.ipub.get("slide", False):
                if (cells_in_slide > self.max_cells and
                        self.max_cells) or cell.metadata.ipub.slide == "new":
                    final_cells.mkdcell(nonheader_lines, cell.metadata,
                                        "verticalbreak_after")
                    cells_in_slide = 1
                else:
                    cells_in_slide += 1
                    final_cells.mkdcell(nonheader_lines, cell.metadata,
                                        "normal")

        if not final_cells.finalize():
            logging.warning("no cells available for slideshow")
        nb.cells = final_cells.cells

        return nb, resources
Exemplo n.º 30
0
    def ensure_title(self, licence, authors, logo_path):
        """
        make sure the first cell is a author + licence cell
        """

        # the title cell has 3 parts that are equidistant
        # xxx it looks like this <style> tag somehow gets
        # trimmed away when rendered inside of edx
        # so I had to add it in nbhosting's custom.css as well
        title_style = '''<style>
div.title-slide {
    width: 100%;
    display: flex;
    flex-direction: row;            /* default value; can be omitted */
    flex-wrap: nowrap;              /* default value; can be omitted */
    justify-content: space-between;
}
</style>
'''

        title_format = '''<div class="title-slide">
<span style="float:left;">{licence}</span>
<span>{html_authors}</span>
<span>{html_image}</span>
</div>'''

        title_image_format = '<img src="{logo_path}" style="display:inline" />'
        html_image = "" if not logo_path else \
                      title_image_format.format(logo_path=logo_path)

        # a bit rustic but good enough

        def is_title_cell(cell):
            # for legacy - notebooks tweaked with older versions
            # of this tool, we want to consider first cells that have
            # Licence as being our title cell as well
            return cell['cell_type'] == 'markdown' \
                and (cell['source'].find("title-slide") >= 0
                     or cell['source'].find("Licence") >= 0)
        html_authors = "" if not authors \
                       else " &amp; ".join(authors)

        title_line = title_style.replace("\n", "") \
                       + title_format.format(
                           licence=licence,
                           html_authors=html_authors,
                           html_image=html_image)

        # when opened interactively and then saved again, this is how the result looks like
        title_lines = [line + "\n" for line in title_line.split("\n")]
        # remove last \n
        title_lines[-1] = title_lines[-1][:-1]

        first_cell = self.cells()[0]
        # cell.source is a list of strings
        if is_title_cell(first_cell):
            # licence cell already here, just overwrite contents to latest version
            first_cell['source'] = title_lines
        else:
            self.cells().insert(
                0,
                NotebookNode({
                    "cell_type": "markdown",
                    "metadata": {},
                    "source": title_lines,
                }))