def test_getitem(): attr = PandocAttributes() assert attr['id'] == '' assert attr['classes'] == [] assert not attr['whatever'] attr.kvs['whatever'] = 'dude' assert attr['whatever'] == 'dude'
def create_figures(key, value, format, metadata): """Convert Images with attributes to Figures. Images are [caption, (filename, title)]. Figures are [caption, (filename, title), attrs]. This isn't a supported pandoc type, we just use it internally. """ if isattrfigure(key, value): image = value[0] attr = PandocAttributes(pf.stringify(value[1:]), 'markdown') caption, target = image['c'] return Figure(caption, target, attr.to_pandoc()) elif isdivfigure(key, value): # use the first image inside attr, blocks = value images = [b['c'][0] for b in blocks if b['c'][0]['t'] == 'Image'] image = images[0] caption, target = image['c'] return Figure(caption, target, attr) else: return None
def test_markdown_special(): attr = PandocAttributes(attr_markdown, 'markdown') attr_special = PandocAttributes(attr_markdown_special, 'markdown') assert (attr.id == attr_special.id) assert (attr.classes == attr_special.classes) assert (attr.kvs == attr_special.kvs)
def test_markdown_special(): attr = PandocAttributes(attr_markdown, 'markdown') attr_special = PandocAttributes(attr_markdown_special, 'markdown') nt.assert_equal(attr.id, attr_special.id) nt.assert_equal(attr.classes, attr_special.classes) nt.assert_equal(attr.kvs, attr_special.kvs)
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()
def process_code_block(self, block): """Parse block attributes""" if block['type'] != self.code: return block attr = PandocAttributes(block['attributes'], 'markdown') if self.match == 'all': pass elif self.match == 'fenced' and block.get('indent'): return self.new_text_block(content=('\n' + block['icontent'] + '\n')) elif self.match == 'strict' and 'input' not in attr.classes: return self.new_text_block(content=block['raw']) elif self.match not in list(attr.classes) + ['fenced', 'strict']: return self.new_text_block(content=block['raw']) # set input / output status of cell if 'output' in attr.classes and 'json' in attr.classes: block['IO'] = 'output' elif 'input' in attr.classes: block['IO'] = 'input' attr.classes.remove('input') else: block['IO'] = 'input' if self.caption_comments: # override attributes id and caption with those set in # comments, if they exist id, caption = get_caption_comments(block['content']) if id: attr.id = id if caption: attr['caption'] = caption try: # determine the language as the first class that # is in the block attributes and also in the list # of languages language = set(attr.classes).intersection(languages).pop() attr.classes.remove(language) except KeyError: language = None block['language'] = language block['attributes'] = attr # ensure one identifier for python code if language in ('python', 'py', '', None): block['language'] = self.python # add alternate language execution magic elif language != self.python and self.magic: block['content'] = CodeMagician.magic(language) + block['content'] block['language'] = language return self.new_code_block(**block)
def process_code_block(self, block): """Parse block attributes""" if block['type'] != self.code: return block attr = PandocAttributes(block['attributes'], 'markdown') if self.match == 'all': pass elif self.match == 'fenced' and block.get('indent'): return self.new_text_block(content=('\n' + block['icontent'] + '\n')) elif (self.match == 'strict' and 'input' not in attr.classes and 'output' not in attr.classes): return self.new_text_block(content=block['raw']) elif self.match not in list(attr.classes) + ['fenced', 'strict']: return self.new_text_block(content=block['raw']) # set input / output status of cell if 'output' in attr.classes and 'json' in attr.classes: block['IO'] = 'output' elif 'input' in attr.classes: block['IO'] = 'input' attr.classes.remove('input') else: block['IO'] = 'input' if self.caption_comments: # override attributes id and caption with those set in # comments, if they exist id, caption = get_caption_comments(block['content']) if id: attr.id = id if caption: attr['caption'] = caption try: # determine the language as the first class that # is in the block attributes and also in the list # of languages language = set(attr.classes).intersection(languages).pop() attr.classes.remove(language) except KeyError: language = None block['language'] = language block['attributes'] = attr # ensure one identifier for python code if language in ('python', 'py', '', None): block['language'] = self.python # add alternate language execution magic elif language != self.python and self.magic: block['content'] = CodeMagician.magic(language) + block['content'] block['language'] = language return self.new_code_block(**block)
def test_markdown_format(): attr = PandocAttributes() attr.id = 'a' attr.classes = ['b'] attr.kvs['c'] = 'd' md = attr.to_markdown(format='{classes} {id} {kvs}') assert(md == '{.b #a c=d}')
def test_getitem(): attr = PandocAttributes() nt.assert_equal(attr['id'], '') nt.assert_equal(attr['classes'], []) with nt.assert_raises(KeyError): attr['whatever'] attr.kvs['whatever'] = 'dude' nt.assert_equal(attr['whatever'], 'dude')
def figure_replacement(self, key, value, format, metadata): """Replace figures with appropriate representation. This works with Figure, which is our special type for images with attributes. This allows us to set an id in the attributes. The other way of doing it would be to pull out a '\label{(.*)}' from the caption of an Image and use that to update the references. """ _caption, (filename, target), attrs = value caption = pf.stringify(_caption) attr = PandocAttributes(attrs) if 'unnumbered' in attr.classes: star = '*' fcaption = caption else: self.fig_replacement_count += 1 if not attr.id: attr.id = self.auto_fig_id(self.fig_replacement_count) ref = self.references[attr.id] star = '' if caption: fcaption = u'Figure {n}: {caption}'.format(n=ref['id'], caption=caption) else: fcaption = u'Figure {n}'.format(n=ref['id']) if 'figure' not in attr.classes: attr.classes.insert(0, 'figure') if format in self.formats: figure = self.figure_styles[format].format(attr=attr, filename=filename, alt=fcaption, fcaption=fcaption, caption=caption, star=star).encode('utf-8') return RawBlock(format, figure) else: alt = [pf.Str(fcaption)] target = (filename, '') image = pf.Image(alt, target) figure = pf.Para([image]) return pf.Div(attr.to_pandoc(), [figure])
def create_tableattrs(key, value, format, metadata): """Convert Tables with attributes to TableAttr. Tables are [caption, alignment, size, headers, rows] TableAttrs are [caption, alignment, size, headers, rows, attrs] Like Figures, this isn't supported pandoc type but only used internally. """ if key == 'Table': captionList, alignment, size, headers, rows = value caption, attrs = tableattrCaption(captionList) if attrs: attrs = PandocAttributes(attrs, 'markdown') return TableAttrs(caption, alignment, size, headers, rows, attrs.to_pandoc()) else: return None
def _extract_attrs(x, n): """Extracts attributes for an image. n is the index where the attributes begin. Extracted elements are deleted from the element list x. Attrs are returned in pandoc format. """ try: return extract_attrs(x, n) except (ValueError, IndexError): if PANDOCVERSION < '1.16': # Look for attributes attached to the image path, as occurs with # image references for pandoc < 1.16 (pandoc-fignos Issue #14). # See http://pandoc.org/MANUAL.html#images for the syntax. # Note: This code does not handle the "optional title" for # image references (search for link_attributes in pandoc's docs). assert x[n - 1]['t'] == 'Image' image = x[n - 1] s = image['c'][-1][0] if '%20%7B' in s: path = s[:s.index('%20%7B')] attrs = unquote(s[s.index('%7B'):]) image['c'][-1][0] = path # Remove attr string from the path return PandocAttributes(attrs.strip(), 'markdown').to_pandoc() raise
def _process_equation(value, fmt): """Processes the equation. Returns a dict containing eq properties.""" global Nreferences # pylint: disable=global-statement # Parse the equation attrs = value[0] # Initialize the return value eq = { 'is_unnumbered': False, 'is_unreferenceable': False, 'is_tagged': False, 'attrs': attrs } # Bail out if the label does not conform if not LABEL_PATTERN.match(attrs[0]): eq['is_unnumbered'] = True eq['is_unreferenceable'] = True return eq if attrs[0] == 'eq:': # Make up a unique description attrs[0] = attrs[0] + str(uuid.uuid4()) eq['is_unreferenceable'] = True unreferenceable.append(attrs[0]) # Save to the global references tracker kvs = PandocAttributes(attrs, 'pandoc').kvs eq['is_tagged'] = 'tag' in kvs if eq['is_tagged']: # Remove any surrounding quotes if kvs['tag'][0] == '"' and kvs['tag'][-1] == '"': kvs['tag'] = kvs['tag'].strip('"') elif kvs['tag'][0] == "'" and kvs['tag'][-1] == "'": kvs['tag'] = kvs['tag'].strip("'") references[attrs[0]] = kvs['tag'] else: Nreferences += 1 references[attrs[0]] = Nreferences # Adjust equation depending on the output format if fmt == 'latex': if not eq['is_unreferenceable']: # Code in the tags value[-1] += r'\tag{%s}\label{%s}' % \ (references[attrs[0]].replace(' ', r'\ '), attrs[0]) \ if eq['is_tagged'] else r'\label{%s}'%attrs[0] else: # Hard-code in the number/tag if type(references[attrs[0]]) is int: # Numbered reference value[-1] += r'\qquad (%d)' % references[attrs[0]] else: # Tagged reference assert type(references[attrs[0]]) in STRTYPES text = references[attrs[0]].replace(' ', r'\ ') if text.startswith('$') and text.endswith('$'): # Math tag = text[1:-1] else: # Text tag = r'\text{%s}' % text value[-1] += r'\qquad (%s)' % tag return eq
def test_pandoc(): attr = PandocAttributes(attr_pandoc, 'pandoc') print attr_dict print attr.to_dict() nt.assert_dict_equal(attr_dict, attr.to_dict()) nt.assert_equal(attr_html, attr.to_html()) nt.assert_equal(attr_markdown.replace('\n', ' '), attr.to_markdown()) assert (attr_pandoc == attr.to_pandoc())
def math_replacement(self, key, value, format, metadata): """Create our own links to equations instead of relying on mathjax. http://meta.math.stackexchange.com/questions/3764/equation-and-equation-is-the-same-for-me """ mathtype, math = value label = re.findall(math_label, math)[-1] attr = PandocAttributes() attr.id = '#' + label if format in ['latex', 'beamer']: return pf.Math(mathtype, math) else: return pf.Span(attr.to_pandoc(), [pf.Math(mathtype, math)])
def math_replacement(self, key, value, format, metadata): """Create our own links to equations instead of relying on mathjax. http://meta.math.stackexchange.com/questions/3764/equation-and-equation-is-the-same-for-me """ mathtype, math = value label = re.findall(math_label, math)[-1] attr = PandocAttributes() attr.id = '#' + label if format == 'latex' or format == 'beamer': return pf.Math(mathtype, math) else: return pf.Span(attr.to_pandoc(), [pf.Math(mathtype, math)])
def test_pandoc(): attr = PandocAttributes(attr_pandoc, 'pandoc') print attr_dict print attr.to_dict() nt.assert_dict_equal(attr_dict, attr.to_dict()) nt.assert_equal(attr_html, attr.to_html()) nt.assert_equal(attr_markdown.replace('\n', ' '), attr.to_markdown()) assert(attr_pandoc == attr.to_pandoc())
def code2raw(key, val, format, meta): if key not in raw4code: return None attrs = PandocAttributes(val[0], format='pandoc') raw = attrs.kvs.get('raw', None) if raw: # if raw != format: # but what if we output markdown? # return [] return raw4code[key](raw, val[-1]) else: return None
def test_markdown_format(): attr = PandocAttributes() attr.id = 'a' attr.classes = ['b'] attr.kvs['c'] = 'd' md = attr.to_markdown(format='{classes} {id} {kvs}') assert (md == '{.b #a c=d}')
def process_code_block(self, block): """Parse block attributes""" if block['type'] != self.code: return block attr = PandocAttributes(block['attributes'], 'markdown') try: language = set(attr.classes).intersection(languages).pop() attr.classes.remove(language) except KeyError: language = None if self.match == 'all': pass elif self.match == 'fenced': if block.get('indent'): return self.new_text_block(content=('\n' + block['icontent'] + '\n')) elif self.match == 'strict': if 'input' not in attr.classes: return self.new_text_block(content=block['raw']) elif self.match != language: return self.new_text_block(content=block['raw']) # set input / output status of cell if 'output' in attr.classes and 'json' in attr.classes: block['IO'] = 'output' elif 'input' in attr.classes: block['IO'] = 'input' attr.classes.remove('input') else: block['IO'] = 'input' block['language'] = language block['attributes'] = attr # ensure one identifier for python code if language in ('python', 'py', '', None): block['language'] = self.python # add alternate language execution magic elif language != self.python and self.magic: block['content'] = CodeMagician.magic(language) + block['content'] block['language'] = language return self.new_code_block(**block)
def enclose_input_code(key, value, format, metadata): """Enclose any input code in a div to allow collapsing. 'Input code' is a code block that has 'n' defined (the prompt number). """ if key == 'CodeBlock': div_attr = {'classes': ['collapsible']} code_attr = PandocAttributes(value[0], format='pandoc') if 'n' not in code_attr.kvs: return else: button = pf.RawBlock('html', collapse_button(n=code_attr['n'])) code = pf.CodeBlock(*value) content = [button, pf.Div(pf.attributes({}), [code])] return pf.Div(pf.attributes(div_attr), content)
def parse_attrtable(value): """Parses an attributed table.""" # Extract the attribute string. There may be text immediately in front # of the attribute string that we will need to retain. caption, content = value[0], value[1:] c, s = ATTR_PATTERN.match(caption[-1]['c']).groups() if not c: caption = caption[:-1] if caption and caption[-1]['t'] == 'Space': caption = caption[:-1] else: caption[-1]['c'] = c # Extract label from the attributes (label, classes, kvs) label = PandocAttributes(s, 'markdown').to_pandoc()[0] if label == 'tbl:': # Make up a unique description label = label + '__' + str(hash(str(content))) + '__' return content, caption, label
def parse_attrimage(value): """Parses an attributed image.""" if len(value[0]['c']) == 2: # Old pandoc < 1.16 attrs, (caption, target) = None, value[0]['c'] s = stringify(value[1:]).strip() # The attribute string # Extract label from attributes (label, classes, kvs) label = PandocAttributes(s, 'markdown').to_pandoc()[0] if label == 'fig:': # Make up a unique description label = label + '__' + str(hash(target[0])) + '__' return attrs, caption, target, label else: # New pandoc >= 1.16 assert len(value[0]['c']) == 3 attrs, caption, target = value[0]['c'] s = stringify(value[1:]).strip() # The attribute string # Extract label from attributes label = attrs[0] if label == 'fig:': # Make up a unique description label = label + '__' + str(hash(target[0])) + '__' return attrs, caption, target, label
def blocks_to_components(self, blocks): """Convert blocks into Dash components""" for block in blocks: if block["type"] == self.markdown: content = self.preprocess_markdown(block["content"]) yield self.make_markdown_component(content) else: # attrs.id --> the ID # attrs.classes --> list of classed # attrs.kvs --> OrderedDict of key, val pairs attrs = PandocAttributes(block["attributes"], "markdown") if "precode" in attrs.classes: self.precode = f"{self.precode}\n\n{attrs.classes['precode']}" if "app-precode" in attrs.classes: self.app_precode = f"{self.app_precode}\n\n{attrs.classes['app-precode']}" if "dash" not in attrs.classes: # Currently ignore code blocks without a `dash` class continue if "app" in attrs.kvs: # assume this is a file path. # TODO: also support python imports with optional attribute: # eg app.foo:layout path = self.app_path / attrs["app"] else: # TODO: support copying inline apps into new dir continue component_id = attrs.id if attrs.id != "" else None classes = [ c for c in attrs.classes if c not in ("dash", "app") ] yield self.make_dash_component(path, id=component_id, classes=classes)
def test_empty(): attr = PandocAttributes() nt.assert_true(attr.is_empty)
def test_surround(): attr = PandocAttributes(attr_markdown, 'markdown') print(attr.to_markdown(surround=False)) print(attr_markdown.replace('\n', ' ').strip('{}')) nt.assert_equal(attr.to_markdown(surround=False), attr_markdown.replace('\n', ' ').strip('{}'))
def test_properties(): attr = PandocAttributes(attr_markdown, 'markdown') nt.assert_equal(attr.html, attr.to_html()) nt.assert_equal(attr.markdown, attr.to_markdown()) nt.assert_equal(attr.dict, attr.to_dict()) nt.assert_equal(attr.list, attr.to_pandoc())
def _process_table(value, fmt): """Processes the table. Returns a dict containing table properties.""" # pylint: disable=global-statement global Nreferences # Global references counter global has_unnumbered_tables # Flags unnumbered tables were found global cursec # Current section # Parse the table attrs, caption = value[:2] # Initialize the return value table = {'is_unnumbered': False, 'is_unreferenceable': False, 'is_tagged': False, 'attrs': attrs} # Bail out if the label does not conform if not LABEL_PATTERN.match(attrs[0]): has_unnumbered_tables = True table['is_unnumbered'] = True table['is_unreferenceable'] = True return table # Process unreferenceable tables if attrs[0] == 'tbl:': # Make up a unique description attrs[0] = 'tbl:' + str(uuid.uuid4()) table['is_unreferenceable'] = True unreferenceable.append(attrs[0]) # For html, hard-code in the section numbers as tags kvs = PandocAttributes(attrs, 'pandoc').kvs if numbersections and fmt in ['html', 'html5'] and not 'tag' in kvs: if kvs['secno'] != cursec: cursec = kvs['secno'] Nreferences = 1 kvs['tag'] = cursec + '.' + str(Nreferences) Nreferences += 1 # Save to the global references tracker table['is_tagged'] = 'tag' in kvs if table['is_tagged']: # Remove any surrounding quotes if kvs['tag'][0] == '"' and kvs['tag'][-1] == '"': kvs['tag'] = kvs['tag'].strip('"') elif kvs['tag'][0] == "'" and kvs['tag'][-1] == "'": kvs['tag'] = kvs['tag'].strip("'") references[attrs[0]] = kvs['tag'] else: Nreferences += 1 references[attrs[0]] = Nreferences # Adjust caption depending on the output format if fmt == 'latex': if not table['is_unreferenceable']: value[1] += [RawInline('tex', r'\label{%s}'%attrs[0])] else: # Hard-code in the caption name and number/tag if type(references[attrs[0]]) is int: value[1] = [Str(captionname), Space(), Str('%d:'%references[attrs[0]]), Space()] + \ list(caption) else: # Tagged reference assert type(references[attrs[0]]) in STRTYPES text = references[attrs[0]] if text.startswith('$') and text.endswith('$'): math = text.replace(' ', r'\ ')[1:-1] els = [Math({"t":"InlineMath", "c":[]}, math), Str(':')] else: els = [Str(text + ':')] value[1] = [Str(captionname), Space()] + els + [Space()] + \ list(caption) return table
def test_markdown_single(): attr = PandocAttributes('python', 'markdown') nt.assert_equal(attr.id, '') nt.assert_equal(attr.classes, ['python']) nt.assert_equal(attr.kvs, OrderedDict())
def test_markdown_single(): attr = PandocAttributes('python', 'markdown') assert (attr.id == '') assert (attr.classes == ['python']) assert (attr.kvs == OrderedDict())
def test_surround(): attr = PandocAttributes(attr_markdown, 'markdown') print attr.to_markdown(surround=False) print attr_markdown.replace('\n', ' ').strip('{}') assert (attr.to_markdown(surround=False) == attr_markdown.replace( '\n', ' ').strip('{}'))
def _process_figure(value, fmt): """Processes the figure. Returns a dict containing figure properties.""" # pylint: disable=global-statement global Nreferences global has_unnumbered_figures # Parse the image attrs, caption = value[0]['c'][:2] # Initialize the return value fig = {'is_unnumbered': False, 'is_unreferenceable': False, 'is_tagged': False, 'attrs': attrs} # Bail out if the label does not conform if not LABEL_PATTERN.match(attrs[0]): has_unnumbered_figures = True fig['is_unnumbered'] = True fig['is_unreferenceable'] = True return fig # Process unreferenceable figures if attrs[0] == 'fig:': # Make up a unique description attrs[0] = attrs[0] + str(uuid.uuid4()) fig['is_unreferenceable'] = True unreferenceable.append(attrs[0]) # Save to the global references tracker kvs = PandocAttributes(attrs, 'pandoc').kvs fig['is_tagged'] = 'tag' in kvs if fig['is_tagged']: # Remove any surrounding quotes if kvs['tag'][0] == '"' and kvs['tag'][-1] == '"': kvs['tag'] = kvs['tag'].strip('"') elif kvs['tag'][0] == "'" and kvs['tag'][-1] == "'": kvs['tag'] = kvs['tag'].strip("'") references[attrs[0]] = kvs['tag'] else: Nreferences += 1 references[attrs[0]] = Nreferences # Adjust caption depending on the output format if fmt == 'latex': # Append a \label if this is referenceable if not fig['is_unreferenceable']: value[0]['c'][1] += [RawInline('tex', r'\label{%s}'%attrs[0])] else: # Hard-code in the caption name and number/tag if type(references[attrs[0]]) is int: # Numbered reference value[0]['c'][1] = [Str(captionname), Space(), Str('%d:'%references[attrs[0]]), Space()] + \ list(caption) else: # Tagged reference assert type(references[attrs[0]]) in STRTYPES text = references[attrs[0]] if text.startswith('$') and text.endswith('$'): # Math math = text.replace(' ', r'\ ')[1:-1] els = [Math({"t":"InlineMath", "c":[]}, math), Str(':')] else: # Text els = [Str(text+':')] value[0]['c'][1] = [Str('Table'), Space()]+ els + [Space()] + \ list(caption) return fig
def test_empty(): attr = PandocAttributes() assert attr.is_empty
def test_properties(): attr = PandocAttributes(attr_markdown, 'markdown') assert(attr.html == attr.to_html()) assert(attr.markdown == attr.to_markdown()) assert(attr.dict == attr.to_dict()) assert(attr.list == attr.to_pandoc())
def test_surround(): attr = PandocAttributes(attr_markdown, 'markdown') print attr.to_markdown(surround=False) print attr_markdown.replace('\n', ' ').strip('{}') assert(attr.to_markdown(surround=False) == attr_markdown.replace('\n', ' ').strip('{}'))
def test_properties(): attr = PandocAttributes(attr_markdown, 'markdown') assert (attr.html == attr.to_html()) assert (attr.markdown == attr.to_markdown()) assert (attr.dict == attr.to_dict()) assert (attr.list == attr.to_pandoc())