Пример #1
0
    def __init__(self, template_file, strip_outputs=True, write_outputs=False):
        """template_file - location of jinja template to use for export
        strip_outputs - whether to remove output cells from the output
        """
        self.exporter = MarkdownExporter()
        self.exporter.register_filter('string2json', self.string2json)
        self.exporter.register_filter('create_input_codeblock',
                                      self.create_input_codeblock)
        self.exporter.register_filter('create_output_codeblock',
                                      self.create_output_codeblock)
        self.exporter.register_filter('create_output_block',
                                      self.create_output_block)
        self.exporter.register_filter('create_attributes',
                                      self.create_attributes)
        self.exporter.register_filter('dequote', self.dequote)
        self.exporter.register_filter('data2uri', self.data2uri)
        self.load_template(template_file)
        self.strip_outputs = strip_outputs

        self.write_outputs = write_outputs
        self.output_dir = './figures/'
Пример #2
0
    def __init__(self, template_file, strip_outputs=True,
                 write_outputs=False):
        """template_file - location of jinja template to use for export
        strip_outputs - whether to remove output cells from the output
        """
        self.exporter = MarkdownExporter()
        self.exporter.register_filter('string2json', self.string2json)
        self.exporter.register_filter('create_input_codeblock',
                                      self.create_input_codeblock)
        self.exporter.register_filter('create_output_codeblock',
                                      self.create_output_codeblock)
        self.exporter.register_filter('create_output_block',
                                      self.create_output_block)
        self.exporter.register_filter('create_attributes',
                                      self.create_attributes)
        self.exporter.register_filter('dequote', self.dequote)
        self.exporter.register_filter('data2uri', self.data2uri)
        self.load_template(template_file)
        self.strip_outputs = strip_outputs

        self.write_outputs = write_outputs
        self.output_dir = './figures/'
Пример #3
0
class MarkdownWriter(NotebookWriter):
    """Write a notebook into markdown."""
    def __init__(self, template_file, strip_outputs=True,
                 write_outputs=False):
        """template_file - location of jinja template to use for export
        strip_outputs - whether to remove output cells from the output
        """
        self.exporter = MarkdownExporter()
        self.exporter.register_filter('string2json', self.string2json)
        self.exporter.register_filter('create_input_codeblock',
                                      self.create_input_codeblock)
        self.exporter.register_filter('create_output_codeblock',
                                      self.create_output_codeblock)
        self.exporter.register_filter('create_output_block',
                                      self.create_output_block)
        self.exporter.register_filter('create_attributes',
                                      self.create_attributes)
        self.exporter.register_filter('dequote', self.dequote)
        self.exporter.register_filter('data2uri', self.data2uri)
        self.load_template(template_file)
        self.strip_outputs = strip_outputs

        self.write_outputs = write_outputs
        self.output_dir = './figures/'

    def load_template(self, template_file):
        """IPython cannot load a template from an absolute path. If
        we want to include templates in our package they will be
        placed on an absolute path. Here we create a temporary file
        on a relative path and read from there after copying the
        template to it.
        """
        tmp = tempfile.NamedTemporaryFile(dir='./', mode='w+')
        tmp_path = os.path.relpath(tmp.name)

        with io.open(template_file, encoding='utf-8') as orig:
            tmp.file.write(orig.read())
            tmp.file.flush()

        self.exporter.template_file = tmp_path
        self.exporter._load_template()
        tmp.close()

    def write_from_json(self, notebook_json):
        notebook = v4.reads_json(notebook_json)
        return self.write(notebook)

    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

    def write_resources(self, resources):
        """Write the output data in resources returned by exporter
        to files.
        """
        for filename, data in list(resources.get('outputs', {}).items()):
            # Determine where to write the file to
            dest = os.path.join(self.output_dir, filename)
            path = os.path.dirname(dest)
            if path and not os.path.isdir(path):
                os.makedirs(path)

            # Write file
            with open(dest, 'wb') as f:
                f.write(data)

    # --- filter functions to be used in the output template --- #
    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')

    def create_input_codeblock(self, cell):
        codeblock = ('{fence}{attributes}\n'
                     '{cell.source}\n'
                     '{fence}')
        attrs = self.create_attributes(cell, cell_type='input')
        return codeblock.format(attributes=attrs, fence='```', cell=cell)

    def create_output_block(self, cell):
        if self.strip_outputs:
            return ''
        else:
            return self.create_output_codeblock(cell)

    def create_output_codeblock(self, cell):
        codeblock = ('{fence}{{.json .output n={execution_count}}}\n'
                     '{contents}\n'
                     '{fence}')
        return codeblock.format(fence='```',
                                execution_count=cell.execution_count,
                                contents=self.string2json(cell.outputs))

    def create_attributes(self, cell, cell_type=None):
        """Turn the attribute dict into an attribute string
        for the code block.
        """
        if self.strip_outputs or not hasattr(cell, 'execution_count'):
            return 'python'

        attrs = cell.metadata.get('attributes')
        attr = PandocAttributes(attrs, 'dict')

        if 'python' in attr.classes:
            attr.classes.remove('python')
        if 'input' in attr.classes:
            attr.classes.remove('input')

        if cell_type == 'figure':
            attr.kvs.pop('caption', '')
            attr.classes.append('figure')
            attr.classes.append('output')
            return attr.to_html()

        elif cell_type == 'input':
            # ensure python goes first so that github highlights it
            attr.classes.insert(0, 'python')
            attr.classes.insert(1, 'input')
            if cell.execution_count:
                attr.kvs['n'] = cell.execution_count
            return attr.to_markdown(format='{classes} {id} {kvs}')

        else:
            return attr.to_markdown()

    @staticmethod
    def dequote(s):
        """Remove excess quotes from a string."""
        if len(s) < 2:
            return s
        elif (s[0] == s[-1]) and s.startswith(('"', "'")):
            return s[1: -1]
        else:
            return s

    @staticmethod
    def data2uri(data, data_type):
        """Convert base64 data into a data uri with the given data_type."""
        MIME_MAP = {
            'image/jpeg': 'jpeg',
            'image/png': 'png',
            'text/plain': 'text',
            'text/html': 'html',
            'text/latex': 'latex',
            'application/javascript': 'html',
            'image/svg+xml': 'svg',
        }
        inverse_map = {v: k for k, v in list(MIME_MAP.items())}
        mime_type = inverse_map[data_type]
        uri = r"data:{mime};base64,{data}"
        return uri.format(mime=mime_type,
                          data=data[mime_type].replace('\n', ''))
