├── .github └── workflows │ └── test.yml ├── .gitignore ├── AUTHORS ├── LICENSE ├── MANIFEST.in ├── README.md ├── dev-requirements.txt ├── docs ├── Makefile ├── _static │ ├── logo.png │ └── logo.svg ├── _themes │ ├── .gitignore │ ├── LICENSE │ ├── README │ ├── flask │ │ ├── layout.html │ │ ├── relations.html │ │ ├── static │ │ │ ├── flasky.css_t │ │ │ └── small_flask.css │ │ └── theme.conf │ ├── flask_small │ │ ├── layout.html │ │ ├── static │ │ │ └── flasky.css_t │ │ └── theme.conf │ └── flask_theme_support.py ├── conf.py ├── index.rst └── make.bat ├── flask_misaka.py ├── requirements.txt ├── setup.py └── tests.py /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | on: 3 | pull_request: 4 | branches: 5 | - main 6 | push: 7 | branches: 8 | - main 9 | 10 | jobs: 11 | pytest: 12 | runs-on: ubuntu-latest 13 | strategy: 14 | matrix: 15 | python-version: ["3.x"] 16 | name: "pytest: Python ${{ matrix.python-version }}" 17 | 18 | steps: 19 | - uses: actions/checkout@v2 20 | - uses: actions/setup-python@v2 21 | with: 22 | python-version: ${{ matrix.python-version }} 23 | 24 | - name: Install setuptools 25 | run: pip install setuptools 26 | 27 | - name: Install dependencies 28 | run: >- 29 | pip install 30 | -r requirements.txt 31 | -r dev-requirements.txt 32 | 33 | - name: Run tests 34 | run: coverage run --source=flask_misaka setup.py test 35 | 36 | - name: Upload coverage to Codecov 37 | if: ${{ always() }} 38 | uses: codecov/codecov-action@v1 39 | with: 40 | fail_ci_if_error: false 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.DS_Store 3 | .Python 4 | *.egg 5 | *.eggs 6 | *.egg-info 7 | .coverage 8 | bin 9 | build 10 | dist 11 | docs/_build 12 | include 13 | lib 14 | man 15 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | David Baumgold 2 | Jesse Spangenberger 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012-2021 David Baumgold 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE tests.py 2 | recursive-include docs * 3 | recursive-exclude docs *.pyc 4 | recursive-exclude docs *.pyo 5 | recursive-exclude docs *.DS_Store 6 | prune docs/_build 7 | prune docs/_themes/.git -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Flask-Misaka 2 | 3 | ![Build Status](https://github.com/singingwolfboy/flask-misaka/workflows/Test/badge.svg) [![Coverage Status](http://codecov.io/github/singingwolfboy/flask-misaka/coverage.svg?branch=master)](http://codecov.io/github/singingwolfboy/flask-misaka?branch=master) [![Documentation Status](https://readthedocs.org/projects/flask-misaka/badge/?version=latest)](http://flask-misaka.readthedocs.org/en/latest/?badge=latest) 4 | 5 | A simple Flask extension to integrate the [Misaka](http://misaka.61924.nl) 6 | module, which is a Python interface to the excellent 7 | [Hoedown](https://github.com/hoedown/hoedown) markdown-parsing library. 8 | Check the [Misaka changelog](http://misaka.61924.nl/changelog.html) 9 | to keep up with new features. 10 | 11 | The full documentation for this project is built using Sphinx; you can also 12 | check out [a pre-built version hosted on RTD](https://flask-misaka.readthedocs.org/en/latest/). 13 | -------------------------------------------------------------------------------- /dev-requirements.txt: -------------------------------------------------------------------------------- 1 | Flask>=0.7 2 | coverage 3 | mock; python_version < '3.3' 4 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # Internal variables. 11 | PAPEROPT_a4 = -D latex_paper_size=a4 12 | PAPEROPT_letter = -D latex_paper_size=letter 13 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 14 | # the i18n builder cannot share the environment and doctrees with the others 15 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 16 | 17 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext 18 | 19 | help: 20 | @echo "Please use \`make ' where is one of" 21 | @echo " html to make standalone HTML files" 22 | @echo " dirhtml to make HTML files named index.html in directories" 23 | @echo " singlehtml to make a single large HTML file" 24 | @echo " pickle to make pickle files" 25 | @echo " json to make JSON files" 26 | @echo " htmlhelp to make HTML files and a HTML help project" 27 | @echo " qthelp to make HTML files and a qthelp project" 28 | @echo " devhelp to make HTML files and a Devhelp project" 29 | @echo " epub to make an epub" 30 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 31 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 32 | @echo " text to make text files" 33 | @echo " man to make manual pages" 34 | @echo " texinfo to make Texinfo files" 35 | @echo " info to make Texinfo files and run them through makeinfo" 36 | @echo " gettext to make PO message catalogs" 37 | @echo " changes to make an overview of all changed/added/deprecated items" 38 | @echo " linkcheck to check all external links for integrity" 39 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 40 | 41 | clean: 42 | -rm -rf $(BUILDDIR)/* 43 | 44 | html: 45 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 46 | @echo 47 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 48 | 49 | dirhtml: 50 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 51 | @echo 52 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 53 | 54 | singlehtml: 55 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 56 | @echo 57 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 58 | 59 | pickle: 60 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 61 | @echo 62 | @echo "Build finished; now you can process the pickle files." 63 | 64 | json: 65 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 66 | @echo 67 | @echo "Build finished; now you can process the JSON files." 68 | 69 | htmlhelp: 70 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 71 | @echo 72 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 73 | ".hhp project file in $(BUILDDIR)/htmlhelp." 74 | 75 | qthelp: 76 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 77 | @echo 78 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 79 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 80 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Flask-Misaka.qhcp" 81 | @echo "To view the help file:" 82 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Flask-Misaka.qhc" 83 | 84 | devhelp: 85 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 86 | @echo 87 | @echo "Build finished." 88 | @echo "To view the help file:" 89 | @echo "# mkdir -p $$HOME/.local/share/devhelp/Flask-Misaka" 90 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Flask-Misaka" 91 | @echo "# devhelp" 92 | 93 | epub: 94 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 95 | @echo 96 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 97 | 98 | latex: 99 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 100 | @echo 101 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 102 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 103 | "(use \`make latexpdf' here to do that automatically)." 104 | 105 | latexpdf: 106 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 107 | @echo "Running LaTeX files through pdflatex..." 108 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 109 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 110 | 111 | text: 112 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 113 | @echo 114 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 115 | 116 | man: 117 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 118 | @echo 119 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 120 | 121 | texinfo: 122 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 123 | @echo 124 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 125 | @echo "Run \`make' in that directory to run these through makeinfo" \ 126 | "(use \`make info' here to do that automatically)." 127 | 128 | info: 129 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 130 | @echo "Running Texinfo files through makeinfo..." 131 | make -C $(BUILDDIR)/texinfo info 132 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 133 | 134 | gettext: 135 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 136 | @echo 137 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 138 | 139 | changes: 140 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 141 | @echo 142 | @echo "The overview file is in $(BUILDDIR)/changes." 143 | 144 | linkcheck: 145 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 146 | @echo 147 | @echo "Link check complete; look for any errors in the above output " \ 148 | "or in $(BUILDDIR)/linkcheck/output.txt." 149 | 150 | doctest: 151 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 152 | @echo "Testing of doctests in the sources finished, look at the " \ 153 | "results in $(BUILDDIR)/doctest/output.txt." 154 | -------------------------------------------------------------------------------- /docs/_static/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/singingwolfboy/flask-misaka/f804c05afb8633b9953faef788025377515c2553/docs/_static/logo.png -------------------------------------------------------------------------------- /docs/_themes/.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.pyo 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /docs/_themes/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010 by Armin Ronacher. 2 | 3 | Some rights reserved. 4 | 5 | Redistribution and use in source and binary forms of the theme, with or 6 | without modification, are permitted provided that the following conditions 7 | are met: 8 | 9 | * Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above 13 | copyright notice, this list of conditions and the following 14 | disclaimer in the documentation and/or other materials provided 15 | with the distribution. 16 | 17 | * The names of the contributors may not be used to endorse or 18 | promote products derived from this software without specific 19 | prior written permission. 20 | 21 | We kindly ask you to only use these themes in an unmodified manner just 22 | for Flask and Flask-related products, not for unrelated projects. If you 23 | like the visual style and want to use it for your own projects, please 24 | consider making some larger changes to the themes (such as changing 25 | font faces, sizes, colors or margins). 26 | 27 | THIS THEME IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 28 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 31 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 | ARISING IN ANY WAY OUT OF THE USE OF THIS THEME, EVEN IF ADVISED OF THE 37 | POSSIBILITY OF SUCH DAMAGE. 38 | -------------------------------------------------------------------------------- /docs/_themes/README: -------------------------------------------------------------------------------- 1 | Flask Sphinx Styles 2 | =================== 3 | 4 | This repository contains sphinx styles for Flask and Flask related 5 | projects. To use this style in your Sphinx documentation, follow 6 | this guide: 7 | 8 | 1. put this folder as _themes into your docs folder. Alternatively 9 | you can also use git submodules to check out the contents there. 10 | 2. add this to your conf.py: 11 | 12 | sys.path.append(os.path.abspath('_themes')) 13 | html_theme_path = ['_themes'] 14 | html_theme = 'flask' 15 | 16 | The following themes exist: 17 | 18 | - 'flask' - the standard flask documentation theme for large 19 | projects 20 | - 'flask_small' - small one-page theme. Intended to be used by 21 | very small addon libraries for flask. 22 | 23 | The following options exist for the flask_small theme: 24 | 25 | [options] 26 | index_logo = '' filename of a picture in _static 27 | to be used as replacement for the 28 | h1 in the index.rst file. 29 | index_logo_height = 120px height of the index logo 30 | github_fork = '' repository name on github for the 31 | "fork me" badge 32 | -------------------------------------------------------------------------------- /docs/_themes/flask/layout.html: -------------------------------------------------------------------------------- 1 | {%- extends "basic/layout.html" %} 2 | {%- block extrahead %} 3 | {{ super() }} 4 | {% if theme_touch_icon %} 5 | 6 | {% endif %} 7 | 9 | {% endblock %} 10 | {%- block relbar2 %}{% endblock %} 11 | {% block header %} 12 | {{ super() }} 13 | {% if pagename == 'index' %} 14 |
15 | {% endif %} 16 | {% endblock %} 17 | {%- block footer %} 18 | 22 | {% if pagename == 'index' %} 23 |
24 | {% endif %} 25 | {%- endblock %} 26 | -------------------------------------------------------------------------------- /docs/_themes/flask/relations.html: -------------------------------------------------------------------------------- 1 |

Related Topics

2 | 20 | -------------------------------------------------------------------------------- /docs/_themes/flask/static/flasky.css_t: -------------------------------------------------------------------------------- 1 | /* 2 | * flasky.css_t 3 | * ~~~~~~~~~~~~ 4 | * 5 | * :copyright: Copyright 2010 by Armin Ronacher. 6 | * :license: Flask Design License, see LICENSE for details. 7 | */ 8 | 9 | {% set page_width = '940px' %} 10 | {% set sidebar_width = '220px' %} 11 | 12 | @import url("basic.css"); 13 | 14 | /* -- page layout ----------------------------------------------------------- */ 15 | 16 | body { 17 | font-family: 'Georgia', serif; 18 | font-size: 17px; 19 | background-color: white; 20 | color: #000; 21 | margin: 0; 22 | padding: 0; 23 | } 24 | 25 | div.document { 26 | width: {{ page_width }}; 27 | margin: 30px auto 0 auto; 28 | } 29 | 30 | div.documentwrapper { 31 | float: left; 32 | width: 100%; 33 | } 34 | 35 | div.bodywrapper { 36 | margin: 0 0 0 {{ sidebar_width }}; 37 | } 38 | 39 | div.sphinxsidebar { 40 | width: {{ sidebar_width }}; 41 | } 42 | 43 | hr { 44 | border: 1px solid #B1B4B6; 45 | } 46 | 47 | div.body { 48 | background-color: #ffffff; 49 | color: #3E4349; 50 | padding: 0 30px 0 30px; 51 | } 52 | 53 | img.floatingflask { 54 | padding: 0 0 10px 10px; 55 | float: right; 56 | } 57 | 58 | div.footer { 59 | width: {{ page_width }}; 60 | margin: 20px auto 30px auto; 61 | font-size: 14px; 62 | color: #888; 63 | text-align: right; 64 | } 65 | 66 | div.footer a { 67 | color: #888; 68 | } 69 | 70 | div.related { 71 | display: none; 72 | } 73 | 74 | div.sphinxsidebar a { 75 | color: #444; 76 | text-decoration: none; 77 | border-bottom: 1px dotted #999; 78 | } 79 | 80 | div.sphinxsidebar a:hover { 81 | border-bottom: 1px solid #999; 82 | } 83 | 84 | div.sphinxsidebar { 85 | font-size: 14px; 86 | line-height: 1.5; 87 | } 88 | 89 | div.sphinxsidebarwrapper { 90 | padding: 18px 10px; 91 | } 92 | 93 | div.sphinxsidebarwrapper p.logo { 94 | padding: 0 0 20px 0; 95 | margin: 0; 96 | text-align: center; 97 | } 98 | 99 | div.sphinxsidebar h3, 100 | div.sphinxsidebar h4 { 101 | font-family: 'Garamond', 'Georgia', serif; 102 | color: #444; 103 | font-size: 24px; 104 | font-weight: normal; 105 | margin: 0 0 5px 0; 106 | padding: 0; 107 | } 108 | 109 | div.sphinxsidebar h4 { 110 | font-size: 20px; 111 | } 112 | 113 | div.sphinxsidebar h3 a { 114 | color: #444; 115 | } 116 | 117 | div.sphinxsidebar p.logo a, 118 | div.sphinxsidebar h3 a, 119 | div.sphinxsidebar p.logo a:hover, 120 | div.sphinxsidebar h3 a:hover { 121 | border: none; 122 | } 123 | 124 | div.sphinxsidebar p { 125 | color: #555; 126 | margin: 10px 0; 127 | } 128 | 129 | div.sphinxsidebar ul { 130 | margin: 10px 0; 131 | padding: 0; 132 | color: #000; 133 | } 134 | 135 | div.sphinxsidebar input { 136 | border: 1px solid #ccc; 137 | font-family: 'Georgia', serif; 138 | font-size: 1em; 139 | } 140 | 141 | /* -- body styles ----------------------------------------------------------- */ 142 | 143 | a { 144 | color: #004B6B; 145 | text-decoration: underline; 146 | } 147 | 148 | a:hover { 149 | color: #6D4100; 150 | text-decoration: underline; 151 | } 152 | 153 | div.body h1, 154 | div.body h2, 155 | div.body h3, 156 | div.body h4, 157 | div.body h5, 158 | div.body h6 { 159 | font-family: 'Garamond', 'Georgia', serif; 160 | font-weight: normal; 161 | margin: 30px 0px 10px 0px; 162 | padding: 0; 163 | } 164 | 165 | {% if theme_index_logo %} 166 | div.indexwrapper h1 { 167 | text-indent: -999999px; 168 | background: url({{ theme_index_logo }}) no-repeat center center; 169 | height: {{ theme_index_logo_height }}; 170 | } 171 | {% endif %} 172 | 173 | div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; } 174 | div.body h2 { font-size: 180%; } 175 | div.body h3 { font-size: 150%; } 176 | div.body h4 { font-size: 130%; } 177 | div.body h5 { font-size: 100%; } 178 | div.body h6 { font-size: 100%; } 179 | 180 | a.headerlink { 181 | color: #ddd; 182 | padding: 0 4px; 183 | text-decoration: none; 184 | } 185 | 186 | a.headerlink:hover { 187 | color: #444; 188 | background: #eaeaea; 189 | } 190 | 191 | div.body p, div.body dd, div.body li { 192 | line-height: 1.4em; 193 | } 194 | 195 | div.admonition { 196 | background: #fafafa; 197 | margin: 20px -30px; 198 | padding: 10px 30px; 199 | border-top: 1px solid #ccc; 200 | border-bottom: 1px solid #ccc; 201 | } 202 | 203 | div.admonition tt.xref, div.admonition a tt { 204 | border-bottom: 1px solid #fafafa; 205 | } 206 | 207 | dd div.admonition { 208 | margin-left: -60px; 209 | padding-left: 60px; 210 | } 211 | 212 | div.admonition p.admonition-title { 213 | font-family: 'Garamond', 'Georgia', serif; 214 | font-weight: normal; 215 | font-size: 24px; 216 | margin: 0 0 10px 0; 217 | padding: 0; 218 | line-height: 1; 219 | } 220 | 221 | div.admonition p.last { 222 | margin-bottom: 0; 223 | } 224 | 225 | div.highlight { 226 | background-color: white; 227 | } 228 | 229 | dt:target, .highlight { 230 | background: #FAF3E8; 231 | } 232 | 233 | div.note { 234 | background-color: #eee; 235 | border: 1px solid #ccc; 236 | } 237 | 238 | div.seealso { 239 | background-color: #ffc; 240 | border: 1px solid #ff6; 241 | } 242 | 243 | div.topic { 244 | background-color: #eee; 245 | } 246 | 247 | p.admonition-title { 248 | display: inline; 249 | } 250 | 251 | p.admonition-title:after { 252 | content: ":"; 253 | } 254 | 255 | pre, tt { 256 | font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; 257 | font-size: 0.9em; 258 | } 259 | 260 | img.screenshot { 261 | } 262 | 263 | tt.descname, tt.descclassname { 264 | font-size: 0.95em; 265 | } 266 | 267 | tt.descname { 268 | padding-right: 0.08em; 269 | } 270 | 271 | img.screenshot { 272 | -moz-box-shadow: 2px 2px 4px #eee; 273 | -webkit-box-shadow: 2px 2px 4px #eee; 274 | box-shadow: 2px 2px 4px #eee; 275 | } 276 | 277 | table.docutils { 278 | border: 1px solid #888; 279 | -moz-box-shadow: 2px 2px 4px #eee; 280 | -webkit-box-shadow: 2px 2px 4px #eee; 281 | box-shadow: 2px 2px 4px #eee; 282 | } 283 | 284 | table.docutils td, table.docutils th { 285 | border: 1px solid #888; 286 | padding: 0.25em 0.7em; 287 | } 288 | 289 | table.field-list, table.footnote { 290 | border: none; 291 | -moz-box-shadow: none; 292 | -webkit-box-shadow: none; 293 | box-shadow: none; 294 | } 295 | 296 | table.footnote { 297 | margin: 15px 0; 298 | width: 100%; 299 | border: 1px solid #eee; 300 | background: #fdfdfd; 301 | font-size: 0.9em; 302 | } 303 | 304 | table.footnote + table.footnote { 305 | margin-top: -15px; 306 | border-top: none; 307 | } 308 | 309 | table.field-list th { 310 | padding: 0 0.8em 0 0; 311 | } 312 | 313 | table.field-list td { 314 | padding: 0; 315 | } 316 | 317 | table.footnote td.label { 318 | width: 0px; 319 | padding: 0.3em 0 0.3em 0.5em; 320 | } 321 | 322 | table.footnote td { 323 | padding: 0.3em 0.5em; 324 | } 325 | 326 | dl { 327 | margin: 0; 328 | padding: 0; 329 | } 330 | 331 | dl dd { 332 | margin-left: 30px; 333 | } 334 | 335 | blockquote { 336 | margin: 0 0 0 30px; 337 | padding: 0; 338 | } 339 | 340 | ul, ol { 341 | margin: 10px 0 10px 30px; 342 | padding: 0; 343 | } 344 | 345 | pre { 346 | background: #eee; 347 | padding: 7px 30px; 348 | margin: 15px -30px; 349 | line-height: 1.3em; 350 | } 351 | 352 | dl pre, blockquote pre, li pre { 353 | margin-left: -60px; 354 | padding-left: 60px; 355 | } 356 | 357 | dl dl pre { 358 | margin-left: -90px; 359 | padding-left: 90px; 360 | } 361 | 362 | tt { 363 | background-color: #ecf0f3; 364 | color: #222; 365 | /* padding: 1px 2px; */ 366 | } 367 | 368 | tt.xref, a tt { 369 | background-color: #FBFBFB; 370 | border-bottom: 1px solid white; 371 | } 372 | 373 | a.reference { 374 | text-decoration: none; 375 | border-bottom: 1px dotted #004B6B; 376 | } 377 | 378 | a.reference:hover { 379 | border-bottom: 1px solid #6D4100; 380 | } 381 | 382 | a.footnote-reference { 383 | text-decoration: none; 384 | font-size: 0.7em; 385 | vertical-align: top; 386 | border-bottom: 1px dotted #004B6B; 387 | } 388 | 389 | a.footnote-reference:hover { 390 | border-bottom: 1px solid #6D4100; 391 | } 392 | 393 | a:hover tt { 394 | background: #EEE; 395 | } 396 | -------------------------------------------------------------------------------- /docs/_themes/flask/static/small_flask.css: -------------------------------------------------------------------------------- 1 | /* 2 | * small_flask.css_t 3 | * ~~~~~~~~~~~~~~~~~ 4 | * 5 | * :copyright: Copyright 2010 by Armin Ronacher. 6 | * :license: Flask Design License, see LICENSE for details. 7 | */ 8 | 9 | body { 10 | margin: 0; 11 | padding: 20px 30px; 12 | } 13 | 14 | div.documentwrapper { 15 | float: none; 16 | background: white; 17 | } 18 | 19 | div.sphinxsidebar { 20 | display: block; 21 | float: none; 22 | width: 102.5%; 23 | margin: 50px -30px -20px -30px; 24 | padding: 10px 20px; 25 | background: #333; 26 | color: white; 27 | } 28 | 29 | div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p, 30 | div.sphinxsidebar h3 a { 31 | color: white; 32 | } 33 | 34 | div.sphinxsidebar a { 35 | color: #aaa; 36 | } 37 | 38 | div.sphinxsidebar p.logo { 39 | display: none; 40 | } 41 | 42 | div.document { 43 | width: 100%; 44 | margin: 0; 45 | } 46 | 47 | div.related { 48 | display: block; 49 | margin: 0; 50 | padding: 10px 0 20px 0; 51 | } 52 | 53 | div.related ul, 54 | div.related ul li { 55 | margin: 0; 56 | padding: 0; 57 | } 58 | 59 | div.footer { 60 | display: none; 61 | } 62 | 63 | div.bodywrapper { 64 | margin: 0; 65 | } 66 | 67 | div.body { 68 | min-height: 0; 69 | padding: 0; 70 | } 71 | -------------------------------------------------------------------------------- /docs/_themes/flask/theme.conf: -------------------------------------------------------------------------------- 1 | [theme] 2 | inherit = basic 3 | stylesheet = flasky.css 4 | pygments_style = flask_theme_support.FlaskyStyle 5 | 6 | [options] 7 | index_logo = '' 8 | index_logo_height = 120px 9 | touch_icon = 10 | -------------------------------------------------------------------------------- /docs/_themes/flask_small/layout.html: -------------------------------------------------------------------------------- 1 | {% extends "basic/layout.html" %} 2 | {% block header %} 3 | {{ super() }} 4 | {% if pagename == 'index' %} 5 |
6 | {% endif %} 7 | {% endblock %} 8 | {% block footer %} 9 | {% if pagename == 'index' %} 10 |
11 | {% endif %} 12 | {% endblock %} 13 | {# do not display relbars #} 14 | {% block relbar1 %}{% endblock %} 15 | {% block relbar2 %} 16 | {% if theme_github_fork %} 17 | Fork me on GitHub 19 | {% endif %} 20 | {% endblock %} 21 | {% block sidebar1 %}{% endblock %} 22 | {% block sidebar2 %}{% endblock %} 23 | -------------------------------------------------------------------------------- /docs/_themes/flask_small/static/flasky.css_t: -------------------------------------------------------------------------------- 1 | /* 2 | * flasky.css_t 3 | * ~~~~~~~~~~~~ 4 | * 5 | * Sphinx stylesheet -- flasky theme based on nature theme. 6 | * 7 | * :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS. 8 | * :license: BSD, see LICENSE for details. 9 | * 10 | */ 11 | 12 | @import url("basic.css"); 13 | 14 | /* -- page layout ----------------------------------------------------------- */ 15 | 16 | body { 17 | font-family: 'Georgia', serif; 18 | font-size: 17px; 19 | color: #000; 20 | background: white; 21 | margin: 0; 22 | padding: 0; 23 | } 24 | 25 | div.documentwrapper { 26 | float: left; 27 | width: 100%; 28 | } 29 | 30 | div.bodywrapper { 31 | margin: 40px auto 0 auto; 32 | width: 700px; 33 | } 34 | 35 | hr { 36 | border: 1px solid #B1B4B6; 37 | } 38 | 39 | div.body { 40 | background-color: #ffffff; 41 | color: #3E4349; 42 | padding: 0 30px 30px 30px; 43 | } 44 | 45 | img.floatingflask { 46 | padding: 0 0 10px 10px; 47 | float: right; 48 | } 49 | 50 | div.footer { 51 | text-align: right; 52 | color: #888; 53 | padding: 10px; 54 | font-size: 14px; 55 | width: 650px; 56 | margin: 0 auto 40px auto; 57 | } 58 | 59 | div.footer a { 60 | color: #888; 61 | text-decoration: underline; 62 | } 63 | 64 | div.related { 65 | line-height: 32px; 66 | color: #888; 67 | } 68 | 69 | div.related ul { 70 | padding: 0 0 0 10px; 71 | } 72 | 73 | div.related a { 74 | color: #444; 75 | } 76 | 77 | /* -- body styles ----------------------------------------------------------- */ 78 | 79 | a { 80 | color: #004B6B; 81 | text-decoration: underline; 82 | } 83 | 84 | a:hover { 85 | color: #6D4100; 86 | text-decoration: underline; 87 | } 88 | 89 | div.body { 90 | padding-bottom: 40px; /* saved for footer */ 91 | } 92 | 93 | div.body h1, 94 | div.body h2, 95 | div.body h3, 96 | div.body h4, 97 | div.body h5, 98 | div.body h6 { 99 | font-family: 'Garamond', 'Georgia', serif; 100 | font-weight: normal; 101 | margin: 30px 0px 10px 0px; 102 | padding: 0; 103 | } 104 | 105 | {% if theme_index_logo %} 106 | div.indexwrapper h1 { 107 | text-indent: -999999px; 108 | background: url({{ theme_index_logo }}) no-repeat center center; 109 | height: {{ theme_index_logo_height }}; 110 | } 111 | {% endif %} 112 | 113 | div.body h2 { font-size: 180%; } 114 | div.body h3 { font-size: 150%; } 115 | div.body h4 { font-size: 130%; } 116 | div.body h5 { font-size: 100%; } 117 | div.body h6 { font-size: 100%; } 118 | 119 | a.headerlink { 120 | color: white; 121 | padding: 0 4px; 122 | text-decoration: none; 123 | } 124 | 125 | a.headerlink:hover { 126 | color: #444; 127 | background: #eaeaea; 128 | } 129 | 130 | div.body p, div.body dd, div.body li { 131 | line-height: 1.4em; 132 | } 133 | 134 | div.admonition { 135 | background: #fafafa; 136 | margin: 20px -30px; 137 | padding: 10px 30px; 138 | border-top: 1px solid #ccc; 139 | border-bottom: 1px solid #ccc; 140 | } 141 | 142 | div.admonition p.admonition-title { 143 | font-family: 'Garamond', 'Georgia', serif; 144 | font-weight: normal; 145 | font-size: 24px; 146 | margin: 0 0 10px 0; 147 | padding: 0; 148 | line-height: 1; 149 | } 150 | 151 | div.admonition p.last { 152 | margin-bottom: 0; 153 | } 154 | 155 | div.highlight{ 156 | background-color: white; 157 | } 158 | 159 | dt:target, .highlight { 160 | background: #FAF3E8; 161 | } 162 | 163 | div.note { 164 | background-color: #eee; 165 | border: 1px solid #ccc; 166 | } 167 | 168 | div.seealso { 169 | background-color: #ffc; 170 | border: 1px solid #ff6; 171 | } 172 | 173 | div.topic { 174 | background-color: #eee; 175 | } 176 | 177 | div.warning { 178 | background-color: #ffe4e4; 179 | border: 1px solid #f66; 180 | } 181 | 182 | p.admonition-title { 183 | display: inline; 184 | } 185 | 186 | p.admonition-title:after { 187 | content: ":"; 188 | } 189 | 190 | pre, tt { 191 | font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; 192 | font-size: 0.85em; 193 | } 194 | 195 | img.screenshot { 196 | } 197 | 198 | tt.descname, tt.descclassname { 199 | font-size: 0.95em; 200 | } 201 | 202 | tt.descname { 203 | padding-right: 0.08em; 204 | } 205 | 206 | img.screenshot { 207 | -moz-box-shadow: 2px 2px 4px #eee; 208 | -webkit-box-shadow: 2px 2px 4px #eee; 209 | box-shadow: 2px 2px 4px #eee; 210 | } 211 | 212 | table.docutils { 213 | border: 1px solid #888; 214 | -moz-box-shadow: 2px 2px 4px #eee; 215 | -webkit-box-shadow: 2px 2px 4px #eee; 216 | box-shadow: 2px 2px 4px #eee; 217 | } 218 | 219 | table.docutils td, table.docutils th { 220 | border: 1px solid #888; 221 | padding: 0.25em 0.7em; 222 | } 223 | 224 | table.field-list, table.footnote { 225 | border: none; 226 | -moz-box-shadow: none; 227 | -webkit-box-shadow: none; 228 | box-shadow: none; 229 | } 230 | 231 | table.footnote { 232 | margin: 15px 0; 233 | width: 100%; 234 | border: 1px solid #eee; 235 | } 236 | 237 | table.field-list th { 238 | padding: 0 0.8em 0 0; 239 | } 240 | 241 | table.field-list td { 242 | padding: 0; 243 | } 244 | 245 | table.footnote td { 246 | padding: 0.5em; 247 | } 248 | 249 | dl { 250 | margin: 0; 251 | padding: 0; 252 | } 253 | 254 | dl dd { 255 | margin-left: 30px; 256 | } 257 | 258 | pre { 259 | padding: 0; 260 | margin: 15px -30px; 261 | padding: 8px; 262 | line-height: 1.3em; 263 | padding: 7px 30px; 264 | background: #eee; 265 | border-radius: 2px; 266 | -moz-border-radius: 2px; 267 | -webkit-border-radius: 2px; 268 | } 269 | 270 | dl pre { 271 | margin-left: -60px; 272 | padding-left: 60px; 273 | } 274 | 275 | tt { 276 | background-color: #ecf0f3; 277 | color: #222; 278 | /* padding: 1px 2px; */ 279 | } 280 | 281 | tt.xref, a tt { 282 | background-color: #FBFBFB; 283 | } 284 | 285 | a:hover tt { 286 | background: #EEE; 287 | } 288 | -------------------------------------------------------------------------------- /docs/_themes/flask_small/theme.conf: -------------------------------------------------------------------------------- 1 | [theme] 2 | inherit = basic 3 | stylesheet = flasky.css 4 | nosidebar = true 5 | pygments_style = flask_theme_support.FlaskyStyle 6 | 7 | [options] 8 | index_logo = '' 9 | index_logo_height = 120px 10 | github_fork = '' 11 | -------------------------------------------------------------------------------- /docs/_themes/flask_theme_support.py: -------------------------------------------------------------------------------- 1 | # flasky extensions. flasky pygments style based on tango style 2 | from pygments.style import Style 3 | from pygments.token import Keyword, Name, Comment, String, Error, \ 4 | Number, Operator, Generic, Whitespace, Punctuation, Other, Literal 5 | 6 | 7 | class FlaskyStyle(Style): 8 | background_color = "#f8f8f8" 9 | default_style = "" 10 | 11 | styles = { 12 | # No corresponding class for the following: 13 | #Text: "", # class: '' 14 | Whitespace: "underline #f8f8f8", # class: 'w' 15 | Error: "#a40000 border:#ef2929", # class: 'err' 16 | Other: "#000000", # class 'x' 17 | 18 | Comment: "italic #8f5902", # class: 'c' 19 | Comment.Preproc: "noitalic", # class: 'cp' 20 | 21 | Keyword: "bold #004461", # class: 'k' 22 | Keyword.Constant: "bold #004461", # class: 'kc' 23 | Keyword.Declaration: "bold #004461", # class: 'kd' 24 | Keyword.Namespace: "bold #004461", # class: 'kn' 25 | Keyword.Pseudo: "bold #004461", # class: 'kp' 26 | Keyword.Reserved: "bold #004461", # class: 'kr' 27 | Keyword.Type: "bold #004461", # class: 'kt' 28 | 29 | Operator: "#582800", # class: 'o' 30 | Operator.Word: "bold #004461", # class: 'ow' - like keywords 31 | 32 | Punctuation: "bold #000000", # class: 'p' 33 | 34 | # because special names such as Name.Class, Name.Function, etc. 35 | # are not recognized as such later in the parsing, we choose them 36 | # to look the same as ordinary variables. 37 | Name: "#000000", # class: 'n' 38 | Name.Attribute: "#c4a000", # class: 'na' - to be revised 39 | Name.Builtin: "#004461", # class: 'nb' 40 | Name.Builtin.Pseudo: "#3465a4", # class: 'bp' 41 | Name.Class: "#000000", # class: 'nc' - to be revised 42 | Name.Constant: "#000000", # class: 'no' - to be revised 43 | Name.Decorator: "#888", # class: 'nd' - to be revised 44 | Name.Entity: "#ce5c00", # class: 'ni' 45 | Name.Exception: "bold #cc0000", # class: 'ne' 46 | Name.Function: "#000000", # class: 'nf' 47 | Name.Property: "#000000", # class: 'py' 48 | Name.Label: "#f57900", # class: 'nl' 49 | Name.Namespace: "#000000", # class: 'nn' - to be revised 50 | Name.Other: "#000000", # class: 'nx' 51 | Name.Tag: "bold #004461", # class: 'nt' - like a keyword 52 | Name.Variable: "#000000", # class: 'nv' - to be revised 53 | Name.Variable.Class: "#000000", # class: 'vc' - to be revised 54 | Name.Variable.Global: "#000000", # class: 'vg' - to be revised 55 | Name.Variable.Instance: "#000000", # class: 'vi' - to be revised 56 | 57 | Number: "#990000", # class: 'm' 58 | 59 | Literal: "#000000", # class: 'l' 60 | Literal.Date: "#000000", # class: 'ld' 61 | 62 | String: "#4e9a06", # class: 's' 63 | String.Backtick: "#4e9a06", # class: 'sb' 64 | String.Char: "#4e9a06", # class: 'sc' 65 | String.Doc: "italic #8f5902", # class: 'sd' - like a comment 66 | String.Double: "#4e9a06", # class: 's2' 67 | String.Escape: "#4e9a06", # class: 'se' 68 | String.Heredoc: "#4e9a06", # class: 'sh' 69 | String.Interpol: "#4e9a06", # class: 'si' 70 | String.Other: "#4e9a06", # class: 'sx' 71 | String.Regex: "#4e9a06", # class: 'sr' 72 | String.Single: "#4e9a06", # class: 's1' 73 | String.Symbol: "#4e9a06", # class: 'ss' 74 | 75 | Generic: "#000000", # class: 'g' 76 | Generic.Deleted: "#a40000", # class: 'gd' 77 | Generic.Emph: "italic #000000", # class: 'ge' 78 | Generic.Error: "#ef2929", # class: 'gr' 79 | Generic.Heading: "bold #000080", # class: 'gh' 80 | Generic.Inserted: "#00A000", # class: 'gi' 81 | Generic.Output: "#888", # class: 'go' 82 | Generic.Prompt: "#745334", # class: 'gp' 83 | Generic.Strong: "bold #000000", # class: 'gs' 84 | Generic.Subheading: "bold #800080", # class: 'gu' 85 | Generic.Traceback: "bold #a40000", # class: 'gt' 86 | } 87 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Flask-Misaka documentation build configuration file, created by 4 | # sphinx-quickstart on Thu Nov 1 20:28:32 2012. 5 | # 6 | # This file is execfile()d with the current directory set to its containing dir. 7 | # 8 | # Note that not all possible configuration values are present in this 9 | # autogenerated file. 10 | # 11 | # All configuration values have a default; values that are commented out 12 | # serve to show the default. 13 | 14 | import sys, os 15 | 16 | # If extensions (or modules to document with autodoc) are in another directory, 17 | # add these directories to sys.path here. If the directory is relative to the 18 | # documentation root, use os.path.abspath to make it absolute, like shown here. 19 | sys.path.insert(0, os.path.abspath('..')) 20 | sys.path.append(os.path.abspath('_themes')) 21 | from flask_misaka import __version__ 22 | 23 | # -- General configuration ----------------------------------------------------- 24 | 25 | # If your documentation needs a minimal Sphinx version, state it here. 26 | #needs_sphinx = '1.0' 27 | 28 | # Add any Sphinx extension module names here, as strings. They can be extensions 29 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 30 | extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx'] 31 | 32 | # Add any paths that contain templates here, relative to this directory. 33 | templates_path = ['_templates'] 34 | 35 | # The suffix of source filenames. 36 | source_suffix = '.rst' 37 | 38 | # The encoding of source files. 39 | #source_encoding = 'utf-8-sig' 40 | 41 | # The master toctree document. 42 | master_doc = 'index' 43 | 44 | # General information about the project. 45 | project = u'Flask-Misaka' 46 | copyright = u'2012-2016, David Baumgold' 47 | 48 | # The version info for the project you're documenting, acts as replacement for 49 | # |version| and |release|, also used in various other places throughout the 50 | # built documents. 51 | # 52 | # The short X.Y version. 53 | version = __version__ 54 | # The full version, including alpha/beta/rc tags. 55 | release = version 56 | 57 | # The language for content autogenerated by Sphinx. Refer to documentation 58 | # for a list of supported languages. 59 | #language = None 60 | 61 | # There are two options for replacing |today|: either, you set today to some 62 | # non-false value, then it is used: 63 | #today = '' 64 | # Else, today_fmt is used as the format for a strftime call. 65 | #today_fmt = '%B %d, %Y' 66 | 67 | # List of patterns, relative to source directory, that match files and 68 | # directories to ignore when looking for source files. 69 | exclude_patterns = ['_build'] 70 | 71 | # The reST default role (used for this markup: `text`) to use for all documents. 72 | #default_role = None 73 | 74 | # If true, '()' will be appended to :func: etc. cross-reference text. 75 | #add_function_parentheses = True 76 | 77 | # If true, the current module name will be prepended to all description 78 | # unit titles (such as .. function::). 79 | #add_module_names = True 80 | 81 | # If true, sectionauthor and moduleauthor directives will be shown in the 82 | # output. They are ignored by default. 83 | #show_authors = False 84 | 85 | # The name of the Pygments (syntax highlighting) style to use. 86 | pygments_style = 'sphinx' 87 | 88 | # A list of ignored prefixes for module index sorting. 89 | #modindex_common_prefix = [] 90 | 91 | 92 | # -- Options for HTML output --------------------------------------------------- 93 | 94 | # The theme to use for HTML and HTML Help pages. See the documentation for 95 | # a list of builtin themes. 96 | html_theme = 'flask_small' 97 | 98 | # Theme options are theme-specific and customize the look and feel of a theme 99 | # further. For a list of options available for each theme, see the 100 | # documentation. 101 | html_theme_options = { 102 | "github_fork": "singingwolfboy/flask-misaka", 103 | "index_logo": "logo.png", 104 | } 105 | 106 | # Add any paths that contain custom themes here, relative to this directory. 107 | html_theme_path = ['_themes'] 108 | 109 | # The name for this set of Sphinx documents. If None, it defaults to 110 | # " v documentation". 111 | #html_title = None 112 | 113 | # A shorter title for the navigation bar. Default is the same as html_title. 114 | #html_short_title = None 115 | 116 | # The name of an image file (relative to this directory) to place at the top 117 | # of the sidebar. 118 | #html_logo = None 119 | 120 | # The name of an image file (within the static path) to use as favicon of the 121 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 122 | # pixels large. 123 | #html_favicon = None 124 | 125 | # Add any paths that contain custom static files (such as style sheets) here, 126 | # relative to this directory. They are copied after the builtin static files, 127 | # so a file named "default.css" will overwrite the builtin "default.css". 128 | html_static_path = ['_static'] 129 | 130 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 131 | # using the given strftime format. 132 | #html_last_updated_fmt = '%b %d, %Y' 133 | 134 | # If true, SmartyPants will be used to convert quotes and dashes to 135 | # typographically correct entities. 136 | #html_use_smartypants = True 137 | 138 | # Custom sidebar templates, maps document names to template names. 139 | #html_sidebars = {} 140 | 141 | # Additional templates that should be rendered to pages, maps page names to 142 | # template names. 143 | #html_additional_pages = {} 144 | 145 | # If false, no module index is generated. 146 | #html_domain_indices = True 147 | 148 | # If false, no index is generated. 149 | #html_use_index = True 150 | 151 | # If true, the index is split into individual pages for each letter. 152 | #html_split_index = False 153 | 154 | # If true, links to the reST sources are added to the pages. 155 | #html_show_sourcelink = True 156 | 157 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 158 | #html_show_sphinx = True 159 | 160 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 161 | #html_show_copyright = True 162 | 163 | # If true, an OpenSearch description file will be output, and all pages will 164 | # contain a tag referring to it. The value of this option must be the 165 | # base URL from which the finished HTML is served. 166 | #html_use_opensearch = '' 167 | 168 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 169 | #html_file_suffix = None 170 | 171 | # Output file base name for HTML help builder. 172 | htmlhelp_basename = 'Flask-Misakadoc' 173 | 174 | 175 | # -- Options for LaTeX output -------------------------------------------------- 176 | 177 | latex_elements = { 178 | # The paper size ('letterpaper' or 'a4paper'). 179 | #'papersize': 'letterpaper', 180 | 181 | # The font size ('10pt', '11pt' or '12pt'). 182 | #'pointsize': '10pt', 183 | 184 | # Additional stuff for the LaTeX preamble. 185 | #'preamble': '', 186 | } 187 | 188 | # Grouping the document tree into LaTeX files. List of tuples 189 | # (source start file, target name, title, author, documentclass [howto/manual]). 190 | latex_documents = [ 191 | ('index', 'Flask-Misaka.tex', u'Flask-Misaka Documentation', 192 | u'David Baumgold', 'manual'), 193 | ] 194 | 195 | # The name of an image file (relative to this directory) to place at the top of 196 | # the title page. 197 | #latex_logo = None 198 | 199 | # For "manual" documents, if this is true, then toplevel headings are parts, 200 | # not chapters. 201 | #latex_use_parts = False 202 | 203 | # If true, show page references after internal links. 204 | #latex_show_pagerefs = False 205 | 206 | # If true, show URL addresses after external links. 207 | #latex_show_urls = False 208 | 209 | # Documents to append as an appendix to all manuals. 210 | #latex_appendices = [] 211 | 212 | # If false, no module index is generated. 213 | #latex_domain_indices = True 214 | 215 | 216 | # -- Options for manual page output -------------------------------------------- 217 | 218 | # One entry per manual page. List of tuples 219 | # (source start file, name, description, authors, manual section). 220 | man_pages = [ 221 | ('index', 'flask-misaka', u'Flask-Misaka Documentation', 222 | [u'David Baumgold'], 1) 223 | ] 224 | 225 | # If true, show URL addresses after external links. 226 | #man_show_urls = False 227 | 228 | 229 | # -- Options for Texinfo output ------------------------------------------------ 230 | 231 | # Grouping the document tree into Texinfo files. List of tuples 232 | # (source start file, target name, title, author, 233 | # dir menu entry, description, category) 234 | texinfo_documents = [ 235 | ('index', 'Flask-Misaka', u'Flask-Misaka Documentation', 236 | u'David Baumgold', 'Flask-Misaka', 'One line description of project.', 237 | 'Miscellaneous'), 238 | ] 239 | 240 | # Documents to append as an appendix to all manuals. 241 | #texinfo_appendices = [] 242 | 243 | # If false, no module index is generated. 244 | #texinfo_domain_indices = True 245 | 246 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 247 | #texinfo_show_urls = 'footnote' 248 | 249 | intersphinx_mapping = { 250 | 'flask': ('http://flask.pocoo.org/docs/', None), 251 | 'misaka': ('http://misaka.61924.nl/', None), 252 | } 253 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | Flask-Misaka 2 | ============ 3 | 4 | .. module:: flask_misaka 5 | 6 | Flask-Misaka provides a pleasant interface between the `Flask`_ web framework 7 | and the `Misaka`_ `Markdown`_ parser. [#technically]_ 8 | 9 | Installation 10 | ------------ 11 | 12 | Install the extension with: 13 | 14 | .. code-block:: sh 15 | 16 | $ pip install Flask-Misaka 17 | 18 | Usage 19 | ---------- 20 | Just import the :func:`markdown` function and use it! 21 | 22 | .. code-block:: python 23 | 24 | >>> from flask_misaka import markdown 25 | >>> markdown("A *simple* example.") 26 | Markup(u'

A simple example.

\n') 27 | 28 | To use Markdown in your templates, you just need to import the :class:`Misaka` 29 | class and wrap your Flask instance with it: 30 | 31 | .. code-block:: python 32 | 33 | from flask import Flask 34 | from flask_misaka import Misaka 35 | 36 | app = Flask(__name__) 37 | Misaka(app) 38 | 39 | or use the :ref:`application factory pattern `: 40 | 41 | .. code-block:: python 42 | 43 | md = Misaka() 44 | app = Flask(__name__) 45 | md.init_app(app) 46 | 47 | And then the ``markdown`` filter will be available in your `Jinja2`_ templates. 48 | You can pass variables in your template through it: 49 | 50 | .. code-block:: jinja 51 | 52 | {{ text|markdown }} 53 | 54 | Or, you can use the ``filter`` tag to write your template directly in Markdown 55 | and have Jinja dynamically interpret it for you! 56 | 57 | .. code-block:: jinja 58 | 59 | {% filter markdown %} 60 | I'm writing my templates in *Markdown!* 61 | {% endfilter %} 62 | 63 | 64 | API 65 | --- 66 | .. autofunction:: markdown 67 | 68 | .. autoclass:: Misaka 69 | :members: __init__, init_app, render 70 | 71 | Options 72 | ------- 73 | Misaka is very customizable, and `supports many Markdown extensions 74 | `_. Flask-Misaka provides a nicer API for these 75 | extensions. All functions in the public API (except :py:meth:`Misaka.init_app`) 76 | accept the following boolean arguments, all of which default to False: 77 | 78 | .. list-table:: Flask-Misaka options 79 | :header-rows: 1 80 | 81 | * - Option Name 82 | - Description 83 | 84 | * - ``autolink`` 85 | - Parse links even when they are not enclosed in ``<>`` characters. 86 | Autolinks for the http, https and ftp protocols will be automatically 87 | detected. Email addresses are also handled, and http links without 88 | protocol, but starting with ``www``. 89 | 90 | * - ``fenced_code`` 91 | - Blocks delimited with 3 or more ``~`` or backticks will be considered 92 | as code, without the need to be indented. An optional language name 93 | may be added at the end of the opening fence for the code block. 94 | 95 | * - ``underline`` 96 | - Treat text surrounded by underscores (like ``_this_``) as underlined, 97 | rather than emphasized. 98 | 99 | * - ``highlight`` 100 | - Treat text surrounded by double equal signs (like ``==this==``) 101 | as highlighted. 102 | 103 | * - ``quote`` 104 | - Parse inline quotes (like ``"this"``). This allows the renderer to 105 | control how they are rendered. 106 | 107 | * - ``math`` 108 | - Parse inline LaTeX-style math blocks (like ``$$this$$``). 109 | 110 | * - ``math_explicit`` 111 | - Parse inline LaTeX-style math blocks with a single dollar, e.g. 112 | ``$x + y = 3$`` 113 | 114 | * - ``disable_indented_code`` or ``no_indented_code`` 115 | - Ignore indented code blocks 116 | 117 | * - ``no_intra_emphasis`` 118 | - Do not parse emphasis inside of words. Strings such as ``foo_bar_baz`` 119 | will not generate ```` tags. 120 | 121 | * - ``space_headers`` 122 | - A space is always required between the hash at the beginning of 123 | a header and its name, e.g. ``#this is my header`` would not be 124 | a valid header. 125 | 126 | * - ``strikethrough`` 127 | - Two ``~`` characters mark the start of a strikethrough, e.g. 128 | ``this is ~~good~~ bad``. 129 | 130 | * - ``superscript`` 131 | - Parse superscripts after the ``^`` character; contiguous superscripts 132 | are nested together, and complex values can be enclosed in parenthesis, 133 | e.g. ``this is the 2^(nd) time``. 134 | 135 | * - ``tables`` 136 | - Parse `PHP-Markdown tables`_. 137 | 138 | * - ``hard_wrap`` *or* ``wrap`` 139 | - Insert HTML ``
`` tags inside on paragraphs where the origin 140 | Markdown document had newlines (by default, Markdown 141 | ignores these newlines). 142 | 143 | * - ``footnotes`` 144 | - Parse Markdown footnotes. 145 | 146 | * - ``escape`` 147 | - Escape all HTML tags, regardless of what they are. 148 | 149 | * - ``skip_html`` *or* ``no_html`` 150 | - Do not allow any user-inputted HTML in the output. 151 | 152 | * - ``use_xhtml`` *or* ``xhtml`` 153 | - Output XHTML-conformant tags. 154 | 155 | * - ``smartypants`` 156 | - Post-process rendered markdown text with `SmartyPants`_. 157 | 158 | 159 | Any option that starts with ``no_`` can also be passed as its inverse set to 160 | False. For example, ``no_html=True`` and ``html=False`` have exactly the same 161 | effect, just as ``no_intra_emphasis=True`` and ``intra_emphasis=False`` have 162 | exactly the same effect. 163 | 164 | .. note:: 165 | To override an option, you must use exactly the same option name as you used 166 | to originally set the option. If you set ``html=False`` as a default, you 167 | must override it with ``html=True``: using ``no_html=False`` or 168 | ``skip_html=False`` will not work, even though they all refer to the same 169 | thing. 170 | 171 | .. _Flask: http://flask.pocoo.org/ 172 | .. _Jinja2: http://jinja.pocoo.org/ 173 | .. _Misaka: http://misaka.61924.nl/ 174 | .. _Markdown: http://en.wikipedia.org/wiki/Markdown 175 | .. _Hoedown: https://github.com/hoedown/hoedown 176 | .. _PHP-Markdown tables: http://michelf.com/projects/php-markdown/extra/#table 177 | .. _SmartyPants: http://daringfireball.net/projects/smartypants/ 178 | .. _inline LaTex-style math: https://github.com/bhollis/maruku/blob/master/docs/math.md 179 | 180 | .. rubric:: Footnotes 181 | .. [#technically] 182 | (Technically, `Misaka`_ is just a Python binding to the `Hoedown`_ library, 183 | which is written in C.) 184 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=_build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . 10 | set I18NSPHINXOPTS=%SPHINXOPTS% . 11 | if NOT "%PAPER%" == "" ( 12 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 13 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% 14 | ) 15 | 16 | if "%1" == "" goto help 17 | 18 | if "%1" == "help" ( 19 | :help 20 | echo.Please use `make ^` where ^ is one of 21 | echo. html to make standalone HTML files 22 | echo. dirhtml to make HTML files named index.html in directories 23 | echo. singlehtml to make a single large HTML file 24 | echo. pickle to make pickle files 25 | echo. json to make JSON files 26 | echo. htmlhelp to make HTML files and a HTML help project 27 | echo. qthelp to make HTML files and a qthelp project 28 | echo. devhelp to make HTML files and a Devhelp project 29 | echo. epub to make an epub 30 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 31 | echo. text to make text files 32 | echo. man to make manual pages 33 | echo. texinfo to make Texinfo files 34 | echo. gettext to make PO message catalogs 35 | echo. changes to make an overview over all changed/added/deprecated items 36 | echo. linkcheck to check all external links for integrity 37 | echo. doctest to run all doctests embedded in the documentation if enabled 38 | goto end 39 | ) 40 | 41 | if "%1" == "clean" ( 42 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 43 | del /q /s %BUILDDIR%\* 44 | goto end 45 | ) 46 | 47 | if "%1" == "html" ( 48 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 49 | if errorlevel 1 exit /b 1 50 | echo. 51 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 52 | goto end 53 | ) 54 | 55 | if "%1" == "dirhtml" ( 56 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 57 | if errorlevel 1 exit /b 1 58 | echo. 59 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 60 | goto end 61 | ) 62 | 63 | if "%1" == "singlehtml" ( 64 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 65 | if errorlevel 1 exit /b 1 66 | echo. 67 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 68 | goto end 69 | ) 70 | 71 | if "%1" == "pickle" ( 72 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 73 | if errorlevel 1 exit /b 1 74 | echo. 75 | echo.Build finished; now you can process the pickle files. 76 | goto end 77 | ) 78 | 79 | if "%1" == "json" ( 80 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 81 | if errorlevel 1 exit /b 1 82 | echo. 83 | echo.Build finished; now you can process the JSON files. 84 | goto end 85 | ) 86 | 87 | if "%1" == "htmlhelp" ( 88 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 89 | if errorlevel 1 exit /b 1 90 | echo. 91 | echo.Build finished; now you can run HTML Help Workshop with the ^ 92 | .hhp project file in %BUILDDIR%/htmlhelp. 93 | goto end 94 | ) 95 | 96 | if "%1" == "qthelp" ( 97 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 98 | if errorlevel 1 exit /b 1 99 | echo. 100 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 101 | .qhcp project file in %BUILDDIR%/qthelp, like this: 102 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Flask-Misaka.qhcp 103 | echo.To view the help file: 104 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Flask-Misaka.ghc 105 | goto end 106 | ) 107 | 108 | if "%1" == "devhelp" ( 109 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 110 | if errorlevel 1 exit /b 1 111 | echo. 112 | echo.Build finished. 113 | goto end 114 | ) 115 | 116 | if "%1" == "epub" ( 117 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 118 | if errorlevel 1 exit /b 1 119 | echo. 120 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 121 | goto end 122 | ) 123 | 124 | if "%1" == "latex" ( 125 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 126 | if errorlevel 1 exit /b 1 127 | echo. 128 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 129 | goto end 130 | ) 131 | 132 | if "%1" == "text" ( 133 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 134 | if errorlevel 1 exit /b 1 135 | echo. 136 | echo.Build finished. The text files are in %BUILDDIR%/text. 137 | goto end 138 | ) 139 | 140 | if "%1" == "man" ( 141 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 142 | if errorlevel 1 exit /b 1 143 | echo. 144 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 145 | goto end 146 | ) 147 | 148 | if "%1" == "texinfo" ( 149 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo 150 | if errorlevel 1 exit /b 1 151 | echo. 152 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. 153 | goto end 154 | ) 155 | 156 | if "%1" == "gettext" ( 157 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale 158 | if errorlevel 1 exit /b 1 159 | echo. 160 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale. 161 | goto end 162 | ) 163 | 164 | if "%1" == "changes" ( 165 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 166 | if errorlevel 1 exit /b 1 167 | echo. 168 | echo.The overview file is in %BUILDDIR%/changes. 169 | goto end 170 | ) 171 | 172 | if "%1" == "linkcheck" ( 173 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 174 | if errorlevel 1 exit /b 1 175 | echo. 176 | echo.Link check complete; look for any errors in the above output ^ 177 | or in %BUILDDIR%/linkcheck/output.txt. 178 | goto end 179 | ) 180 | 181 | if "%1" == "doctest" ( 182 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 183 | if errorlevel 1 exit /b 1 184 | echo. 185 | echo.Testing of doctests in the sources finished, look at the ^ 186 | results in %BUILDDIR%/doctest/output.txt. 187 | goto end 188 | ) 189 | 190 | :end 191 | -------------------------------------------------------------------------------- /flask_misaka.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, unicode_literals 2 | 3 | __version__ = '1.0.1' 4 | 5 | import misaka 6 | from markupsafe import Markup 7 | from copy import copy 8 | 9 | # import constants for compatibility 10 | from misaka import (EXT_AUTOLINK, EXT_FENCED_CODE, # pyflakes.ignore 11 | EXT_NO_INTRA_EMPHASIS, EXT_SPACE_HEADERS, EXT_STRIKETHROUGH, 12 | EXT_SUPERSCRIPT, EXT_TABLES, HTML_ESCAPE, HTML_HARD_WRAP, HTML_SKIP_HTML, 13 | HTML_USE_XHTML, TABLE_ALIGNMASK, TABLE_HEADER, TABLE_ALIGN_CENTER, TABLE_ALIGN_LEFT, 14 | TABLE_ALIGN_RIGHT, EXT_MATH, EXT_FOOTNOTES, EXT_UNDERLINE, EXT_MATH_EXPLICIT, 15 | EXT_DISABLE_INDENTED_CODE, EXT_HIGHLIGHT, EXT_QUOTE) 16 | 17 | ALIAS_EXT = { 18 | 'autolink': EXT_AUTOLINK, 19 | 'fenced_code': EXT_FENCED_CODE, 20 | 'no_intra_emphasis': EXT_NO_INTRA_EMPHASIS, 21 | 'space_headers': EXT_SPACE_HEADERS, 22 | 'strikethrough': EXT_STRIKETHROUGH, 23 | 'superscript': EXT_SUPERSCRIPT, 24 | 'tables': EXT_TABLES, 25 | 'math': EXT_MATH, 26 | 'footnotes': EXT_FOOTNOTES, 27 | 'underline': EXT_UNDERLINE, 28 | 'math_explicit': EXT_MATH_EXPLICIT, 29 | 'disable_indented_code': EXT_DISABLE_INDENTED_CODE, 30 | 'no_indented_code': EXT_DISABLE_INDENTED_CODE, 31 | 'highlight': EXT_HIGHLIGHT, 32 | 'quote': EXT_QUOTE 33 | } 34 | 35 | ALIAS_RENDER = { 36 | 'escape': HTML_ESCAPE, 37 | 'hard_wrap': HTML_HARD_WRAP, 38 | 'wrap': HTML_HARD_WRAP, 39 | 'skip_html': HTML_SKIP_HTML, 40 | 'no_html': HTML_SKIP_HTML, 41 | 'use_xhtml': HTML_USE_XHTML, 42 | 'xhtml': HTML_USE_XHTML, 43 | } 44 | 45 | 46 | def make_flags(**options): 47 | ext = 0 48 | for name, val in ALIAS_EXT.items(): 49 | if options.get(name): 50 | ext = ext | val 51 | if name.startswith("no_"): 52 | if options.get(name[3:]) is False: 53 | ext = ext | val 54 | 55 | rndr = 0 56 | for name, val in ALIAS_RENDER.items(): 57 | if options.get(name): 58 | rndr = rndr | val 59 | if name.startswith("no_"): 60 | if options.get(name[3:]) is False: 61 | rndr = rndr | val 62 | 63 | return ext, rndr 64 | 65 | 66 | def markdown(text, renderer=None, **options): 67 | """ 68 | Parses the provided Markdown-formatted text into valid HTML, and returns 69 | it as a :class:`flask.Markup` instance. 70 | 71 | :param text: Markdown-formatted text to be rendered into HTML 72 | :param renderer: A custom misaka renderer to be used instead of the default one 73 | :param options: Additional options for customizing the default renderer 74 | :return: A :class:`flask.Markup` instance representing the rendered text 75 | """ 76 | ext, rndr = make_flags(**options) 77 | if renderer: 78 | md = misaka.Markdown(renderer,ext) 79 | result = md(text) 80 | else: 81 | result = misaka.html(text, extensions=ext, render_flags=rndr) 82 | if options.get("smartypants"): 83 | result = misaka.smartypants(result) 84 | return Markup(result) 85 | 86 | 87 | class Misaka(object): 88 | def __init__(self, app=None, renderer=None, **defaults): 89 | """ 90 | Set the default options for the :meth:`render` method. If you want 91 | the ``markdown`` template filter to use options, set them here. 92 | 93 | A custom misaka renderer can be specified to be used instead of the 94 | default one. 95 | """ 96 | self.renderer = renderer 97 | self.defaults = defaults 98 | if app: 99 | self.init_app(app) 100 | 101 | def init_app(self, app): 102 | """ 103 | Registers the rendering method as template filter. 104 | 105 | :param app: a :class:`flask.Flask` instance. 106 | """ 107 | app.jinja_env.filters.setdefault('markdown', self.render) 108 | 109 | def render(self, text, **overrides): 110 | """ 111 | It delegates to the :func:`markdown` function, passing any default 112 | options or renderer set in the :meth:`__init__` method. 113 | 114 | The ``markdown`` template filter calls this method. 115 | 116 | :param text: Markdown-formatted text to be rendered to HTML 117 | :param overrides: Additional options which may override the defaults 118 | :return: A :class:`flask.Markup` instance representing the rendered text 119 | """ 120 | options = self.defaults 121 | if overrides: 122 | options = copy(options) 123 | options.update(overrides) 124 | return markdown(text, self.renderer, **options) 125 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | markupsafe 2 | misaka>=2.0,<3.0 3 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import re 3 | from setuptools import setup, find_packages 4 | 5 | tests_require = ['Flask'] 6 | if sys.version_info[0] < 3: 7 | tests_require.append('mock') 8 | 9 | version = '' 10 | with open('flask_misaka.py', 'r') as fd: 11 | version = re.search(r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]', 12 | fd.read(), re.MULTILINE).group(1) 13 | 14 | if not version: 15 | raise RuntimeError('Cannot find version information') 16 | 17 | setup( 18 | name='Flask-Misaka', 19 | version=version, 20 | url='https://github.com/singingwolfboy/flask-misaka/', 21 | license='MIT', 22 | author='David Baumgold', 23 | author_email='david@davidbaumgold.com', 24 | description='A pleasant interface between the Flask web framework and the Misaka Markdown parser.', 25 | zip_safe=False, 26 | packages=find_packages(), 27 | py_modules=['flask_misaka'], 28 | install_requires=[ 29 | 'markupsafe', 30 | 'misaka>=2.0,<3.0', 31 | ], 32 | test_suite='tests', 33 | tests_require=tests_require, 34 | classifiers=[ 35 | 'Development Status :: 5 - Production/Stable', 36 | 'Programming Language :: Python', 37 | 'Programming Language :: Python :: 2', 38 | 'Programming Language :: Python :: 2.7', 39 | 'Programming Language :: Python :: 3', 40 | 'Programming Language :: Python :: 3.3', 41 | 'Environment :: Web Environment', 42 | 'Framework :: Flask', 43 | 'Intended Audience :: Developers', 44 | 'License :: OSI Approved :: MIT License', 45 | 'Topic :: Software Development :: Libraries :: Python Modules', 46 | ], 47 | ) 48 | -------------------------------------------------------------------------------- /tests.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | from flask import Flask, render_template_string 3 | from markupsafe import Markup 4 | from unittest import TestCase 5 | from textwrap import dedent 6 | try: 7 | from unittest import mock 8 | except ImportError: 9 | import mock 10 | 11 | import misaka 12 | from misaka import (EXT_AUTOLINK, EXT_FENCED_CODE, # pyflakes.ignore 13 | EXT_NO_INTRA_EMPHASIS, EXT_SPACE_HEADERS, EXT_STRIKETHROUGH, 14 | EXT_SUPERSCRIPT, EXT_TABLES, HTML_ESCAPE, HTML_HARD_WRAP, HTML_SKIP_HTML, 15 | HTML_USE_XHTML, TABLE_ALIGNMASK, TABLE_HEADER, TABLE_ALIGN_CENTER, TABLE_ALIGN_LEFT, 16 | TABLE_ALIGN_RIGHT, EXT_MATH, EXT_FOOTNOTES, EXT_UNDERLINE, EXT_MATH_EXPLICIT, 17 | EXT_DISABLE_INDENTED_CODE, EXT_HIGHLIGHT, EXT_QUOTE) 18 | 19 | from flask_misaka import Misaka, markdown 20 | 21 | TEST_MD = "*This* ~~contains~~ ``some`` mark^(down) extensions: www.markdown.com foo_bar_baz it's" 22 | 23 | app = Flask(__name__) 24 | app.debug = True 25 | Misaka(app) 26 | 27 | # templating tests # 28 | 29 | 30 | @app.route('/a') 31 | def view_render_inline(): 32 | s = "This is ~~restructuredtext~~ *markdown*" 33 | return render_template_string('{{s|markdown}}', s=s) 34 | 35 | 36 | def test_render_inline(): 37 | client = app.test_client() 38 | resp = client.open('/a') 39 | assert resp.data == b'

This is ~~restructuredtext~~ markdown

\n' 40 | 41 | 42 | @app.route('/b') 43 | def view_render_var_block(): 44 | s = "This is a *markdown* block" 45 | tpl = '''{% filter markdown %}{{s}}{% endfilter %}''' 46 | return render_template_string(tpl, s=s) 47 | 48 | 49 | def test_render_var_block(): 50 | client = app.test_client() 51 | resp = client.open('/b') 52 | assert resp.data == b'

This is a markdown block

\n' 53 | 54 | 55 | @app.route('/c') 56 | def view_render_in_block(): 57 | tpl = '''{% filter markdown %}This is a *markdown* block{% endfilter %}''' 58 | return render_template_string(tpl) 59 | 60 | 61 | def test_render_in_block(): 62 | client = app.test_client() 63 | resp = client.open('/c') 64 | assert resp.data == b'

This is a markdown block

\n' 65 | 66 | # markdown extensions in templates 67 | 68 | extapp = Flask(__name__) 69 | extapp.debug = True 70 | Misaka(extapp, strikethrough=True) 71 | 72 | 73 | @extapp.route('/d') 74 | def view_render_inline_ext(): 75 | s = "This is ~~restructuredtext~~ *markdown*" 76 | return render_template_string('{{s|markdown}}', s=s) 77 | 78 | 79 | def test_render_inline_ext(): 80 | client = extapp.test_client() 81 | resp = client.open('/d') 82 | assert resp.data == b'

This is restructuredtext markdown

\n' 83 | 84 | 85 | # Note that the Markdown extension tests aren't actually testing that the 86 | # Markdown is rendered correctly; that should be covered by the test suite of 87 | # the misaka module. These tests should test that Flask-Misaka is calling 88 | # the misaka module correctly, and returning the result unmodified 89 | # (aside from being wrapped in a Markup class instance.) 90 | 91 | @mock.patch("flask_misaka.misaka.html", side_effect=misaka.html) 92 | class MarkdownExtensionTests(TestCase): 93 | def test_defaults(self, html): 94 | ext, flags = 0, 0 95 | 96 | result = markdown(TEST_MD) 97 | 98 | html.assert_called_with(TEST_MD, extensions=ext, render_flags=flags) 99 | self.assertIsInstance(result, Markup) 100 | self.assertEqual(result, misaka.html(TEST_MD, 101 | extensions=ext, render_flags=flags)) 102 | 103 | def test_one_ext(self, html): 104 | ext, flags = EXT_AUTOLINK, 0 105 | 106 | result = markdown(TEST_MD, autolink=True) 107 | 108 | html.assert_called_with(TEST_MD, extensions=ext, render_flags=flags) 109 | self.assertIsInstance(result, Markup) 110 | self.assertEqual(result, misaka.html(TEST_MD, 111 | extensions=ext, render_flags=flags)) 112 | 113 | def test_two_ext(self, html): 114 | ext, flags = EXT_FENCED_CODE | EXT_AUTOLINK, 0 115 | 116 | result = markdown(TEST_MD, fenced_code=True, autolink=True) 117 | 118 | html.assert_called_with(TEST_MD, extensions=ext, render_flags=flags) 119 | self.assertIsInstance(result, Markup) 120 | self.assertEqual(result, misaka.html(TEST_MD, 121 | extensions=ext, render_flags=flags)) 122 | 123 | def test_one_render(self, html): 124 | ext, flags = 0, HTML_ESCAPE 125 | 126 | result = markdown(TEST_MD, escape=True) 127 | 128 | html.assert_called_with(TEST_MD, extensions=ext, render_flags=flags) 129 | self.assertIsInstance(result, Markup) 130 | self.assertEqual(result, misaka.html(TEST_MD, 131 | extensions=ext, render_flags=flags)) 132 | 133 | def test_two_render(self, html): 134 | ext, flags = 0, HTML_HARD_WRAP | HTML_ESCAPE 135 | 136 | result = markdown(TEST_MD, wrap=True, escape=True) 137 | 138 | html.assert_called_with(TEST_MD, extensions=ext, render_flags=flags) 139 | self.assertIsInstance(result, Markup) 140 | self.assertEqual(result, misaka.html(TEST_MD, 141 | extensions=ext, render_flags=flags)) 142 | 143 | def test_one_ext_one_render(self, html): 144 | ext, flags = EXT_NO_INTRA_EMPHASIS, HTML_SKIP_HTML 145 | 146 | result = markdown(TEST_MD, no_intra_emphasis=True, no_html=True) 147 | 148 | html.assert_called_with(TEST_MD, extensions=ext, render_flags=flags) 149 | self.assertIsInstance(result, Markup) 150 | self.assertEqual(result, misaka.html(TEST_MD, 151 | extensions=ext, render_flags=flags)) 152 | 153 | def test_two_ext_two_render(self, html): 154 | ext = EXT_STRIKETHROUGH | EXT_SUPERSCRIPT 155 | flags = HTML_HARD_WRAP | HTML_USE_XHTML 156 | 157 | result = markdown(TEST_MD, strikethrough=True, superscript=True, 158 | hard_wrap=True, use_xhtml=True) 159 | 160 | html.assert_called_with(TEST_MD, extensions=ext, render_flags=flags) 161 | self.assertIsInstance(result, Markup) 162 | self.assertEqual(result, misaka.html(TEST_MD, 163 | extensions=ext, render_flags=flags)) 164 | 165 | def test_inverse_ext(self, html): 166 | ext, flags = EXT_NO_INTRA_EMPHASIS, 0 167 | 168 | result = markdown(TEST_MD, intra_emphasis=False) 169 | 170 | html.assert_called_with(TEST_MD, extensions=ext, render_flags=flags) 171 | self.assertIsInstance(result, Markup) 172 | self.assertEqual(result, misaka.html(TEST_MD, 173 | extensions=ext, render_flags=flags)) 174 | 175 | def test_inverse_render(self, html): 176 | ext, flags = 0, HTML_SKIP_HTML 177 | 178 | result = markdown(TEST_MD, no_html=True) 179 | 180 | html.assert_called_with(TEST_MD, extensions=ext, render_flags=flags) 181 | self.assertIsInstance(result, Markup) 182 | self.assertEqual(result, misaka.html(TEST_MD, 183 | extensions=ext, render_flags=flags)) 184 | 185 | def test_undefined_option(self, html): 186 | ext, flags = 0, 0 187 | 188 | result = markdown(TEST_MD, fireworks=True) 189 | 190 | html.assert_called_with(TEST_MD, extensions=ext, render_flags=flags) 191 | self.assertIsInstance(result, Markup) 192 | self.assertEqual(result, misaka.html(TEST_MD, 193 | extensions=ext, render_flags=flags)) 194 | 195 | def test_defined_and_undefined_options(self, html): 196 | ext, flags = 0, HTML_HARD_WRAP 197 | 198 | result = markdown(TEST_MD, hard_wrap=True, stupid_hard_wrap=False) 199 | 200 | html.assert_called_with(TEST_MD, extensions=ext, render_flags=flags) 201 | self.assertIsInstance(result, Markup) 202 | self.assertEqual(result, misaka.html(TEST_MD, 203 | extensions=ext, render_flags=flags)) 204 | 205 | def test_set_defaults(self, html): 206 | ext, flags = EXT_TABLES, HTML_HARD_WRAP 207 | 208 | md = Misaka(hard_wrap=True, tables=True) 209 | result = md.render(TEST_MD) 210 | 211 | html.assert_called_with(TEST_MD, extensions=ext, render_flags=flags) 212 | self.assertIsInstance(result, Markup) 213 | self.assertEqual(result, misaka.html(TEST_MD, 214 | extensions=ext, render_flags=flags)) 215 | 216 | def test_override_defaults(self, html): 217 | ext, flags = 0, 0 218 | 219 | md = Misaka(autolink=True) 220 | result = md.render(TEST_MD, autolink=False) 221 | 222 | html.assert_called_with(TEST_MD, extensions=ext, render_flags=flags) 223 | self.assertIsInstance(result, Markup) 224 | self.assertEqual(result, misaka.html(TEST_MD, 225 | extensions=ext, render_flags=flags)) 226 | 227 | def test_custom_renderer(self, html): 228 | 229 | class CustomRenderer(misaka.HtmlRenderer): 230 | def image(self, link, title, alt_text): 231 | return '
{2}
{1}
'.format( 232 | link, title, alt_text) 233 | 234 | test_md = '![Alt text](/img.jpg "Title")' 235 | expected_result = '

Alt text
Title

\n' 236 | 237 | md = Misaka(None, CustomRenderer()) 238 | result = md.render(test_md) 239 | self.assertFalse(html.called) 240 | self.assertEqual(str(result), expected_result) 241 | 242 | def test_smartypants(self, html): 243 | text = "Don't call me Shirley" 244 | expected_result = "

Don’t call me Shirley

\n" 245 | 246 | md = Misaka(smartypants=True) 247 | result = md.render(text) 248 | 249 | self.assertIsInstance(result, Markup) 250 | self.assertEqual(result, expected_result) 251 | 252 | def test_smartypants_table(self, html): 253 | "smartypants should not interfere with processing tables" 254 | 255 | text = dedent(""" 256 | | Left align | Right align | Center align | 257 | |:-----------|------------:|:------------:| 258 | | This | This | This | 259 | | column | column | column | 260 | | will | will | will | 261 | | be | be | be | 262 | | left | right | center | 263 | | aligned | aligned | aligned | 264 | """) 265 | expected_result = dedent(""" 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 |
Left alignRight alignCenter align
ThisThisThis
columncolumncolumn
willwillwill
bebebe
leftrightcenter
alignedalignedaligned
308 | """) 309 | 310 | md = Misaka(tables=True, smartypants=True) 311 | result = md.render(text).strip() 312 | 313 | self.assertIsInstance(result, Markup) 314 | self.assertEqual(result.strip(), expected_result.strip()) 315 | 316 | 317 | class FactoryPatternTests(TestCase): 318 | def test_init(self): 319 | md = Misaka() 320 | app2 = Flask(__name__) 321 | md.init_app(app2) 322 | self.assertIn("markdown", app2.jinja_env.filters) 323 | --------------------------------------------------------------------------------