aboutsummaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
authorSébastien Dailly <sebastien@chimrod.com>2021-01-04 13:40:21 +0100
committerSébastien Dailly <sebastien@chimrod.com>2021-01-05 11:06:20 +0100
commit1cad4c9044d47c6653d804d7fb58581d92f96cc8 (patch)
tree9696b75a4288976a00dbfc694090768ac93cdd14 /plugins
parent0c09a00a0b298cbd3bbd0082cc1026e22db9b1c5 (diff)
Change organisation
Diffstat (limited to 'plugins')
-rwxr-xr-xplugins/render_math/Readme.md167
-rw-r--r--[-rwxr-xr-x]plugins/render_math/__init__.py2
-rw-r--r--[-rwxr-xr-x]plugins/render_math/math.py252
-rw-r--r--[-rwxr-xr-x]plugins/render_math/mathjax_script_template0
-rw-r--r--[-rwxr-xr-x]plugins/render_math/pelican_mathjax_markdown_extension.py120
-rwxr-xr-xplugins/render_math/requirements.txt1
-rw-r--r--[-rwxr-xr-x]plugins/render_math/test_data/article_with_math_formulas.rst0
-rw-r--r--[-rwxr-xr-x]plugins/render_math/test_render_math.py28
-rw-r--r--plugins/render_math/version.py3
9 files changed, 257 insertions, 316 deletions
diff --git a/plugins/render_math/Readme.md b/plugins/render_math/Readme.md
deleted file mode 100755
index 7d541aa..0000000
--- a/plugins/render_math/Readme.md
+++ /dev/null
@@ -1,167 +0,0 @@
-Math Render Plugin For Pelican
-==============================
-
-**NOTE: [This plugin has been moved to its own repository](https://github.com/pelican-plugins/render-math). Please file any issues/PRs there. Once all plugins have been migrated to the [new Pelican Plugins organization](https://github.com/pelican-plugins), this monolithic repository will be archived.**
-
-This plugin gives pelican the ability to render mathematics. It accomplishes
-this by using the [MathJax](http://www.mathjax.org/) javascript engine.
-
-The plugin also ensures that Typogrify and recognized math "play" nicely together, by
-ensuring [Typogrify](https://github.com/mintchaos/typogrify) does not alter math content.
-
-Both Markdown and reStructuredText is supported.
-
-Requirements
-------------
-
- * Pelican version *3.6* or above is required.
- * Typogrify version *2.0.7* or higher is needed for Typogrify to play
- "nicely" with this plugin. If this version is not available, Typogrify
- will be disabled for the entire site.
- * BeautifulSoup4 is required to correct summaries. If BeautifulSoup4 is
- not installed, summary processing will be ignored, even if specified
- in user settings.
-
-Installation
-------------
-To enable, ensure that `render_math` plugin is accessible.
-Then add the following to settings.py:
-
- PLUGINS = ["render_math"]
-
-Your site is now capable of rendering math math using the mathjax JavaScript
-engine. No alterations to the template is needed, just use and enjoy!
-
-However, if you wish, you can set the `auto_insert` setting to `False` which
-will disable the mathjax script from being automatically inserted into the
-content. You would only want to do this if you had control over the template
-and wanted to insert the script manually.
-
-### Typogrify
-In the past, using [Typgogrify](https://github.com/mintchaos/typogrify) would
-alter the math contents resulting in math that could not be rendered by MathJax.
-The only option was to ensure that Typogrify was disabled in the settings.
-
-The problem has been rectified in this plugin, but it requires at a minimum
-[Typogrify version 2.0.7](https://pypi.python.org/pypi/typogrify) (or higher).
-If this version is not present, the plugin will disable Typogrify for the entire
-site.
-
-### BeautifulSoup4
-Pelican creates summaries by truncating the contents to a specified user length.
-The truncation process is oblivious to any math and can therefore destroy
-the math output in the summary.
-
-To restore math, [BeautifulSoup4](https://pypi.python.org/pypi/beautifulsoup4/4.4.0)
-is used. If it is not installed, no summary processing will happen.
-
-Usage
------
-### Templates
-No alteration is needed to a template for this plugin to work. Just install
-the plugin and start writing your Math.
-
-### Settings
-Certain MathJax rendering options can be set. These options
-are in a dictionary variable called `MATH_JAX` in the pelican
-settings file.
-
-The dictionary can be set with the following keys:
-
- * `align`: [string] controls how displayed math will be aligned. Can be set to either
-`'left'`, `'right'` or `'center'`. **Default Value**: `'center'`.
- * `auto_insert`: [boolean] will insert the mathjax script into content that it is
-detected to have math in it. Setting it to false is not recommended.
-**Default Value**: `True`
- * `indent`: [string] if `align` not set to `'center'`, then this controls the indent
-level. **Default Value**: `'0em'`.
- * `show_menu`: [boolean] controls whether the mathjax contextual menu is shown.
-**Default Value**: `True`
- * `process_escapes`: [boolean] controls whether mathjax processes escape sequences.
-**Default Value**: `True`
- * `mathjax_font`: [string] will force mathjax to use the chosen font. Current choices
-for the font is `sanserif`, `typewriter` or `fraktur`. If this is not set, it will
-use the default font settings. **Default Value**: `default`
- * `latex_preview`: [string] controls the preview message users are shown while mathjax is
-rendering LaTex. If set to `'Tex'`, then the TeX code is used as the preview
-(which will be visible until it is processed by MathJax). **Default Value**: `'Tex'`
- * `color`: [string] controls the color of the mathjax rendered font. **Default Value**: `'inherit'`
- * `linebreak_automatic`: [boolean] If set, Mathjax will try to *intelligently* break up displayed math
-(Note: It will not work for inline math). This is very useful for a responsive site. It
-is turned off by default due to it potentially being CPU expensive. **Default Value**: `False`
- * `tex_extensions`: [list] a list of [latex extensions](http://docs.mathjax.org/en/latest/tex.html#tex-and-latex-extensions)
-accepted by mathjax. **Default Value**: `[]` (empty list)
- * `responsive`: [boolean] tries to make displayed math render responsively. It does by determining if the width
-is less than `responsive_break` (see below) and if so, sets `align` to `left`, `indent` to `0em` and `linebreak_automatic` to `True`.
-**Default Value**: `False` (defaults to `False` for backward compatibility)
- * `responsive_break`: [integer] a number (in pixels) representing the width breakpoint that is used
-when setting `responsive_align` to `True`. **Default Value**: 768
- * `process_summary`: [boolean] ensures math will render in summaries and fixes math in that were cut off.
-Requires [BeautifulSoup4](http://www.crummy.com/software/BeautifulSoup/bs4/doc/) be installed. **Default Value**: `True`
- * `message_style`: [string] This value controls the verbosity of the messages in the lower left-hand corner. Set it to `None` to eliminate all messages.
-**Default Value**: normal
-
-#### Settings Examples
-Make math render in blue and displaymath align to the left:
-
- MATH_JAX = {'color':'blue','align':left}
-
-Use the [color](http://docs.mathjax.org/en/latest/tex.html#color) and
-[mhchem](http://docs.mathjax.org/en/latest/tex.html#mhchem) extensions:
-
- MATH_JAX = {'tex_extensions': ['color.js','mhchem.js']}
-
-#### Resulting HTML
-Inlined math is wrapped in `span` tags, while displayed math is wrapped in `div` tags.
-These tags will have a class attribute that is set to `math` which
-can be used by template designers to alter the display of the math.
-
-Markdown
---------
-This plugin implements a custom extension for markdown resulting in math
-being a "first class citizen" for Pelican.
-
-### Inlined Math
-Math between `$`..`$`, for example, `$`x^2`$`, will be rendered inline
-with respect to the current html block. Note: To use inline math, there
-must *not* be any whitespace before the ending `$`. So for example:
-
- * **Relevant inline math**: `$e=mc^2$`
- * **Will not render as inline math**: `$40 vs $50`
-
-### Displayed Math
-Math between `$$`..`$$` will be rendered "block style", for example, `$$`x^2`$$`, will be rendered centered in a
-new paragraph.
-
-#### Other Latex Display Math commands
-The other LaTeX commands which usually invoke display math mode from text mode
-are supported,
-and are automatically treated like `$$`-style displayed math
-in that they are rendered "block" style on their own lines.
-For example, `\begin{equation}` x^2 `\end{equation}`,
-will be rendered in its own block with a right justified equation number
-at the top of the block. This equation number can be referenced in the document.
-To do this, use a `label` inside of the equation format and then refer to that label
-using `ref`. For example: `\begin{equation}` `\label{eq}` X^2 `\end{equation}`.
-Now refer to that equation number by `$`\ref{eq}`$`.
-
-reStructuredText
-----------------
-If there is math detected in reStructuredText document, the plugin will automatically
-set the [math_output](http://docutils.sourceforge.net/docs/user/config.html#math-output) configuration setting to `MathJax`.
-
-### Inlined Math
-Inlined math needs to use the [math role](http://docutils.sourceforge.net/docs/ref/rst/roles.html#math):
-
-```
-The area of a circle is :math:`A_\text{c} = (\pi/4) d^2`.
-```
-
-### Displayed Math
-Displayed math uses the [math block](http://docutils.sourceforge.net/docs/ref/rst/directives.html#math):
-
-```
-.. math::
-
- α_t(i) = P(O_1, O_2, … O_t, q_t = S_i λ)
-```
diff --git a/plugins/render_math/__init__.py b/plugins/render_math/__init__.py
index 2ac15dd..513bf02 100755..100644
--- a/plugins/render_math/__init__.py
+++ b/plugins/render_math/__init__.py
@@ -1 +1 @@
-from .math import *
+from .math import * # NOQA
diff --git a/plugins/render_math/math.py b/plugins/render_math/math.py
index 165d59e..a189ba2 100755..100644
--- a/plugins/render_math/math.py
+++ b/plugins/render_math/math.py
@@ -19,7 +19,7 @@ into the HTML.
Typogrify Compatibility
-----------------------
This plugin now plays nicely with Typogrify, but it
-requires Typogrify version 2.07 or above.
+requires Typogrify version 2.0.7 or above.
User Settings
-------------
@@ -33,16 +33,16 @@ the math. See README for more details.
import os
import sys
-from pelican import signals, generators
+from pelican import generators, signals
try:
from bs4 import BeautifulSoup
-except ImportError as e:
+except ImportError:
BeautifulSoup = None
try:
- from . pelican_mathjax_markdown_extension import PelicanMathJaxExtension
-except ImportError as e:
+ from .pelican_mathjax_markdown_extension import PelicanMathJaxExtension
+except ImportError:
PelicanMathJaxExtension = None
try:
@@ -51,7 +51,7 @@ except NameError:
string_type = str
-def process_settings(pelicanobj):
+def process_settings(pelicanobj): # NOQA: C901
"""Sets user specified MathJax settings (see README for more details)"""
mathjax_settings = {}
@@ -62,30 +62,59 @@ def process_settings(pelicanobj):
# will be used for
# Default settings
- mathjax_settings['auto_insert'] = True # if set to true, it will insert mathjax script automatically into content without needing to alter the template.
- mathjax_settings['align'] = 'center' # controls alignment of of displayed equations (values can be: left, right, center)
- mathjax_settings['indent'] = '0em' # if above is not set to 'center', then this setting acts as an indent
- mathjax_settings['show_menu'] = 'true' # controls whether to attach mathjax contextual menu
- mathjax_settings['process_escapes'] = 'true' # controls whether escapes are processed
- mathjax_settings['latex_preview'] = 'TeX' # controls what user sees while waiting for LaTex to render
- mathjax_settings['color'] = 'inherit' # controls color math is rendered in
- mathjax_settings['linebreak_automatic'] = 'false' # Set to false by default for performance reasons (see http://docs.mathjax.org/en/latest/output.html#automatic-line-breaking)
- mathjax_settings['tex_extensions'] = '' # latex extensions that can be embedded inside mathjax (see http://docs.mathjax.org/en/latest/tex.html#tex-and-latex-extensions)
- mathjax_settings['responsive'] = 'false' # Tries to make displayed math responsive
- mathjax_settings['responsive_break'] = '768' # The break point at which it math is responsively aligned (in pixels)
- mathjax_settings['mathjax_font'] = 'default' # forces mathjax to use the specified font.
- mathjax_settings['process_summary'] = BeautifulSoup is not None # will fix up summaries if math is cut off. Requires beautiful soup
- mathjax_settings['message_style'] = 'normal' # This value controls the verbosity of the messages in the lower left-hand corner. Set it to "none" to eliminate all messages
- mathjax_settings['font_list'] = ['STIX', 'TeX'] # Include in order of preference among TeX, STIX-Web, Asana-Math, Neo-Euler, Gyre-Pagella, Gyre-Termes and Latin-Modern
- mathjax_settings['equation_numbering'] = 'none' # AMS, auto, none
+ mathjax_settings[
+ "auto_insert"
+ ] = True # if set to true, it will insert mathjax script automatically into content without needing to alter the template.
+ mathjax_settings[
+ "align"
+ ] = "center" # controls alignment of of displayed equations (values can be: left, right, center)
+ mathjax_settings[
+ "indent"
+ ] = "0em" # if above is not set to 'center', then this setting acts as an indent
+ mathjax_settings[
+ "show_menu"
+ ] = "true" # controls whether to attach mathjax contextual menu
+ mathjax_settings[
+ "process_escapes"
+ ] = "true" # controls whether escapes are processed
+ mathjax_settings[
+ "latex_preview"
+ ] = "TeX" # controls what user sees while waiting for LaTex to render
+ mathjax_settings["color"] = "inherit" # controls color math is rendered in
+ mathjax_settings[
+ "linebreak_automatic"
+ ] = "false" # Set to false by default for performance reasons (see http://docs.mathjax.org/en/latest/output.html#automatic-line-breaking)
+ mathjax_settings[
+ "tex_extensions"
+ ] = "" # latex extensions that can be embedded inside mathjax (see http://docs.mathjax.org/en/latest/tex.html#tex-and-latex-extensions)
+ mathjax_settings["responsive"] = "false" # Tries to make displayed math responsive
+ mathjax_settings[
+ "responsive_break"
+ ] = "768" # The break point at which it math is responsively aligned (in pixels)
+ mathjax_settings[
+ "mathjax_font"
+ ] = "default" # forces mathjax to use the specified font.
+ mathjax_settings["process_summary"] = (
+ BeautifulSoup is not None
+ ) # will fix up summaries if math is cut off. Requires beautiful soup
+ mathjax_settings[
+ "message_style"
+ ] = "normal" # This value controls the verbosity of the messages in the lower left-hand corner. Set it to "none" to eliminate all messages
+ mathjax_settings["font_list"] = [
+ "STIX",
+ "TeX",
+ ] # Include in order of preference among TeX, STIX-Web, Asana-Math, Neo-Euler, Gyre-Pagella, Gyre-Termes and Latin-Modern
+ mathjax_settings["equation_numbering"] = "none" # AMS, auto, none
# Source for MathJax
- mathjax_settings['source'] = "'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.3/latest.js?config=TeX-AMS-MML_HTMLorMML'"
+ mathjax_settings[
+ "source"
+ ] = "'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.3/latest.js?config=TeX-AMS-MML_HTMLorMML'"
# Get the user specified settings
- try:
- settings = pelicanobj.settings['MATH_JAX']
- except:
+ if "MATH_JAX" in pelicanobj.settings:
+ settings = pelicanobj.settings["MATH_JAX"]
+ else:
settings = None
# If no settings have been specified, then return the defaults
@@ -97,36 +126,36 @@ def process_settings(pelicanobj):
# Iterate over dictionary in a way that is compatible with both version 2
# and 3 of python
- if key == 'align':
+ if key == "align":
typeVal = isinstance(value, string_type)
if not typeVal:
continue
- if value == 'left' or value == 'right' or value == 'center':
+ if value == "left" or value == "right" or value == "center":
mathjax_settings[key] = value
else:
- mathjax_settings[key] = 'center'
+ mathjax_settings[key] = "center"
- if key == 'indent':
+ if key == "indent":
mathjax_settings[key] = value
- if key == 'source':
+ if key == "source":
mathjax_settings[key] = value
- if key == 'show_menu' and isinstance(value, bool):
- mathjax_settings[key] = 'true' if value else 'false'
+ if key == "show_menu" and isinstance(value, bool):
+ mathjax_settings[key] = "true" if value else "false"
- if key == 'message_style':
- mathjax_settings[key] = value if value is not None else 'none'
+ if key == "message_style":
+ mathjax_settings[key] = value if value is not None else "none"
- if key == 'auto_insert' and isinstance(value, bool):
+ if key == "auto_insert" and isinstance(value, bool):
mathjax_settings[key] = value
- if key == 'process_escapes' and isinstance(value, bool):
- mathjax_settings[key] = 'true' if value else 'false'
+ if key == "process_escapes" and isinstance(value, bool):
+ mathjax_settings[key] = "true" if value else "false"
- if key == 'latex_preview':
+ if key == "latex_preview":
typeVal = isinstance(value, string_type)
if not typeVal:
@@ -134,7 +163,7 @@ def process_settings(pelicanobj):
mathjax_settings[key] = value
- if key == 'color':
+ if key == "color":
typeVal = isinstance(value, string_type)
if not typeVal:
@@ -142,29 +171,31 @@ def process_settings(pelicanobj):
mathjax_settings[key] = value
- if key == 'linebreak_automatic' and isinstance(value, bool):
- mathjax_settings[key] = 'true' if value else 'false'
+ if key == "linebreak_automatic" and isinstance(value, bool):
+ mathjax_settings[key] = "true" if value else "false"
- if key == 'process_summary' and isinstance(value, bool):
+ if key == "process_summary" and isinstance(value, bool):
if value and BeautifulSoup is None:
- print("BeautifulSoup4 is needed for summaries to be processed by render_math\nPlease install it")
+ print(
+ "BeautifulSoup4 is needed for summaries to be processed by render_math\nPlease install it"
+ )
value = False
mathjax_settings[key] = value
- if key == 'responsive' and isinstance(value, bool):
- mathjax_settings[key] = 'true' if value else 'false'
+ if key == "responsive" and isinstance(value, bool):
+ mathjax_settings[key] = "true" if value else "false"
- if key == 'responsive_break' and isinstance(value, int):
+ if key == "responsive_break" and isinstance(value, int):
mathjax_settings[key] = str(value)
- if key == 'tex_extensions' and isinstance(value, list):
+ if key == "tex_extensions" and isinstance(value, list):
# filter string values, then add '' to them
value = filter(lambda string: isinstance(string, string_type), value)
value = map(lambda string: "'%s'" % string, value)
- mathjax_settings[key] = ',' + ','.join(value)
+ mathjax_settings[key] = "," + ",".join(value)
- if key == 'mathjax_font':
+ if key == "mathjax_font":
typeVal = isinstance(value, string_type)
if not typeVal:
@@ -172,66 +203,73 @@ def process_settings(pelicanobj):
value = value.lower()
- if value == 'sanserif':
- value = 'SansSerif'
- elif value == 'fraktur':
- value = 'Fraktur'
- elif value == 'typewriter':
- value = 'Typewriter'
+ if value == "sanserif":
+ value = "SansSerif"
+ elif value == "fraktur":
+ value = "Fraktur"
+ elif value == "typewriter":
+ value = "Typewriter"
else:
- value = 'default'
+ value = "default"
mathjax_settings[key] = value
- if key == 'font_list' and isinstance(value, list):
+ if key == "font_list" and isinstance(value, list):
# make an array string from the list
value = filter(lambda string: isinstance(string, string_type), value)
value = map(lambda string: ",'%s'" % string, value)
- mathjax_settings[key] = ''.join(value)[1:]
+ mathjax_settings[key] = "".join(value)[1:]
- if key == 'equation_numbering':
- mathjax_settings[key] = value if value is not None else 'none'
+ if key == "equation_numbering":
+ mathjax_settings[key] = value if value is not None else "none"
return mathjax_settings
+
def process_summary(article):
"""Ensures summaries are not cut off. Also inserts
mathjax script so that math will be rendered"""
summary = article.summary
- summary_parsed = BeautifulSoup(summary, 'html.parser')
- math = summary_parsed.find_all(class_='math')
+ summary_parsed = BeautifulSoup(summary, "html.parser")
+ math = summary_parsed.find_all(class_="math")
if len(math) > 0:
last_math_text = math[-1].get_text()
- if len(last_math_text) > 3 and last_math_text[-3:] == '...':
- content_parsed = BeautifulSoup(article._content, 'html.parser')
- full_text = content_parsed.find_all(class_='math')[len(math)-1].get_text()
+ if len(last_math_text) > 3 and last_math_text[-3:] == "...":
+ content_parsed = BeautifulSoup(article._content, "html.parser")
+ full_text = content_parsed.find_all(class_="math")[len(math) - 1].get_text()
math[-1].string = "%s ..." % full_text
summary = summary_parsed.decode()
# clear memoization cache
import functools
+
if isinstance(article.get_summary, functools.partial):
memoize_instance = article.get_summary.func.__self__
memoize_instance.cache.clear()
- article._summary = "%s<script type='text/javascript'>%s</script>" % (summary, process_summary.mathjax_script)
+ article.metadata["summary"] = "%s<script type='text/javascript'>%s</script>" % (
+ summary,
+ process_summary.mathjax_script,
+ )
+
def configure_typogrify(pelicanobj, mathjax_settings):
"""Instructs Typogrify to ignore math tags - which allows Typogrify
to play nicely with math related content"""
# If Typogrify is not being used, then just exit
- if not pelicanobj.settings.get('TYPOGRIFY', False):
+ if not pelicanobj.settings.get("TYPOGRIFY", False):
return
try:
- import typogrify
from distutils.version import LooseVersion
- if LooseVersion(typogrify.__version__) < LooseVersion('2.0.7'):
- raise TypeError('Incorrect version of Typogrify')
+ import typogrify
+
+ if LooseVersion(typogrify.__version__) < LooseVersion("2.0.7"):
+ raise TypeError("Incorrect version of Typogrify")
from typogrify.filters import typogrify
@@ -239,55 +277,74 @@ def configure_typogrify(pelicanobj, mathjax_settings):
# it is installed and it is a recent enough version
# that can be used to ignore all math
# Instantiate markdown extension and append it to the current extensions
- pelicanobj.settings['TYPOGRIFY_IGNORE_TAGS'].extend(['.math', 'script']) # ignore math class and script
+ pelicanobj.settings["TYPOGRIFY_IGNORE_TAGS"].extend(
+ [".math", "script"]
+ ) # ignore math class and script
except (ImportError, TypeError) as e:
- pelicanobj.settings['TYPOGRIFY'] = False # disable Typogrify
+ pelicanobj.settings["TYPOGRIFY"] = False # disable Typogrify
if isinstance(e, ImportError):
- print("\nTypogrify is not installed, so it is being ignored.\nIf you want to use it, please install via: pip install typogrify\n")
+ print(
+ "\nTypogrify is not installed, so it is being ignored.\nIf you want to use it, please install via: pip install typogrify\n"
+ )
if isinstance(e, TypeError):
- print("\nA more recent version of Typogrify is needed for the render_math module.\nPlease upgrade Typogrify to the latest version (anything equal or above version 2.0.7 is okay).\nTypogrify will be turned off due to this reason.\n")
+ print(
+ "\nA more recent version of Typogrify is needed for the render_math module.\nPlease upgrade Typogrify to the latest version (anything equal or above version 2.0.7 is okay).\nTypogrify will be turned off due to this reason.\n"
+ )
+
def process_mathjax_script(mathjax_settings):
"""Load the mathjax script template from file, and render with the settings"""
# Read the mathjax javascript template from file
- with open (os.path.dirname(os.path.realpath(__file__))
- + '/mathjax_script_template', 'r') as mathjax_script_template:
+ with open(
+ os.path.dirname(os.path.realpath(__file__)) + "/mathjax_script_template", "r"
+ ) as mathjax_script_template:
mathjax_template = mathjax_script_template.read()
return mathjax_template.format(**mathjax_settings)
+
def mathjax_for_markdown(pelicanobj, mathjax_script, mathjax_settings):
"""Instantiates a customized markdown extension for handling mathjax
related content"""
# Create the configuration for the markdown template
config = {}
- config['mathjax_script'] = mathjax_script
- config['math_tag_class'] = 'math'
- config['auto_insert'] = mathjax_settings['auto_insert']
+ config["mathjax_script"] = mathjax_script
+ config["math_tag_class"] = "math"
+ config["auto_insert"] = mathjax_settings["auto_insert"]
# Instantiate markdown extension and append it to the current extensions
try:
- if isinstance(pelicanobj.settings.get('MD_EXTENSIONS'), list): # pelican 3.6.3 and earlier
- pelicanobj.settings['MD_EXTENSIONS'].append(PelicanMathJaxExtension(config))
+ if isinstance(
+ pelicanobj.settings.get("MD_EXTENSIONS"), list
+ ): # pelican 3.6.3 and earlier
+ pelicanobj.settings["MD_EXTENSIONS"].append(PelicanMathJaxExtension(config))
else:
- pelicanobj.settings['MARKDOWN'].setdefault('extensions', []).append(PelicanMathJaxExtension(config))
- except:
+ pelicanobj.settings["MARKDOWN"].setdefault("extensions", []).append(
+ PelicanMathJaxExtension(config)
+ )
+ except: # NOQA E722
sys.excepthook(*sys.exc_info())
- sys.stderr.write("\nError - the pelican mathjax markdown extension failed to configure. MathJax is non-functional.\n")
+ sys.stderr.write(
+ "\nError - the pelican mathjax markdown extension failed to configure. MathJax is non-functional.\n"
+ )
sys.stderr.flush()
+
def mathjax_for_rst(pelicanobj, mathjax_script, mathjax_settings):
"""Setup math for RST"""
- docutils_settings = pelicanobj.settings.get('DOCUTILS_SETTINGS', {})
- docutils_settings.setdefault('math_output', 'MathJax %s' % mathjax_settings['source'])
- pelicanobj.settings['DOCUTILS_SETTINGS'] = docutils_settings
+ docutils_settings = pelicanobj.settings.get("DOCUTILS_SETTINGS", {})
+ docutils_settings.setdefault(
+ "math_output", "MathJax %s" % mathjax_settings["source"]
+ )
+ pelicanobj.settings["DOCUTILS_SETTINGS"] = docutils_settings
rst_add_mathjax.mathjax_script = mathjax_script
+
def pelican_init(pelicanobj):
"""
Loads the mathjax script according to the settings.
@@ -313,21 +370,26 @@ def pelican_init(pelicanobj):
# Set process_summary's mathjax_script variable
process_summary.mathjax_script = None
- if mathjax_settings['process_summary']:
+ if mathjax_settings["process_summary"]:
process_summary.mathjax_script = mathjax_script
+
def rst_add_mathjax(content):
"""Adds mathjax script for reStructuredText"""
# .rst is the only valid extension for reStructuredText files
_, ext = os.path.splitext(os.path.basename(content.source_path))
- if ext != '.rst':
+ if ext != ".rst":
return
# If math class is present in text, add the javascript
# note that RST hardwires mathjax to be class "math"
if 'class="math"' in content._content:
- content._content += "<script type='text/javascript'>%s</script>" % rst_add_mathjax.mathjax_script
+ content._content += (
+ "<script type='text/javascript'>%s</script>"
+ % rst_add_mathjax.mathjax_script
+ )
+
def process_rst_and_summaries(content_generators):
"""
@@ -348,11 +410,10 @@ def process_rst_and_summaries(content_generators):
for generator in content_generators:
if isinstance(generator, generators.ArticlesGenerator):
for article in (
- generator.articles +
- generator.translations +
- generator.drafts):
+ generator.articles + generator.translations + generator.drafts
+ ):
rst_add_mathjax(article)
- #optionally fix truncated formulae in summaries.
+ # optionally fix truncated formulae in summaries.
if process_summary.mathjax_script is not None:
process_summary(article)
elif isinstance(generator, generators.PagesGenerator):
@@ -361,6 +422,7 @@ def process_rst_and_summaries(content_generators):
for page in generator.hidden_pages:
rst_add_mathjax(page)
+
def register():
"""Plugin registration"""
signals.initialized.connect(pelican_init)
diff --git a/plugins/render_math/mathjax_script_template b/plugins/render_math/mathjax_script_template
index db8aeba..db8aeba 100755..100644
--- a/plugins/render_math/mathjax_script_template
+++ b/plugins/render_math/mathjax_script_template
diff --git a/plugins/render_math/pelican_mathjax_markdown_extension.py b/plugins/render_math/pelican_mathjax_markdown_extension.py
index e739363..77e0593 100755..100644
--- a/plugins/render_math/pelican_mathjax_markdown_extension.py
+++ b/plugins/render_math/pelican_mathjax_markdown_extension.py
@@ -8,33 +8,35 @@ gives Pelican the ability to use Mathjax as a "first class
citizen" of the blog
"""
-import markdown
+from xml.etree.ElementTree import Element
-from markdown.util import etree
+import markdown
from markdown.util import AtomicString
+
class PelicanMathJaxPattern(markdown.inlinepatterns.Pattern):
"""Inline markdown processing that matches mathjax"""
def __init__(self, pelican_mathjax_extension, tag, pattern):
- super(PelicanMathJaxPattern,self).__init__(pattern)
- self.math_tag_class = pelican_mathjax_extension.getConfig('math_tag_class')
+ super(PelicanMathJaxPattern, self).__init__(pattern)
+ self.math_tag_class = pelican_mathjax_extension.getConfig("math_tag_class")
self.pelican_mathjax_extension = pelican_mathjax_extension
self.tag = tag
def handleMatch(self, m):
- node = markdown.util.etree.Element(self.tag)
- node.set('class', self.math_tag_class)
+ node = Element(self.tag)
+ node.set("class", self.math_tag_class)
- prefix = '\\(' if m.group('prefix') == '$' else m.group('prefix')
- suffix = '\\)' if m.group('suffix') == '$' else m.group('suffix')
- node.text = markdown.util.AtomicString(prefix + m.group('math') + suffix)
+ prefix = "\\(" if m.group("prefix") == "$" else m.group("prefix")
+ suffix = "\\)" if m.group("suffix") == "$" else m.group("suffix")
+ node.text = markdown.util.AtomicString(prefix + m.group("math") + suffix)
# If mathjax was successfully matched, then JavaScript needs to be added
# for rendering. The boolean below indicates this
self.pelican_mathjax_extension.mathjax_needed = True
return node
+
class PelicanMathJaxCorrectDisplayMath(markdown.treeprocessors.Treeprocessor):
"""Corrects invalid html that results from a <div> being put inside
a <p> for displayed math"""
@@ -49,22 +51,22 @@ class PelicanMathJaxCorrectDisplayMath(markdown.treeprocessors.Treeprocessor):
current_idx = 0
for idx in div_math:
- el = markdown.util.etree.Element('p')
+ el = Element("p")
el.text = text
el.extend(children[current_idx:idx])
- # Test to ensure that empty <p> is not inserted
+ # Test to ensure that empty <p> is not inserted
if len(el) != 0 or (el.text and not el.text.isspace()):
- root.insert(insert_idx, el)
- insert_idx += 1
+ root.insert(insert_idx, el)
+ insert_idx += 1
text = children[idx].tail
children[idx].tail = None
root.insert(insert_idx, children[idx])
insert_idx += 1
- current_idx = idx+1
+ current_idx = idx + 1
- el = markdown.util.etree.Element('p')
+ el = Element("p")
el.text = text
el.extend(children[current_idx:])
@@ -75,14 +77,14 @@ class PelicanMathJaxCorrectDisplayMath(markdown.treeprocessors.Treeprocessor):
"""Searches for <div class="math"> that are children in <p> tags and corrects
the invalid HTML that results"""
- math_tag_class = self.pelican_mathjax_extension.getConfig('math_tag_class')
+ math_tag_class = self.pelican_mathjax_extension.getConfig("math_tag_class")
for parent in root:
div_math = []
children = list(parent)
- for div in parent.findall('div'):
- if div.get('class') == math_tag_class:
+ for div in parent.findall("div"):
+ if div.get("class") == math_tag_class:
div_math.append(children.index(div))
# Do not process further if no displayed math has been found
@@ -90,11 +92,14 @@ class PelicanMathJaxCorrectDisplayMath(markdown.treeprocessors.Treeprocessor):
continue
insert_idx = list(root).index(parent)
- self.correct_html(root, children, div_math, insert_idx, parent.text)
- root.remove(parent) # Parent must be removed last for correct insertion index
+ self.correct_html(root, children, div_math, insert_idx, parent.text)
+ root.remove(
+ parent
+ ) # Parent must be removed last for correct insertion index
return root
+
class PelicanMathJaxAddJavaScript(markdown.treeprocessors.Treeprocessor):
"""Tree Processor for adding Mathjax JavaScript to the blog"""
@@ -103,13 +108,15 @@ class PelicanMathJaxAddJavaScript(markdown.treeprocessors.Treeprocessor):
def run(self, root):
# If no mathjax was present, then exit
- if (not self.pelican_mathjax_extension.mathjax_needed):
+ if not self.pelican_mathjax_extension.mathjax_needed:
return root
# Add the mathjax script to the html document
- mathjax_script = etree.Element('script')
- mathjax_script.set('type','text/javascript')
- mathjax_script.text = AtomicString(self.pelican_mathjax_extension.getConfig('mathjax_script'))
+ mathjax_script = Element("script")
+ mathjax_script.set("type", "text/javascript")
+ mathjax_script.text = AtomicString(
+ self.pelican_mathjax_extension.getConfig("mathjax_script")
+ )
root.append(mathjax_script)
# Reset the boolean switch to false so that script is only added
@@ -117,22 +124,39 @@ class PelicanMathJaxAddJavaScript(markdown.treeprocessors.Treeprocessor):
self.pelican_mathjax_extension.mathjax_needed = False
return root
+
class PelicanMathJaxExtension(markdown.Extension):
"""A markdown extension enabling mathjax processing in Markdown for Pelican"""
+
def __init__(self, config):
try:
# Needed for markdown versions >= 2.5
- self.config['mathjax_script'] = ['', 'Mathjax JavaScript script']
- self.config['math_tag_class'] = ['math', 'The class of the tag in which mathematics is wrapped']
- self.config['auto_insert'] = [True, 'Determines if mathjax script is automatically inserted into content']
- super(PelicanMathJaxExtension,self).__init__(**config)
+ self.config["mathjax_script"] = ["", "Mathjax JavaScript script"]
+ self.config["math_tag_class"] = [
+ "math",
+ "The class of the tag in which mathematics is wrapped",
+ ]
+ self.config["auto_insert"] = [
+ True,
+ "Determines if mathjax script is automatically inserted into content",
+ ]
+ super(PelicanMathJaxExtension, self).__init__(**config)
except AttributeError:
# Markdown versions < 2.5
- config['mathjax_script'] = [config['mathjax_script'], 'Mathjax JavaScript script']
- config['math_tag_class'] = [config['math_tag_class'], 'The class of the tag in which mathematic is wrapped']
- config['auto_insert'] = [config['auto_insert'], 'Determines if mathjax script is automatically inserted into content']
- super(PelicanMathJaxExtension,self).__init__(config)
+ config["mathjax_script"] = [
+ config["mathjax_script"],
+ "Mathjax JavaScript script",
+ ]
+ config["math_tag_class"] = [
+ config["math_tag_class"],
+ "The class of the tag in which mathematic is wrapped",
+ ]
+ config["auto_insert"] = [
+ config["auto_insert"],
+ "Determines if mathjax script is automatically inserted into content",
+ ]
+ super(PelicanMathJaxExtension, self).__init__(config)
# Used as a flag to determine if javascript
# needs to be injected into a document
@@ -140,19 +164,33 @@ class PelicanMathJaxExtension(markdown.Extension):
def extendMarkdown(self, md):
# Regex to detect mathjax
- mathjax_inline_regex = r'(?P<prefix>\$)(?P<math>.+?)(?P<suffix>(?<!\s)\2)'
- mathjax_display_regex = r'(?P<prefix>\$\$|\\begin\{(.+?)\})(?P<math>.+?)(?P<suffix>\2|\\end\{\3\})'
+ mathjax_inline_regex = r"(?P<prefix>\$)(?P<math>.+?)(?P<suffix>(?<!\s)\2)"
+ mathjax_display_regex = (
+ r"(?P<prefix>\$\$|\\begin\{(.+?)\})(?P<math>.+?)(?P<suffix>\2|\\end\{\3\})"
+ )
# Process mathjax before escapes are processed since escape processing will
# intefer with mathjax. The order in which the displayed and inlined math
# is registered below matters: we should have higher priority than 'escape' which has 180
- md.inlinePatterns.register(PelicanMathJaxPattern(self, 'div', mathjax_display_regex), 'mathjax_displayed', 186)
- md.inlinePatterns.register(PelicanMathJaxPattern(self, 'span', mathjax_inline_regex), 'mathjax_inlined', 185)
-
- # Correct the invalid HTML that results from teh displayed math (<div> tag within a <p> tag)
- md.treeprocessors.register(PelicanMathJaxCorrectDisplayMath(self), 'mathjax_correctdisplayedmath', 15)
+ md.inlinePatterns.register(
+ PelicanMathJaxPattern(self, "div", mathjax_display_regex),
+ "mathjax_displayed",
+ 186,
+ )
+ md.inlinePatterns.register(
+ PelicanMathJaxPattern(self, "span", mathjax_inline_regex),
+ "mathjax_inlined",
+ 185,
+ )
+
+ # Correct the invalid HTML that results from teh displayed math (<div> tag within a <p> tag)
+ md.treeprocessors.register(
+ PelicanMathJaxCorrectDisplayMath(self), "mathjax_correctdisplayedmath", 15
+ )
# If necessary, add the JavaScript Mathjax library to the document. This must
# be last in the ordered dict (hence it is given the position '_end')
- if self.getConfig('auto_insert'):
- md.treeprocessors.register(PelicanMathJaxAddJavaScript(self), 'mathjax_addjavascript', 0)
+ if self.getConfig("auto_insert"):
+ md.treeprocessors.register(
+ PelicanMathJaxAddJavaScript(self), "mathjax_addjavascript", 0
+ )
diff --git a/plugins/render_math/requirements.txt b/plugins/render_math/requirements.txt
deleted file mode 100755
index be64ec9..0000000
--- a/plugins/render_math/requirements.txt
+++ /dev/null
@@ -1 +0,0 @@
-typogrify
diff --git a/plugins/render_math/test_data/article_with_math_formulas.rst b/plugins/render_math/test_data/article_with_math_formulas.rst
index 87dcc45..87dcc45 100755..100644
--- a/plugins/render_math/test_data/article_with_math_formulas.rst
+++ b/plugins/render_math/test_data/article_with_math_formulas.rst
diff --git a/plugins/render_math/test_render_math.py b/plugins/render_math/test_render_math.py
index b71f4e7..dc1e5fd 100755..100644
--- a/plugins/render_math/test_render_math.py
+++ b/plugins/render_math/test_render_math.py
@@ -10,22 +10,22 @@ from pelican.writers import Writer
from .math import pelican_init, process_rst_and_summaries
-
CUR_DIR = dirname(__file__)
class RenderMathTest(unittest.TestCase):
def test_ok_on_shared_test_data(self):
settings = get_settings(filenames={})
- settings['PATH'] = join(CUR_DIR, '..', 'test_data')
+ settings["PATH"] = join(CUR_DIR, "..", "test_data")
pelican_init(PelicanMock(settings))
with TemporaryDirectory() as tmpdirname:
generator = _build_article_generator(settings, tmpdirname)
process_rst_and_summaries([generator])
+
def test_ok_on_custom_data(self):
settings = get_settings(filenames={})
- settings['PATH'] = join(CUR_DIR, 'test_data')
- settings['PLUGINS'] = ['pelican-ipynb.markup'] # to also parse .ipynb files
+ settings["PATH"] = join(CUR_DIR, "test_data")
+ settings["PLUGINS"] = ["pelican-ipynb.markup"] # to also parse .ipynb files
configure_settings(settings)
pelican_mock = PelicanMock(settings)
pelican_init(pelican_mock)
@@ -34,23 +34,29 @@ class RenderMathTest(unittest.TestCase):
generator = _build_article_generator(settings, tmpdirname)
process_rst_and_summaries([generator])
for article in generator.articles:
- if article.source_path.endswith('.rst'):
- self.assertIn('mathjaxscript_pelican', article.content)
+ if article.source_path.endswith(".rst"):
+ self.assertIn("mathjaxscript_pelican", article.content)
generator.generate_output(Writer(tmpdirname, settings=settings))
def _build_article_generator(settings, output_path):
context = settings.copy()
- context['generated_content'] = dict()
- context['static_links'] = set()
+ context["generated_content"] = dict()
+ context["static_links"] = set()
article_generator = ArticlesGenerator(
- context=context, settings=settings,
- path=settings['PATH'], theme=settings['THEME'], output_path=output_path)
+ context=context,
+ settings=settings,
+ path=settings["PATH"],
+ theme=settings["THEME"],
+ output_path=output_path,
+ )
article_generator.generate_context()
return article_generator
+
class PelicanMock:
- 'A dummy class exposing the only attributes needed'
+ "A dummy class exposing the only attributes needed"
+
def __init__(self, settings):
self.plugins = []
self.settings = settings
diff --git a/plugins/render_math/version.py b/plugins/render_math/version.py
new file mode 100644
index 0000000..0c86483
--- /dev/null
+++ b/plugins/render_math/version.py
@@ -0,0 +1,3 @@
+#!/usr/bin/env python
+
+__version__ = "1.0.3"