Пример #4
0
class MarkdownWriter(NotebookWriter):
    """Write a notebook into markdown."""
    def __init__(self, template_file, strip_outputs=True,
                 write_outputs=False):
        """template_file - location of jinja template to use for export
        strip_outputs - whether to remove output cells from the output
        """
        self.exporter = MarkdownExporter()
        self.exporter.register_filter('string2json', self.string2json)
        self.exporter.register_filter('create_input_codeblock',
                                      self.create_input_codeblock)
        self.exporter.register_filter('create_output_codeblock',
                                      self.create_output_codeblock)
        self.exporter.register_filter('create_output_block',
                                      self.create_output_block)
        self.exporter.register_filter('create_attributes',
                                      self.create_attributes)
        self.exporter.register_filter('dequote', self.dequote)
        self.exporter.register_filter('data2uri', self.data2uri)
        self.load_template(template_file)
        self.strip_outputs = strip_outputs

        self.write_outputs = write_outputs
        self.output_dir = './figures/'

    def load_template(self, template_file):
        """IPython cannot load a template from an absolute path. If
        we want to include templates in our package they will be
        placed on an absolute path. Here we create a temporary file
        on a relative path and read from there after copying the
        template to it.
        """
        tmp = tempfile.NamedTemporaryFile(dir='./', mode='w+')
        tmp_path = os.path.relpath(tmp.name)

        with io.open(template_file, encoding='utf-8') as orig:
            tmp.file.write(orig.read())
            tmp.file.flush()

        self.exporter.template_file = tmp_path
        self.exporter._load_template()
        tmp.close()

    def write_from_json(self, notebook_json):
        notebook = v4.reads_json(notebook_json)
        return self.write(notebook)

    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

    def write_resources(self, resources):
        """Write the output data in resources returned by exporter
        to files.
        """
        for filename, data in list(resources.get('outputs', {}).items()):
            # Determine where to write the file to
            dest = os.path.join(self.output_dir, filename)
            path = os.path.dirname(dest)
            if path and not os.path.isdir(path):
                os.makedirs(path)

            # Write file
            with open(dest, 'wb') as f:
                f.write(data)

    # --- filter functions to be used in the output template --- #
    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')

    def create_input_codeblock(self, cell):
        codeblock = ('{fence}{attributes}\n'
                     '{cell.source}\n'
                     '{fence}')
        attrs = self.create_attributes(cell, cell_type='input')
        return codeblock.format(attributes=attrs, fence='```', cell=cell)

    def create_output_block(self, cell):
        if self.strip_outputs:
            return ''
        else:
            return self.create_output_codeblock(cell)

    def create_output_codeblock(self, cell):
        codeblock = ('{fence}{{.json .output n={execution_count}}}\n'
                     '{contents}\n'
                     '{fence}')
        return codeblock.format(fence='```',
                                execution_count=cell.execution_count,
                                contents=self.string2json(cell.outputs))

    def create_attributes(self, cell, cell_type=None):
        """Turn the attribute dict into an attribute string
        for the code block.
        """
        if self.strip_outputs or not hasattr(cell, 'execution_count'):
            return 'python'

        attrs = cell.metadata.get('attributes')
        attr = PandocAttributes(attrs, 'dict')

        if 'python' in attr.classes:
            attr.classes.remove('python')
        if 'input' in attr.classes:
            attr.classes.remove('input')

        if cell_type == 'figure':
            attr.kvs.pop('caption', '')
            attr.classes.append('figure')
            attr.classes.append('output')
            return attr.to_html()

        elif cell_type == 'input':
            # ensure python goes first so that github highlights it
            attr.classes.insert(0, 'python')
            attr.classes.insert(1, 'input')
            if cell.execution_count:
                attr.kvs['n'] = cell.execution_count
            return attr.to_markdown(format='{classes} {id} {kvs}')

        else:
            return attr.to_markdown()

    @staticmethod
    def dequote(s):
        """Remove excess quotes from a string."""
        if len(s) < 2:
            return s
        elif (s[0] == s[-1]) and s.startswith(('"', "'")):
            return s[1: -1]
        else:
            return s

    @staticmethod
    def data2uri(data, data_type):
        """Convert base64 data into a data uri with the given data_type."""
        MIME_MAP = {
            'image/jpeg': 'jpeg',
            'image/png': 'png',
            'text/plain': 'text',
            'text/html': 'html',
            'text/latex': 'latex',
            'application/javascript': 'html',
            'image/svg+xml': 'svg',
        }
        inverse_map = {v: k for k, v in list(MIME_MAP.items())}
        mime_type = inverse_map[data_type]
        uri = r"data:{mime};base64,{data}"
        return uri.format(mime=mime_type,
                          data=data[mime_type].replace('\n', ''))