[Python-modules-commits] [drf-extensions] 01/05: importing drf-extensions_0.3.1.orig.tar.gz
Michael Fladischer
fladi at moszumanska.debian.org
Wed Mar 1 14:22:37 UTC 2017
This is an automated email from the git hooks/post-receive script.
fladi pushed a commit to branch master
in repository drf-extensions.
commit ecfa9c6fc11a840b5f5fb57de2aae98382ecdba2
Author: Michael Fladischer <FladischerMichael at fladi.at>
Date: Wed Mar 1 12:33:34 2017 +0100
importing drf-extensions_0.3.1.orig.tar.gz
---
.gitignore | 8 +
.travis.yml | 20 +
AUTHORS.md | 11 +
GNUmakefile | 7 +
LICENSE | 21 +
MANIFEST.in | 7 +
README.md | 144 ++
__init__.py | 0
docs/backdoc.py | 2723 ++++++++++++++++++++
docs/index.html | Bin 0 -> 191612 bytes
docs/index.md | 2089 +++++++++++++++
docs/metrika_code.txt | 1 +
docs/post_process_docs.py | 5 +
rest_framework_extensions/__init__.py | 3 +
.../bulk_operations/__init__.py | 1 +
.../bulk_operations/mixins.py | 102 +
rest_framework_extensions/cache/__init__.py | 0
rest_framework_extensions/cache/decorators.py | 98 +
rest_framework_extensions/cache/mixins.py | 27 +
rest_framework_extensions/compat.py | 210 ++
rest_framework_extensions/compat_drf.py | 21 +
rest_framework_extensions/etag/__init__.py | 1 +
rest_framework_extensions/etag/decorators.py | 137 +
rest_framework_extensions/etag/mixins.py | 45 +
rest_framework_extensions/fields.py | 28 +
.../key_constructor/__init__.py | 0
rest_framework_extensions/key_constructor/bits.py | 229 ++
.../key_constructor/constructors.py | 106 +
rest_framework_extensions/mixins.py | 85 +
rest_framework_extensions/models.py | 0
rest_framework_extensions/permissions/__init__.py | 6 +
.../extended_django_object_permissions.py | 21 +
rest_framework_extensions/routers.py | 245 ++
rest_framework_extensions/serializers.py | 42 +
rest_framework_extensions/settings.py | 39 +
rest_framework_extensions/test.py | 173 ++
rest_framework_extensions/utils.py | 88 +
setup.cfg | 2 +
setup.py | 79 +
test | 0
tests_app/__init__.py | 0
tests_app/apps.py | 5 +
tests_app/models.py | 0
tests_app/plugins.py | 78 +
tests_app/requirements.txt | 5 +
tests_app/settings.py | 146 ++
tests_app/tests/__init__.py | 0
tests_app/tests/functional/__init__.py | 0
tests_app/tests/functional/cache/__init__.py | 1 +
.../tests/functional/cache/decorators/__init__.py | 1 +
.../tests/functional/cache/decorators/tests.py | 17 +
.../tests/functional/cache/decorators/urls.py | 9 +
.../tests/functional/cache/decorators/views.py | 11 +
tests_app/tests/functional/examples/__init__.py | 1 +
.../tests/functional/examples/etags/__init__.py | 1 +
.../etags/remove_etag_gzip_postfix/__init__.py | 1 +
.../etags/remove_etag_gzip_postfix/middleware.py | 8 +
.../etags/remove_etag_gzip_postfix/tests.py | 29 +
.../etags/remove_etag_gzip_postfix/urls.py | 9 +
.../etags/remove_etag_gzip_postfix/views.py | 16 +
.../tests/functional/key_constructor/__init__.py | 1 +
.../functional/key_constructor/bits/__init__.py | 1 +
.../functional/key_constructor/bits/models.py | 16 +
.../functional/key_constructor/bits/serializers.py | 9 +
.../tests/functional/key_constructor/bits/tests.py | 37 +
.../tests/functional/key_constructor/bits/urls.py | 9 +
.../tests/functional/key_constructor/bits/views.py | 14 +
tests_app/tests/functional/mixins/__init__.py | 0
.../mixins/detail_serializer_mixin/__init__.py | 1 +
.../mixins/detail_serializer_mixin/models.py | 11 +
.../mixins/detail_serializer_mixin/serializers.py | 23 +
.../mixins/detail_serializer_mixin/tests.py | 117 +
.../mixins/detail_serializer_mixin/urls.py | 19 +
.../mixins/detail_serializer_mixin/views.py | 43 +
.../mixins/list_destroy_model_mixin/__init__.py | 1 +
.../mixins/list_destroy_model_mixin/models.py | 9 +
.../mixins/list_destroy_model_mixin/tests.py | 89 +
.../mixins/list_destroy_model_mixin/urls.py | 10 +
.../mixins/list_destroy_model_mixin/views.py | 32 +
.../mixins/list_update_model_mixin/__init__.py | 1 +
.../mixins/list_update_model_mixin/models.py | 20 +
.../mixins/list_update_model_mixin/serializers.py | 27 +
.../mixins/list_update_model_mixin/tests.py | 201 ++
.../mixins/list_update_model_mixin/urls.py | 11 +
.../mixins/list_update_model_mixin/views.py | 36 +
.../mixins/paginate_by_max_mixin/__init__.py | 1 +
.../mixins/paginate_by_max_mixin/models.py | 11 +
.../mixins/paginate_by_max_mixin/pagination.py | 17 +
.../mixins/paginate_by_max_mixin/serializers.py | 13 +
.../mixins/paginate_by_max_mixin/tests.py | 72 +
.../mixins/paginate_by_max_mixin/urls.py | 15 +
.../mixins/paginate_by_max_mixin/views.py | 24 +
tests_app/tests/functional/permissions/__init__.py | 1 +
.../extended_django_object_permissions/__init__.py | 1 +
.../extended_django_object_permissions/models.py | 13 +
.../extended_django_object_permissions/tests.py | 239 ++
.../extended_django_object_permissions/urls.py | 20 +
.../extended_django_object_permissions/views.py | 56 +
tests_app/tests/functional/routers/__init__.py | 1 +
.../routers/extended_default_router/__init__.py | 1 +
.../routers/extended_default_router/models.py | 25 +
.../routers/extended_default_router/tests.py | 25 +
.../routers/extended_default_router/urls.py | 22 +
.../routers/extended_default_router/views.py | 22 +
tests_app/tests/functional/routers/models.py | 7 +
.../routers/nested_router_mixin/__init__.py | 1 +
.../routers/nested_router_mixin/models.py | 53 +
.../routers/nested_router_mixin/serializers.py | 67 +
.../routers/nested_router_mixin/tests.py | 531 ++++
.../functional/routers/nested_router_mixin/urls.py | 28 +
.../nested_router_mixin/urls_generic_relations.py | 24 +
.../urls_parent_viewset_lookup.py | 17 +
.../routers/nested_router_mixin/views.py | 100 +
tests_app/tests/functional/routers/tests.py | 43 +
tests_app/tests/functional/routers/views.py | 17 +
tests_app/tests/unit/__init__.py | 0
tests_app/tests/unit/cache/__init__.py | 0
tests_app/tests/unit/cache/decorators/__init__.py | 1 +
tests_app/tests/unit/cache/decorators/tests.py | 252 ++
tests_app/tests/unit/etag/__init__.py | 0
tests_app/tests/unit/etag/decorators/__init__.py | 1 +
tests_app/tests/unit/etag/decorators/tests.py | 324 +++
tests_app/tests/unit/key_constructor/__init__.py | 1 +
.../tests/unit/key_constructor/bits/__init__.py | 1 +
.../tests/unit/key_constructor/bits/models.py | 9 +
tests_app/tests/unit/key_constructor/bits/tests.py | 509 ++++
.../unit/key_constructor/constructor/__init__.py | 1 +
.../unit/key_constructor/constructor/tests.py | 273 ++
tests_app/tests/unit/routers/__init__.py | 0
.../unit/routers/nested_router_mixin/__init__.py | 1 +
.../unit/routers/nested_router_mixin/models.py | 30 +
.../unit/routers/nested_router_mixin/tests.py | 114 +
.../unit/routers/nested_router_mixin/views.py | 20 +
tests_app/tests/unit/routers/tests.py | 184 ++
tests_app/tests/unit/serializers/__init__.py | 1 +
tests_app/tests/unit/serializers/models.py | 28 +
tests_app/tests/unit/serializers/serializers.py | 51 +
tests_app/tests/unit/serializers/tests.py | 243 ++
tests_app/tests/unit/utils/__init__.py | 1 +
tests_app/tests/unit/utils/tests.py | 22 +
tests_app/testutils.py | 50 +
tox.ini | 44 +
142 files changed, 11528 insertions(+)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..2971916
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,8 @@
+__pycache__/
+*.pyc
+*.egg-info
+.tox
+*.egg
+.idea
+env
+dist
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..59c65a7
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,20 @@
+language: python
+
+python:
+ - "3.5"
+ - "3.4"
+ - "2.7"
+
+env:
+ - TOX_ENV=django.1.10
+ - TOX_ENV=django.1.9
+ - TOX_ENV=django.1.8.lts
+
+matrix:
+ fast_finish: true
+
+install:
+ - pip install tox
+
+script:
+ - tox -e $TOX_ENV -- tests_app
\ No newline at end of file
diff --git a/AUTHORS.md b/AUTHORS.md
new file mode 100644
index 0000000..43baae8
--- /dev/null
+++ b/AUTHORS.md
@@ -0,0 +1,11 @@
+## Original Author
+---------------
+Gennady Chibisov https://github.com/chibisov
+
+## Core maintainer
+Asif Saifuddin https://github.com/auvipy
+
+
+## Contributors
+------------
+Luke Murphy https://github.com/lwm
diff --git a/GNUmakefile b/GNUmakefile
new file mode 100644
index 0000000..3365ee8
--- /dev/null
+++ b/GNUmakefile
@@ -0,0 +1,7 @@
+build_docs:
+ python docs/backdoc.py --source docs/index.md --title "Django Rest Framework extensions documentation" > docs/index.html
+ python docs/post_process_docs.py
+
+watch_docs:
+ make build_docs
+ watchmedo shell-command -p "*.md" -R -c "make build_docs" docs/
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..2f0fd99
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2013 Gennady Chibisov.
+
+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:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+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.
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..83b9421
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,7 @@
+include LICENSE
+include README.md
+include tox.ini
+recursive-include docs *.md *.html *.txt *.py
+recursive-include tests_app requirements.txt *.py
+recursive-exclude * __pycache__
+global-exclude *pyc
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..3d8d1f9
--- /dev/null
+++ b/README.md
@@ -0,0 +1,144 @@
+## Django REST Framework extensions
+
+DRF-extensions is a collection of custom extensions for [Django REST Framework](https://github.com/tomchristie/django-rest-framework)
+
+Full documentation for project is available at [http://chibisov.github.io/drf-extensions/docs](http://chibisov.github.io/drf-extensions/docs)
+
+[![Build Status](https://travis-ci.org/chibisov/drf-extensions.png?branch=master)](https://travis-ci.org/chibisov/drf-extensions)
+[![Downloads](https://pypip.in/download/drf-extensions/badge.png)](https://pypi.python.org/pypi/drf-extensions/)
+[![Latest Version](https://pypip.in/version/drf-extensions/badge.png)](https://pypi.python.org/pypi/drf-extensions/)
+
+
+## Requirements
+
+* Tested for python 2.7 and 3.4 versions
+* Tested for all releases of Django Rest Framework from 2.3.5 to 3.0.4 versions (pypi 0.2.8)
+* Tested for Django from 1.8 to 1.10 versions
+* master branch is supported with django 1.8 to 1.10 and drf 3.3.* + only
+
+## Installation:
+
+ pip install drf-extensions
+
+## Some features
+
+* DetailSerializerMixin
+* Caching
+* Conditional requests
+* Customizable key construction for caching and conditional requests
+* Nested routes
+* Bulk operations
+
+Read more in [documentation](http://chibisov.github.io/drf-extensions/docs)
+
+## Development
+
+Running the tests:
+
+ $ pip install tox
+ $ tox -- tests_app
+
+Running test for exact environment:
+
+ $ tox -e py27-drf2.3.5 -- tests_app
+
+Recreate envs before running tests:
+
+ $ tox --recreate -- tests_app
+
+Pass custom arguments:
+
+ $ tox -- tests_app --verbosity=3
+
+Run with pdb support:
+
+ $ tox -- tests_app --processes=0 --nocapture
+
+Run exact TestCase:
+
+ $ tox -- tests_app.tests.unit.mixins.tests:DetailSerializerMixinTest_serializer_detail_class
+
+Run tests from exact module:
+
+ $ tox -- tests_app.tests.unit.mixins.tests
+
+Build docs:
+
+ $ make build_docs
+
+Automatically build docs by watching changes:
+
+ $ pip install watchdog
+ $ make watch_docs
+
+## Developing new features
+
+Every new feature should be:
+
+* Documented
+* Tested
+* Implemented
+* Pushed to main repository
+
+### How to write documentation
+
+When new feature implementation starts you should place it into `development version` pull. Add `Development version`
+section to `Release notes` and describe every new feature in it. Use `#anchors` to facilitate navigation.
+
+Every feature should have title and information that it was implemented in current development version.
+
+For example if we've just implemented `Usage of the specific cache`:
+
+ ...
+
+ #### Usage of the specific cache
+
+ *New in DRF-extensions development version*
+
+ `@cache_response` can also take...
+
+ ...
+
+ ### Release notes
+
+ ...
+
+ #### Development version
+
+ * Added ability to [use a specific cache](#usage-of-the-specific-cache) for `@cache_response` decorator
+
+## Publishing new releases
+
+Increment version in `rest_framework_extensions/__init__.py`. For example:
+
+ __version__ = '0.2.2' # from 0.2.1
+
+Move to new version section all release notes in documentation.
+
+Add date for release note section.
+
+Replace in documentation all `New in DRF-extensions development version` notes to `New in DRF-extensions 0.2.2`.
+
+Rebuild documentation.
+
+Run tests.
+
+Commit changes with message "Version 0.2.2"
+
+Add new tag version for commit:
+
+ $ git tag 0.2.2
+
+Push to master with tags:
+
+ $ git push origin master --tags
+
+Don't forget to merge `master` to `gh-pages` branch and push to origin:
+
+ $ git co gh-pages
+ $ git merge --no-ff master
+ $ git push origin gh-pages
+
+Publish to pypi:
+
+ $ python setup.py publish
diff --git a/__init__.py b/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/docs/backdoc.py b/docs/backdoc.py
new file mode 100644
index 0000000..2875eea
--- /dev/null
+++ b/docs/backdoc.py
@@ -0,0 +1,2723 @@
+# -*- coding: utf-8 -*-
+#!/usr/bin/env python
+"""
+Backdoc is a tool for backbone-like documentation generation.
+Backdoc main goal is to help to generate one page documentation from one markdown source file.
+
+https://github.com/chibisov/backdoc
+"""
+import sys
+import argparse
+
+# -*- coding: utf-8 -*-
+#!/usr/bin/env python
+# Copyright (c) 2012 Trent Mick.
+# Copyright (c) 2007-2008 ActiveState Corp.
+# License: MIT (http://www.opensource.org/licenses/mit-license.php)
+
+r"""A fast and complete Python implementation of Markdown.
+
+[from http://daringfireball.net/projects/markdown/]
+> Markdown is a text-to-HTML filter; it translates an easy-to-read /
+> easy-to-write structured text format into HTML. Markdown's text
+> format is most similar to that of plain text email, and supports
+> features such as headers, *emphasis*, code blocks, blockquotes, and
+> links.
+>
+> Markdown's syntax is designed not as a generic markup language, but
+> specifically to serve as a front-end to (X)HTML. You can use span-level
+> HTML tags anywhere in a Markdown document, and you can use block level
+> HTML tags (like <div> and <table> as well).
+
+Module usage:
+
+ >>> import markdown2
+ >>> markdown2.markdown("*boo!*") # or use `html = markdown_path(PATH)`
+ u'<p><em>boo!</em></p>\n'
+
+ >>> markdowner = Markdown()
+ >>> markdowner.convert("*boo!*")
+ u'<p><em>boo!</em></p>\n'
+ >>> markdowner.convert("**boom!**")
+ u'<p><strong>boom!</strong></p>\n'
+
+This implementation of Markdown implements the full "core" syntax plus a
+number of extras (e.g., code syntax coloring, footnotes) as described on
+<https://github.com/trentm/python-markdown2/wiki/Extras>.
+"""
+
+cmdln_desc = """A fast and complete Python implementation of Markdown, a
+text-to-HTML conversion tool for web writers.
+
+Supported extra syntax options (see -x|--extras option below and
+see <https://github.com/trentm/python-markdown2/wiki/Extras> for details):
+
+* code-friendly: Disable _ and __ for em and strong.
+* cuddled-lists: Allow lists to be cuddled to the preceding paragraph.
+* fenced-code-blocks: Allows a code block to not have to be indented
+ by fencing it with '```' on a line before and after. Based on
+ <http://github.github.com/github-flavored-markdown/> with support for
+ syntax highlighting.
+* footnotes: Support footnotes as in use on daringfireball.net and
+ implemented in other Markdown processors (tho not in Markdown.pl v1.0.1).
+* header-ids: Adds "id" attributes to headers. The id value is a slug of
+ the header text.
+* html-classes: Takes a dict mapping html tag names (lowercase) to a
+ string to use for a "class" tag attribute. Currently only supports
+ "pre" and "code" tags. Add an issue if you require this for other tags.
+* markdown-in-html: Allow the use of `markdown="1"` in a block HTML tag to
+ have markdown processing be done on its contents. Similar to
+ <http://michelf.com/projects/php-markdown/extra/#markdown-attr> but with
+ some limitations.
+* metadata: Extract metadata from a leading '---'-fenced block.
+ See <https://github.com/trentm/python-markdown2/issues/77> for details.
+* nofollow: Add `rel="nofollow"` to add `<a>` tags with an href. See
+ <http://en.wikipedia.org/wiki/Nofollow>.
+* pyshell: Treats unindented Python interactive shell sessions as <code>
+ blocks.
+* link-patterns: Auto-link given regex patterns in text (e.g. bug number
+ references, revision number references).
+* smarty-pants: Replaces ' and " with curly quotation marks or curly
+ apostrophes. Replaces --, ---, ..., and . . . with en dashes, em dashes,
+ and ellipses.
+* toc: The returned HTML string gets a new "toc_html" attribute which is
+ a Table of Contents for the document. (experimental)
+* xml: Passes one-liner processing instructions and namespaced XML tags.
+* wiki-tables: Google Code Wiki-style tables. See
+ <http://code.google.com/p/support/wiki/WikiSyntax#Tables>.
+"""
+
+# Dev Notes:
+# - Python's regex syntax doesn't have '\z', so I'm using '\Z'. I'm
+# not yet sure if there implications with this. Compare 'pydoc sre'
+# and 'perldoc perlre'.
+
+__version_info__ = (2, 1, 1)
+__version__ = '.'.join(map(str, __version_info__))
+__author__ = "Trent Mick"
+
+import os
+import sys
+from pprint import pprint
+import re
+import logging
+try:
+ from hashlib import md5
+except ImportError:
+ from md5 import md5
+import optparse
+from random import random, randint
+import codecs
+
+
+#---- Python version compat
+
+try:
+ from urllib.parse import quote # python3
+except ImportError:
+ from urllib import quote # python2
+
+if sys.version_info[:2] < (2,4):
+ from sets import Set as set
+ def reversed(sequence):
+ for i in sequence[::-1]:
+ yield i
+
+# Use `bytes` for byte strings and `unicode` for unicode strings (str in Py3).
+if sys.version_info[0] <= 2:
+ py3 = False
+ try:
+ bytes
+ except NameError:
+ bytes = str
+ base_string_type = basestring
+elif sys.version_info[0] >= 3:
+ py3 = True
+ unicode = str
+ base_string_type = str
+
+
+
+#---- globals
+
+DEBUG = False
+log = logging.getLogger("markdown")
+
+DEFAULT_TAB_WIDTH = 4
+
+
+SECRET_SALT = bytes(randint(0, 1000000))
+def _hash_text(s):
+ return 'md5-' + md5(SECRET_SALT + s.encode("utf-8")).hexdigest()
+
+# Table of hash values for escaped characters:
+g_escape_table = dict([(ch, _hash_text(ch))
+ for ch in '\\`*_{}[]()>#+-.!'])
+
+
+
+#---- exceptions
+
+class MarkdownError(Exception):
+ pass
+
+
+
+#---- public api
+
+def markdown_path(path, encoding="utf-8",
+ html4tags=False, tab_width=DEFAULT_TAB_WIDTH,
+ safe_mode=None, extras=None, link_patterns=None,
+ use_file_vars=False):
+ fp = codecs.open(path, 'r', encoding)
+ text = fp.read()
+ fp.close()
+ return Markdown(html4tags=html4tags, tab_width=tab_width,
+ safe_mode=safe_mode, extras=extras,
+ link_patterns=link_patterns,
+ use_file_vars=use_file_vars).convert(text)
+
+def markdown(text, html4tags=False, tab_width=DEFAULT_TAB_WIDTH,
+ safe_mode=None, extras=None, link_patterns=None,
+ use_file_vars=False):
+ return Markdown(html4tags=html4tags, tab_width=tab_width,
+ safe_mode=safe_mode, extras=extras,
+ link_patterns=link_patterns,
+ use_file_vars=use_file_vars).convert(text)
+
+class Markdown(object):
+ # The dict of "extras" to enable in processing -- a mapping of
+ # extra name to argument for the extra. Most extras do not have an
+ # argument, in which case the value is None.
+ #
+ # This can be set via (a) subclassing and (b) the constructor
+ # "extras" argument.
+ extras = None
+
+ urls = None
+ titles = None
+ html_blocks = None
+ html_spans = None
+ html_removed_text = "[HTML_REMOVED]" # for compat with markdown.py
+
+ # Used to track when we're inside an ordered or unordered list
+ # (see _ProcessListItems() for details):
+ list_level = 0
+
+ _ws_only_line_re = re.compile(r"^[ \t]+$", re.M)
+
+ def __init__(self, html4tags=False, tab_width=4, safe_mode=None,
+ extras=None, link_patterns=None, use_file_vars=False):
+ if html4tags:
+ self.empty_element_suffix = ">"
+ else:
+ self.empty_element_suffix = " />"
+ self.tab_width = tab_width
+
+ # For compatibility with earlier markdown2.py and with
+ # markdown.py's safe_mode being a boolean,
+ # safe_mode == True -> "replace"
+ if safe_mode is True:
+ self.safe_mode = "replace"
+ else:
+ self.safe_mode = safe_mode
+
+ # Massaging and building the "extras" info.
+ if self.extras is None:
+ self.extras = {}
+ elif not isinstance(self.extras, dict):
+ self.extras = dict([(e, None) for e in self.extras])
+ if extras:
+ if not isinstance(extras, dict):
+ extras = dict([(e, None) for e in extras])
+ self.extras.update(extras)
+ assert isinstance(self.extras, dict)
+ if "toc" in self.extras and not "header-ids" in self.extras:
+ self.extras["header-ids"] = None # "toc" implies "header-ids"
+ self._instance_extras = self.extras.copy()
+
+ self.link_patterns = link_patterns
+ self.use_file_vars = use_file_vars
+ self._outdent_re = re.compile(r'^(\t|[ ]{1,%d})' % tab_width, re.M)
+
+ self._escape_table = g_escape_table.copy()
+ if "smarty-pants" in self.extras:
+ self._escape_table['"'] = _hash_text('"')
+ self._escape_table["'"] = _hash_text("'")
+
+ def reset(self):
+ self.urls = {}
+ self.titles = {}
+ self.html_blocks = {}
+ self.html_spans = {}
+ self.list_level = 0
+ self.extras = self._instance_extras.copy()
+ if "footnotes" in self.extras:
+ self.footnotes = {}
+ self.footnote_ids = []
+ if "header-ids" in self.extras:
+ self._count_from_header_id = {} # no `defaultdict` in Python 2.4
+ if "metadata" in self.extras:
+ self.metadata = {}
+
+ # Per <https://developer.mozilla.org/en-US/docs/HTML/Element/a> "rel"
+ # should only be used in <a> tags with an "href" attribute.
+ _a_nofollow = re.compile(r"<(a)([^>]*href=)", re.IGNORECASE)
+
+ def convert(self, text):
+ """Convert the given text."""
+ # Main function. The order in which other subs are called here is
+ # essential. Link and image substitutions need to happen before
+ # _EscapeSpecialChars(), so that any *'s or _'s in the <a>
+ # and <img> tags get encoded.
+
+ # Clear the global hashes. If we don't clear these, you get conflicts
+ # from other articles when generating a page which contains more than
+ # one article (e.g. an index page that shows the N most recent
+ # articles):
+ self.reset()
+
+ if not isinstance(text, unicode):
+ #TODO: perhaps shouldn't presume UTF-8 for string input?
+ text = unicode(text, 'utf-8')
+
+ if self.use_file_vars:
+ # Look for emacs-style file variable hints.
+ emacs_vars = self._get_emacs_vars(text)
+ if "markdown-extras" in emacs_vars:
+ splitter = re.compile("[ ,]+")
+ for e in splitter.split(emacs_vars["markdown-extras"]):
+ if '=' in e:
+ ename, earg = e.split('=', 1)
+ try:
+ earg = int(earg)
+ except ValueError:
+ pass
+ else:
+ ename, earg = e, None
+ self.extras[ename] = earg
+
+ # Standardize line endings:
+ text = re.sub("\r\n|\r", "\n", text)
+
+ # Make sure $text ends with a couple of newlines:
+ text += "\n\n"
+
+ # Convert all tabs to spaces.
+ text = self._detab(text)
+
+ # Strip any lines consisting only of spaces and tabs.
+ # This makes subsequent regexen easier to write, because we can
+ # match consecutive blank lines with /\n+/ instead of something
+ # contorted like /[ \t]*\n+/ .
+ text = self._ws_only_line_re.sub("", text)
+
+ # strip metadata from head and extract
+ if "metadata" in self.extras:
+ text = self._extract_metadata(text)
+
+ text = self.preprocess(text)
+
+ if self.safe_mode:
+ text = self._hash_html_spans(text)
+
+ # Turn block-level HTML blocks into hash entries
+ text = self._hash_html_blocks(text, raw=True)
+
+ # Strip link definitions, store in hashes.
+ if "footnotes" in self.extras:
+ # Must do footnotes first because an unlucky footnote defn
+ # looks like a link defn:
+ # [^4]: this "looks like a link defn"
+ text = self._strip_footnote_definitions(text)
+ text = self._strip_link_definitions(text)
+
+ text = self._run_block_gamut(text)
+
+ if "footnotes" in self.extras:
+ text = self._add_footnotes(text)
+
+ text = self.postprocess(text)
+
+ text = self._unescape_special_chars(text)
+
+ if self.safe_mode:
+ text = self._unhash_html_spans(text)
+
+ if "nofollow" in self.extras:
+ text = self._a_nofollow.sub(r'<\1 rel="nofollow"\2', text)
+
+ text += "\n"
+
+ rv = UnicodeWithAttrs(text)
+ if "toc" in self.extras:
+ rv._toc = self._toc
+ if "metadata" in self.extras:
+ rv.metadata = self.metadata
+ return rv
+
+ def postprocess(self, text):
+ """A hook for subclasses to do some postprocessing of the html, if
+ desired. This is called before unescaping of special chars and
+ unhashing of raw HTML spans.
+ """
+ return text
+
+ def preprocess(self, text):
+ """A hook for subclasses to do some preprocessing of the Markdown, if
+ desired. This is called after basic formatting of the text, but prior
+ to any extras, safe mode, etc. processing.
+ """
+ return text
+
+ # Is metadata if the content starts with '---'-fenced `key: value`
+ # pairs. E.g. (indented for presentation):
+ # ---
+ # foo: bar
+ # another-var: blah blah
+ # ---
+ _metadata_pat = re.compile("""^---[ \t]*\n((?:[ \t]*[^ \t:]+[ \t]*:[^\n]*\n)+)---[ \t]*\n""")
+
+ def _extract_metadata(self, text):
+ # fast test
+ if not text.startswith("---"):
+ return text
+ match = self._metadata_pat.match(text)
+ if not match:
+ return text
+
+ tail = text[len(match.group(0)):]
+ metadata_str = match.group(1).strip()
+ for line in metadata_str.split('\n'):
+ key, value = line.split(':', 1)
+ self.metadata[key.strip()] = value.strip()
+
+ return tail
+
+
+ _emacs_oneliner_vars_pat = re.compile(r"-\*-\s*([^\r\n]*?)\s*-\*-", re.UNICODE)
+ # This regular expression is intended to match blocks like this:
+ # PREFIX Local Variables: SUFFIX
+ # PREFIX mode: Tcl SUFFIX
+ # PREFIX End: SUFFIX
+ # Some notes:
+ # - "[ \t]" is used instead of "\s" to specifically exclude newlines
+ # - "(\r\n|\n|\r)" is used instead of "$" because the sre engine does
+ # not like anything other than Unix-style line terminators.
+ _emacs_local_vars_pat = re.compile(r"""^
+ (?P<prefix>(?:[^\r\n|\n|\r])*?)
+ [\ \t]*Local\ Variables:[\ \t]*
+ (?P<suffix>.*?)(?:\r\n|\n|\r)
+ (?P<content>.*?\1End:)
+ """, re.IGNORECASE | re.MULTILINE | re.DOTALL | re.VERBOSE)
+
+ def _get_emacs_vars(self, text):
+ """Return a dictionary of emacs-style local variables.
+
+ Parsing is done loosely according to this spec (and according to
+ some in-practice deviations from this):
+ http://www.gnu.org/software/emacs/manual/html_node/emacs/Specifying-File-Variables.html#Specifying-File-Variables
+ """
+ emacs_vars = {}
+ SIZE = pow(2, 13) # 8kB
+
+ # Search near the start for a '-*-'-style one-liner of variables.
+ head = text[:SIZE]
+ if "-*-" in head:
+ match = self._emacs_oneliner_vars_pat.search(head)
+ if match:
+ emacs_vars_str = match.group(1)
+ assert '\n' not in emacs_vars_str
+ emacs_var_strs = [s.strip() for s in emacs_vars_str.split(';')
+ if s.strip()]
+ if len(emacs_var_strs) == 1 and ':' not in emacs_var_strs[0]:
+ # While not in the spec, this form is allowed by emacs:
+ # -*- Tcl -*-
+ # where the implied "variable" is "mode". This form
+ # is only allowed if there are no other variables.
+ emacs_vars["mode"] = emacs_var_strs[0].strip()
+ else:
+ for emacs_var_str in emacs_var_strs:
+ try:
+ variable, value = emacs_var_str.strip().split(':', 1)
+ except ValueError:
+ log.debug("emacs variables error: malformed -*- "
+ "line: %r", emacs_var_str)
+ continue
+ # Lowercase the variable name because Emacs allows "Mode"
+ # or "mode" or "MoDe", etc.
+ emacs_vars[variable.lower()] = value.strip()
+
+ tail = text[-SIZE:]
+ if "Local Variables" in tail:
+ match = self._emacs_local_vars_pat.search(tail)
+ if match:
+ prefix = match.group("prefix")
+ suffix = match.group("suffix")
+ lines = match.group("content").splitlines(0)
+ #print "prefix=%r, suffix=%r, content=%r, lines: %s"\
+ # % (prefix, suffix, match.group("content"), lines)
+
+ # Validate the Local Variables block: proper prefix and suffix
+ # usage.
+ for i, line in enumerate(lines):
+ if not line.startswith(prefix):
+ log.debug("emacs variables error: line '%s' "
+ "does not use proper prefix '%s'"
+ % (line, prefix))
+ return {}
+ # Don't validate suffix on last line. Emacs doesn't care,
+ # neither should we.
+ if i != len(lines)-1 and not line.endswith(suffix):
+ log.debug("emacs variables error: line '%s' "
+ "does not use proper suffix '%s'"
+ % (line, suffix))
+ return {}
+
+ # Parse out one emacs var per line.
+ continued_for = None
+ for line in lines[:-1]: # no var on the last line ("PREFIX End:")
+ if prefix: line = line[len(prefix):] # strip prefix
+ if suffix: line = line[:-len(suffix)] # strip suffix
+ line = line.strip()
+ if continued_for:
+ variable = continued_for
+ if line.endswith('\\'):
+ line = line[:-1].rstrip()
+ else:
+ continued_for = None
+ emacs_vars[variable] += ' ' + line
+ else:
+ try:
+ variable, value = line.split(':', 1)
+ except ValueError:
+ log.debug("local variables error: missing colon "
+ "in local variables entry: '%s'" % line)
+ continue
+ # Do NOT lowercase the variable name, because Emacs only
+ # allows "mode" (and not "Mode", "MoDe", etc.) in this block.
+ value = value.strip()
+ if value.endswith('\\'):
+ value = value[:-1].rstrip()
+ continued_for = variable
+ else:
+ continued_for = None
+ emacs_vars[variable] = value
+
+ # Unquote values.
+ for var, val in list(emacs_vars.items()):
+ if len(val) > 1 and (val.startswith('"') and val.endswith('"')
+ or val.startswith('"') and val.endswith('"')):
+ emacs_vars[var] = val[1:-1]
+
+ return emacs_vars
+
+ # Cribbed from a post by Bart Lateur:
+ # <http://www.nntp.perl.org/group/perl.macperl.anyperl/154>
+ _detab_re = re.compile(r'(.*?)\t', re.M)
+ def _detab_sub(self, match):
+ g1 = match.group(1)
+ return g1 + (' ' * (self.tab_width - len(g1) % self.tab_width))
+ def _detab(self, text):
+ r"""Remove (leading?) tabs from a file.
+
+ >>> m = Markdown()
+ >>> m._detab("\tfoo")
+ ' foo'
+ >>> m._detab(" \tfoo")
+ ' foo'
+ >>> m._detab("\t foo")
+ ' foo'
+ >>> m._detab(" foo")
+ ' foo'
+ >>> m._detab(" foo\n\tbar\tblam")
+ ' foo\n bar blam'
+ """
+ if '\t' not in text:
+ return text
+ return self._detab_re.subn(self._detab_sub, text)[0]
+
+ # I broke out the html5 tags here and add them to _block_tags_a and
+ # _block_tags_b. This way html5 tags are easy to keep track of.
+ _html5tags = '|article|aside|header|hgroup|footer|nav|section|figure|figcaption'
+
+ _block_tags_a = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del'
+ _block_tags_a += _html5tags
+
+ _strict_tag_block_re = re.compile(r"""
+ ( # save in \1
+ ^ # start of line (with re.M)
+ <(%s) # start tag = \2
+ \b # word break
+ (.*\n)*? # any number of lines, minimally matching
+ </\2> # the matching end tag
+ [ \t]* # trailing spaces/tabs
+ (?=\n+|\Z) # followed by a newline or end of document
+ )
+ """ % _block_tags_a,
+ re.X | re.M)
+
+ _block_tags_b = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math'
+ _block_tags_b += _html5tags
+
+ _liberal_tag_block_re = re.compile(r"""
+ ( # save in \1
+ ^ # start of line (with re.M)
+ <(%s) # start tag = \2
+ \b # word break
+ (.*\n)*? # any number of lines, minimally matching
+ .*</\2> # the matching end tag
+ [ \t]* # trailing spaces/tabs
+ (?=\n+|\Z) # followed by a newline or end of document
+ )
+ """ % _block_tags_b,
+ re.X | re.M)
+
+ _html_markdown_attr_re = re.compile(
+ r'''\s+markdown=("1"|'1')''')
+ def _hash_html_block_sub(self, match, raw=False):
+ html = match.group(1)
... 11521 lines suppressed ...
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/drf-extensions.git
More information about the Python-modules-commits
mailing list