Markups-1.0.1/ 0000755 0001750 0001750 00000000000 12636260065 014003 5 ustar dmitry dmitry 0000000 0000000 Markups-1.0.1/docs/ 0000755 0001750 0001750 00000000000 12636260064 014732 5 ustar dmitry dmitry 0000000 0000000 Markups-1.0.1/docs/overview.rst 0000644 0001750 0001750 00000002405 12561175331 017332 0 ustar dmitry dmitry 0000000 0000000 ============
API overview
============
For the very basic usage of Python-Markups, one should import
some markup class from :mod:`markups`, create an instance
of that class, and use the methods provided by
:class:`~markups.abstract.AbstractMarkup`:
>>> import markups
>>> markup = markups.ReStructuredTextMarkup()
>>> markup.get_document_body('*reStructuredText* test')
'
reStructuredText test
\n'
For advanced usage (like dynamically choosing the markup class),
one may use one of the functions documented below.
Getting lists of available markups
==================================
.. autofunction:: markups.get_all_markups
.. autofunction:: markups.get_available_markups
.. autofunction:: markups.get_custom_markups
Getting a specific markup
=========================
.. autofunction:: markups.get_markup_for_file_name
.. autofunction:: markups.find_markup_class_by_name
.. _configuration-directory:
Configuration directory
=======================
Some markups can provide configuration files that the user may use
to change the behavior.
These files are stored in a single configuration directory.
If :envvar:`XDG_CONFIG_HOME` is defined, then the configuration
directory is it. Otherwise, it is :file:`.config` subdirectory in
the user's home directory.
Markups-1.0.1/docs/interface.rst 0000644 0001750 0001750 00000000525 12561175331 017425 0 ustar dmitry dmitry 0000000 0000000 ================
Markup interface
================
The main class for interacting with markups is :class:`~markups.abstract.AbstractMarkup`.
However, you shouldn't create direct instances of that class. Instead, use one of the
:doc:`standard markup classes `.
.. autoclass:: markups.abstract.AbstractMarkup
:members:
Markups-1.0.1/docs/standard_markups.rst 0000644 0001750 0001750 00000005426 12633272000 021023 0 ustar dmitry dmitry 0000000 0000000 ================
Built-in markups
================
These markups are available by default:
Markdown markup
===============
Markdown_ markup uses Python-Markdown_ as a backend (version 2.6 is
required).
There are several ways to enable `Python-Markdown extensions`_.
* List extensions in a file named :file:`markdown-extensions.txt` in
the :ref:`configuration directory `,
separated by newline. The extensions will be automatically applied
to all documents.
* If :file:`markdown-extensions.txt` is placed into working directory,
all documents in that directory will get extensions listed in that
file.
* If first line of a document contains ":samp:`Required extensions:
{ext1 ext2 ...}`", that list will be applied to a document.
* Finally, one can programmatically pass list of extension names to
:class:`markups.MarkdownMarkup` constructor.
Additionally to features provided by Python-Markdown, this markup also
supports a syntax for LaTeX-style math formulas (powered by MathJax_).
The delimiters are:
================ ===============
Inline math Standalone math
================ ===============
``$...$`` [#f1]_ ``$$...$$``
``\(...\)`` ``\[...\]``
================ ===============
.. [#f1] To enable single-dollar-sign delimiter, one should enable
virtual ``mathjax`` extension.
The `Python-Markdown Extra`_ set of extensions is enabled by default.
To disable it, one can enable virtual ``remove_extra`` extension
(which also completely disables LaTeX formulas support).
The default file extension associated with Markdown markup is ``.mkd``,
though many other extensions (including ``.md`` and ``.markdown``) are
supported as well.
.. _Markdown: http://daringfireball.net/projects/markdown/
.. _Python-Markdown: https://pythonhosted.org/Markdown/
.. _MathJax: https://www.mathjax.org/
.. _`Python-Markdown extensions`: http://pythonhosted.org/Markdown/extensions/
.. _`Python-Markdown Extra`: http://pythonhosted.org/Markdown/extensions/extra.html
.. autoclass:: markups.MarkdownMarkup
reStructuredText markup
========================
This markup provides support for reStructuredText_ language (the language
this documentation is written in). It uses Docutils_ Python module.
The file extension associated with reStructuredText markup is ``.rst``.
.. _reStructuredText: http://docutils.sourceforge.net/rst.html
.. _Docutils: http://docutils.sourceforge.net/
.. autoclass:: markups.ReStructuredTextMarkup
Textile markup
==============
This markup provides support for Textile_ language. It uses python-textile_
module.
The file extension associated with Textile markup is ``.textile``.
.. _Textile: https://en.wikipedia.org/wiki/Textile_(markup_language)
.. _python-textile: https://github.com/textile/python-textile
.. autoclass:: markups.TextileMarkup
Markups-1.0.1/docs/conf.py 0000644 0001750 0001750 00000003061 12633313326 016226 0 ustar dmitry dmitry 0000000 0000000 #!/usr/bin/env python3
import sys
import os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path.insert(0, os.path.abspath('..'))
# -- General configuration ------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc',
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'Python-Markups'
copyright = u'2015, Dmitry Shachnev'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
from markups import __version_tuple__
# The short X.Y version.
version = '%d.%d' % __version_tuple__[:2]
# The full version, including alpha/beta/rc tags.
release = '%d.%d.%d' % __version_tuple__
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'nature'
Markups-1.0.1/docs/custom_markups.rst 0000644 0001750 0001750 00000004226 12561175331 020543 0 ustar dmitry dmitry 0000000 0000000 ==============
Custom Markups
==============
Registering the markup module
=============================
A third-party markup is a Python module that can be installed
the usual way.
Every module should have :data:`markup` property pointing to
the markup class.
To register the markup, one should append the full module name to
file named ``pymarkups.txt`` in the
:ref:`configuration directory `.
To check if the module was found by Python-Markups, one can check
if the module is present in return value of
:func:`~markups.get_custom_markups` function.
.. versionchanged:: 0.6
The third-party markup is now a normal Python module, not
necessarily a file in ``markups`` namespace.
Importing third-party modules
=============================
A markup must not directly import any third party Python module it uses
at file level. Instead, it should check the module availability in
:meth:`~markups.abstract.AbstractMarkup.available` static method.
That method can try to import the needed modules, and return ``True`` in
case of success, and ``False`` in case of failure.
Implementing methods
====================
Any markup must inherit from :class:`~markups.abstract.AbstractMarkup`
class.
Third-party markups must implement
:meth:`~markups.abstract.AbstractMarkup.get_document_body` method, which
is the main method of any markup.
Other methods that are optional:
* :meth:`~markups.abstract.AbstractMarkup.get_document_title`;
* :meth:`~markups.abstract.AbstractMarkup.get_javascript`;
* :meth:`~markups.abstract.AbstractMarkup.get_stylesheet`.
Using the cache
===============
Markups are provided with :attr:`~markups.abstract.AbstractMarkup._cache`
dictionary that can contain any data shared between subsequent calls to
markup methods. Attribute :attr:`~markups.abstract._enable_cache`
indicates whether or not the cache should be used (set to ``False`` by
default).
For example, :meth:`~markups.abstract.AbstractMarkup.get_whole_html`
method sets :attr:`~markups.abstract._enable_cache` to ``True``, then
subsequently retrieves document title, body, javascript and stylesheet,
and sets :attr:`~markups.abstract._enable_cache` back to ``False``.
Markups-1.0.1/docs/changelog.rst 0000644 0001750 0001750 00000000500 12575334254 017413 0 ustar dmitry dmitry 0000000 0000000 ========================
Python-Markups changelog
========================
This changelog only lists the most important changes that
happened in Python-Markups. Please see the `Git log`_ for
the full list of changes.
.. _`Git log`: https://github.com/retext-project/pymarkups/commits/master
.. include:: ../changelog
Markups-1.0.1/docs/index.rst 0000644 0001750 0001750 00000001776 12575334301 016604 0 ustar dmitry dmitry 0000000 0000000 ===================================
Python-Markups module documentation
===================================
Introduction to Python-Markups
==============================
Python-Markups is a module that provides unified interface for using
various markup languages, such as Markdown, reStructuredText, and
Textile. It is also possible for clients to create and register their
own markup languages.
The output language Python-Markups works with is HTML. Stylesheets and
JavaScript sections are supported.
The abstract interface that any markup implements is
:class:`~markups.abstract.AbstractMarkup`.
Contents
========
.. toctree::
overview
interface
standard_markups
custom_markups
changelog
Links
=====
* Python-Markups source code is hosted on GitHub_.
* You can get the source tarball from PyPI_.
* It is also packaged in Debian_.
.. _GitHub: https://github.com/retext-project/pymarkups
.. _PyPI: https://pypi.python.org/pypi/Markups
.. _Debian: https://packages.debian.org/sid/source/pymarkups
Markups-1.0.1/changelog 0000644 0001750 0001750 00000006172 12636257360 015667 0 ustar dmitry dmitry 0000000 0000000 Version 1.0.1, 2015-12-22
=========================
* The Textile markup now uses the recommended python-textile API.
* Fixed warnings during installation.
* Python-Markdown Math extension updated to the latest version.
Version 1.0, 2015-12-13
=======================
* Web module removed, as ReText no longer needs it.
* Textile markup updated to work with the latest version of Python-Textile
module.
* The setup script now uses setuptools when it is available.
* Testsuite and documentation improvements.
Version 0.6.3, 2015-06-16
=========================
* No-change re-upload with fixed tarball and changelog.
Version 0.6.2, 2015-06-09
=========================
* Markdown markup: fixed detection of codehilite extension with options.
* Added a warning about deprecation of the markups.web module.
Version 0.6.1, 2015-04-19
=========================
* PyMarkups now uses warnings system instead of printing messages to
stderr.
* Improvements to Markdown markup:
+ Fixed parsing math that contains nested environments (thanks to Gautam
Iyer for the patch).
+ Fixed crash on extensions names starting with dot.
* Miscellaneous fixes.
Version 0.6, 2015-01-25
=======================
Incompatible changes:
* Custom markups are now normal Python modules.
* Web module no longer supports Python 2.x.
Other changes:
* Refactor the code related to Markdown extensions to make it work with
upcoming Python-Markdown releases.
* MathJax extension is now in a separate module.
Version 0.5.2, 2014-11-05
=========================
* Fixed loading of Markdown extensions with options.
Version 0.5.1, 2014-09-16
=========================
* Fixed Markdown markup crash on empty files.
* Include documentation in the tarballs.
* Testsuite improvements.
Version 0.5, 2014-07-25
=======================
* Improvements to Markdown markup:
+ All math delimeters except ``$...$`` are now enabled by default.
+ ``remove_extra`` extension now disables formulas support.
+ It is now possible to specify required extensions in the first line of
the file.
* Add Sphinx documentation.
Version 0.4, 2013-11-30
=======================
* Add Textile markup.
* reStructuredText markup now supports file names and settings overrides.
* Web module now raises WebUpdateError when updating fails.
Version 0.3, 2013-07-25
=======================
* MathJax support in Markdown has been improved and no longer relies on
tex2jax extension.
* It is now possible to pass extensions list to MarkdownMarkup constructor.
* Pygments style is now configurable.
* Testsuite improvements.
Version 0.2.3, 2012-11-02
=========================
* Fix support for custom working directory in web module.
* Bug fixes in Markdown module and tests.
Version 0.2.2, 2012-10-02
=========================
* Re-written math support for Markdown.
* Add tests to the tarball.
* Add example template for web module.
* Bug fixes in Markdown and web modules.
Version 0.2.1, 2012-09-09
=========================
* Add caching support, to speed up get_document_body function.
* Add testsuite.
* Fix some bugs in markdown module.
Version 0.2, 2012-09-04
=======================
* Initial release.
Markups-1.0.1/markups/ 0000755 0001750 0001750 00000000000 12636260064 015464 5 ustar dmitry dmitry 0000000 0000000 Markups-1.0.1/markups/restructuredtext.py 0000644 0001750 0001750 00000004713 12561175331 021502 0 ustar dmitry dmitry 0000000 0000000 # This file is part of python-markups module
# License: BSD
# Copyright: (C) Dmitry Shachnev, 2012-2014
import markups.common as common
from markups.abstract import AbstractMarkup
class ReStructuredTextMarkup(AbstractMarkup):
"""Markup class for reStructuredText language.
Inherits :class:`~markups.abstract.AbstractMarkup`.
:param settings_overrides: optional dictionary of overrides for the
`Docutils settings`_
:type settings_overrides: dict
.. _`Docutils settings`: http://docutils.sourceforge.net/docs/user/config.html
"""
name = 'reStructuredText'
attributes = {
common.LANGUAGE_HOME_PAGE: 'http://docutils.sourceforge.net/rst.html',
common.MODULE_HOME_PAGE: 'http://docutils.sourceforge.net/',
common.SYNTAX_DOCUMENTATION: 'http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html'
}
file_extensions = ('.rst', '.rest')
default_extension = '.rst'
@staticmethod
def available():
try:
import docutils.core
except ImportError:
return False
return True
def __init__(self, filename=None, settings_overrides=None):
self.overrides = settings_overrides or {}
self.overrides.update({'math_output': 'MathJax'})
AbstractMarkup.__init__(self, filename)
from docutils.core import publish_parts
self._publish_parts = publish_parts
def publish_parts(self, text):
if 'rest_parts' in self._cache:
return self._cache['rest_parts']
parts = self._publish_parts(text, source_path=self.filename,
writer_name='html', settings_overrides=self.overrides)
if self._enable_cache:
self._cache['rest_parts'] = parts
return parts
def get_document_title(self, text):
return self.publish_parts(text)['title']
def get_document_body(self, text):
return self.publish_parts(text)['body']
def get_stylesheet(self, text=''):
origstyle = self.publish_parts(text)['stylesheet']
# Cut off tags
stylestart = '')]
return stylesheet + common.get_pygments_stylesheet('.code')
def get_javascript(self, text='', webenv=False):
head = self.publish_parts(text)['head']
start_position = head.find('
'''
extensions_re = re.compile(r'required.extensions: ([ \w\.\(\),=_]+)', flags=re.IGNORECASE)
class MarkdownMarkup(AbstractMarkup):
"""Markup class for Markdown language.
Inherits :class:`~markups.abstract.AbstractMarkup`.
:param extensions: list of extension names
:type extensions: list
"""
name = 'Markdown'
attributes = {
common.LANGUAGE_HOME_PAGE: 'http://daringfireball.net/projects/markdown/',
common.MODULE_HOME_PAGE: 'https://github.com/Waylan/Python-Markdown/',
common.SYNTAX_DOCUMENTATION: 'http://daringfireball.net/projects/markdown/syntax'
}
file_extensions = ('.md', '.mkd', '.mkdn', '.mdwn', '.mdown', '.markdown')
default_extension = '.mkd'
@staticmethod
def available():
try:
import markdown
except ImportError:
return False
return hasattr(markdown, 'version_info') and markdown.version_info >= (2, 6)
def _load_extensions_list_from_file(self, filename):
try:
extensions_file = open(filename)
except IOError:
return []
else:
extensions = [line.rstrip() for line in extensions_file
if not line.startswith('#')]
extensions_file.close()
return extensions
def _get_global_extensions(self, filename):
extensions = self._load_extensions_list_from_file(
os.path.join(common.CONFIGURATION_DIR, 'markdown-extensions.txt'))
local_directory = os.path.dirname(filename) if filename else ''
extensions += self._load_extensions_list_from_file(
os.path.join(local_directory, 'markdown-extensions.txt'))
return extensions
def _get_document_extensions(self, text):
lines = text.splitlines()
match = extensions_re.search(lines[0]) if lines else None
if match:
return match.group(1).strip().split()
return []
def _canonicalize_extension_name(self, extension_name):
lb = extension_name.find('(')
if lb >= 0:
extension_name, parameters = extension_name[:lb], extension_name[lb:]
else:
parameters = ''
prefixes = ('markdown.extensions.', '', 'mdx_')
for prefix in prefixes:
try:
module = importlib.import_module(prefix + extension_name)
if not hasattr(module, 'makeExtension'):
continue
except (ImportError, ValueError, TypeError):
pass
else:
return prefix + extension_name + parameters
def _apply_extensions(self):
extensions = (self.requested_extensions or
self.global_extensions) + self.document_extensions
extensions_final = []
should_push_extra = True
should_push_mathjax = (True, False)
for extension in extensions:
if extension == 'mathjax':
should_push_mathjax = (True, True)
elif extension == 'remove_extra':
should_push_extra = False
should_push_mathjax = (False, )
else:
canonical_name = self._canonicalize_extension_name(extension)
if not canonical_name:
warnings.warn('Extension "%s" does not exist.' %
extension, ImportWarning)
continue
if canonical_name not in extensions_final:
extensions_final.append(canonical_name)
if should_push_extra:
extensions_final.append('markdown.extensions.extra')
if should_push_mathjax[0]:
extensions_final.append('markups.mdx_mathjax(enable_dollar_delimiter=%r)' %
should_push_mathjax[1])
self.md = self.markdown.Markdown(extensions=extensions_final, output_format='html4')
self.extensions = extensions_final
def __init__(self, filename=None, extensions=None):
AbstractMarkup.__init__(self, filename)
import markdown
self.markdown = markdown
self.requested_extensions = extensions or []
self.global_extensions = self._get_global_extensions(filename)
self.document_extensions = []
self._apply_extensions()
def get_document_title(self, text):
if not 'body' in self._cache:
self.get_document_body(text)
if hasattr(self.md, 'Meta') and 'title' in self.md.Meta:
return str.join(' ', self.md.Meta['title'])
else:
return ''
def get_stylesheet(self, text=''):
has_codehilite = False
for extension in self.extensions:
if extension.endswith('codehilite'):
has_codehilite = True
if has_codehilite:
return common.get_pygments_stylesheet('.codehilite')
return ''
def get_javascript(self, text='', webenv=False):
if 'body' in self._cache:
body = self._cache['body']
else:
body = self.get_document_body(text)
if not '')
def get_document_body(self, text):
self.md.reset()
document_extensions = self._get_document_extensions(text)
if document_extensions or self.document_extensions:
self.document_extensions = document_extensions
self._apply_extensions()
converted_text = self.md.convert(text) + '\n'
if self._enable_cache:
self._cache['body'] = converted_text
return converted_text
Markups-1.0.1/markups/abstract.py 0000644 0001750 0001750 00000004616 12561175331 017647 0 ustar dmitry dmitry 0000000 0000000 # This file is part of python-markups module
# License: BSD
# Copyright: (C) Dmitry Shachnev, 2012-2014
class AbstractMarkup(object):
"""Abstract class for markup languages.
:param filename: optional name of the file
:type filename: str
"""
#: name of the markup visible to user
name = ''
#: various attributes, like links to website and syntax documentation
attributes = {}
#: indicates which file extensions are associated with the markup
file_extensions = ()
#: the default file extension
default_extension = ''
def __init__(self, filename=None):
self.filename = filename
self._enable_cache = False
self._cache = {}
@staticmethod
def available():
"""
:returns: whether the markup is ready for use
(for example, whether the required third-party
modules are importable)
:rtype: bool
"""
return True
def get_document_title(self, text):
"""
:returns: the document title
:rtype: str
"""
return ''
def get_document_body(self, text):
"""
:returns: the contents of the ```` HTML tag
:rtype: str
"""
raise NotImplementedError
def get_stylesheet(self, text=''):
"""
:returns: the contents of ``\n' if include_stylesheet else '')
title = self.get_document_title(text)
if not title:
title = fallback_title
title_string = ('' + title + '\n') if title else ''
javascript = self.get_javascript(text, webenv)
self._enable_cache = False
self._cache = {}
return (
'\n'
'\n\n'
'\n'
+ custom_headers + title_string + stylesheet + javascript
+ '\n\n' + body + '\n\n'
)
Markups-1.0.1/markups/common.py 0000644 0001750 0001750 00000001660 12602764711 017332 0 ustar dmitry dmitry 0000000 0000000 # This file is part of python-markups module
# License: BSD
# Copyright: (C) Dmitry Shachnev, 2012-2015
import os.path
# Some common constants and functions
(LANGUAGE_HOME_PAGE, MODULE_HOME_PAGE, SYNTAX_DOCUMENTATION) = range(3)
CONFIGURATION_DIR = (os.getenv('XDG_CONFIG_HOME') or os.getenv('APPDATA') or
os.path.expanduser('~/.config'))
MATHJAX_LOCAL_URL = 'file:///usr/share/javascript/mathjax/MathJax.js'
MATHJAX_WEB_URL = 'https://cdn.mathjax.org/mathjax/latest/MathJax.js'
PYGMENTS_STYLE = 'default'
def get_pygments_stylesheet(selector, style=None):
if style is None:
style = PYGMENTS_STYLE
if style == '':
return ''
try:
from pygments.formatters import HtmlFormatter
except ImportError:
return ''
else:
return HtmlFormatter(style=style).get_style_defs(selector) + '\n'
def get_mathjax_url(webenv):
if os.path.exists(MATHJAX_LOCAL_URL[7:]) and not webenv:
return MATHJAX_LOCAL_URL
else:
return MATHJAX_WEB_URL
Markups-1.0.1/markups/mdx_mathjax.py 0000644 0001750 0001750 00000004572 12633336576 020363 0 ustar dmitry dmitry 0000000 0000000 # This file is part of python-markups module
# License: BSD
# Copyright: (C) Dmitry Shachnev, 2015
# Maintained in https://github.com/mitya57/python-markdown-math
'''
Math extension for Python-Markdown
==================================
Adds support for displaying math formulas using [MathJax](http://www.mathjax.org/).
Author: 2015, Dmitry Shachnev .
'''
from __future__ import absolute_import
import markdown
class MathExtension(markdown.extensions.Extension):
def __init__(self, *args, **kwargs):
self.config = {
'enable_dollar_delimiter': [False, 'Enable single-dollar delimiter'],
}
super(MathExtension, self).__init__(*args, **kwargs)
def extendMarkdown(self, md, md_globals):
def handle_match_inline(m):
node = markdown.util.etree.Element('script')
node.set('type', 'math/tex')
node.text = markdown.util.AtomicString(m.group(3))
return node
def handle_match(m):
node = markdown.util.etree.Element('script')
node.set('type', 'math/tex; mode=display')
if '\\begin' in m.group(2):
node.text = markdown.util.AtomicString(m.group(2) + m.group(4) + m.group(5))
else:
node.text = markdown.util.AtomicString(m.group(3))
return node
inlinemathpatterns = (
markdown.inlinepatterns.Pattern(r'(?