18 | {% endblock %}
19 | {% block footer %}{% endblock %}
20 |
--------------------------------------------------------------------------------
/config/__init__.py:
--------------------------------------------------------------------------------
1 | class Config(object):
2 | PLATFORM = 'sqlite'
3 | DATABASE = '/tmp/blog.db'
4 | DEBUG = False
5 | TESTING = False
6 | SECRET_KEY = 'development key'
7 | MAX_PAGE_ENTRIES = 5
8 |
9 | class ProductionConfig(Config):
10 | DATABASE_URI = 'mysql://user@localhost/foo'
11 |
12 | class DevelopmentConfig(Config):
13 | DEBUG = True
14 |
15 | class TestinConfig(Config):
16 | TESTING = True
17 |
--------------------------------------------------------------------------------
/flask/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | flask
4 | ~~~~~
5 |
6 | A microframework based on Werkzeug. It's extensively documented
7 | and follows best practice patterns.
8 |
9 | :copyright: (c) 2010 by Armin Ronacher.
10 | :license: BSD, see LICENSE for more details.
11 | """
12 |
13 | # utilities we import from Werkzeug and Jinja2 that are unused
14 | # in the module but are exported as public interface.
15 | from werkzeug import abort, redirect
16 | from jinja2 import Markup, escape
17 |
18 | from .app import Flask, Request, Response
19 | from .config import Config
20 | from .helpers import url_for, jsonify, json_available, flash, \
21 | send_file, send_from_directory, get_flashed_messages, \
22 | get_template_attribute, make_response
23 | from .globals import current_app, g, request, session, _request_ctx_stack
24 | from .module import Module
25 | from .templating import render_template, render_template_string
26 | from .session import Session
27 |
28 | # the signals
29 | from .signals import signals_available, template_rendered, request_started, \
30 | request_finished, got_request_exception
31 |
32 | # only import json if it's available
33 | if json_available:
34 | from .helpers import json
35 |
--------------------------------------------------------------------------------
/flask/ctx.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | flask.ctx
4 | ~~~~~~~~~
5 |
6 | Implements the objects required to keep the context.
7 |
8 | :copyright: (c) 2010 by Armin Ronacher.
9 | :license: BSD, see LICENSE for more details.
10 | """
11 |
12 | from werkzeug.exceptions import HTTPException
13 |
14 | from .globals import _request_ctx_stack
15 | from .session import _NullSession
16 |
17 |
18 | class _RequestGlobals(object):
19 | pass
20 |
21 |
22 | class _RequestContext(object):
23 | """The request context contains all request relevant information. It is
24 | created at the beginning of the request and pushed to the
25 | `_request_ctx_stack` and removed at the end of it. It will create the
26 | URL adapter and request object for the WSGI environment provided.
27 | """
28 |
29 | def __init__(self, app, environ):
30 | self.app = app
31 | self.request = app.request_class(environ)
32 | self.url_adapter = app.create_url_adapter(self.request)
33 | self.session = app.open_session(self.request)
34 | if self.session is None:
35 | self.session = _NullSession()
36 | self.g = _RequestGlobals()
37 | self.flashes = None
38 |
39 | try:
40 | url_rule, self.request.view_args = \
41 | self.url_adapter.match(return_rule=True)
42 | self.request.url_rule = url_rule
43 | except HTTPException, e:
44 | self.request.routing_exception = e
45 |
46 | def push(self):
47 | """Binds the request context."""
48 | _request_ctx_stack.push(self)
49 |
50 | def pop(self):
51 | """Pops the request context."""
52 | _request_ctx_stack.pop()
53 |
54 | def __enter__(self):
55 | self.push()
56 | return self
57 |
58 | def __exit__(self, exc_type, exc_value, tb):
59 | # do not pop the request stack if we are in debug mode and an
60 | # exception happened. This will allow the debugger to still
61 | # access the request object in the interactive shell. Furthermore
62 | # the context can be force kept alive for the test client.
63 | # See flask.testing for how this works.
64 | if not self.request.environ.get('flask._preserve_context') and \
65 | (tb is None or not self.app.debug):
66 | self.pop()
67 |
--------------------------------------------------------------------------------
/flask/globals.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | flask.globals
4 | ~~~~~~~~~~~~~
5 |
6 | Defines all the global objects that are proxies to the current
7 | active context.
8 |
9 | :copyright: (c) 2010 by Armin Ronacher.
10 | :license: BSD, see LICENSE for more details.
11 | """
12 |
13 | from werkzeug import LocalStack, LocalProxy
14 |
15 | # context locals
16 | _request_ctx_stack = LocalStack()
17 | current_app = LocalProxy(lambda: _request_ctx_stack.top.app)
18 | request = LocalProxy(lambda: _request_ctx_stack.top.request)
19 | session = LocalProxy(lambda: _request_ctx_stack.top.session)
20 | g = LocalProxy(lambda: _request_ctx_stack.top.g)
21 |
--------------------------------------------------------------------------------
/flask/logging.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | flask.logging
4 | ~~~~~~~~~~~~~
5 |
6 | Implements the logging support for Flask.
7 |
8 | :copyright: (c) 2010 by Armin Ronacher.
9 | :license: BSD, see LICENSE for more details.
10 | """
11 |
12 | from __future__ import absolute_import
13 |
14 | from logging import getLogger, StreamHandler, Formatter, Logger, DEBUG
15 |
16 |
17 | def create_logger(app):
18 | """Creates a logger for the given application. This logger works
19 | similar to a regular Python logger but changes the effective logging
20 | level based on the application's debug flag. Furthermore this
21 | function also removes all attached handlers in case there was a
22 | logger with the log name before.
23 | """
24 |
25 | class DebugLogger(Logger):
26 | def getEffectiveLevel(x):
27 | return DEBUG if app.debug else Logger.getEffectiveLevel(x)
28 |
29 | class DebugHandler(StreamHandler):
30 | def emit(x, record):
31 | StreamHandler.emit(x, record) if app.debug else None
32 |
33 | handler = DebugHandler()
34 | handler.setLevel(DEBUG)
35 | handler.setFormatter(Formatter(app.debug_log_format))
36 | logger = getLogger(app.logger_name)
37 | # just in case that was not a new logger, get rid of all the handlers
38 | # already attached to it.
39 | del logger.handlers[:]
40 | logger.__class__ = DebugLogger
41 | logger.addHandler(handler)
42 | return logger
43 |
--------------------------------------------------------------------------------
/flask/session.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | flask.session
4 | ~~~~~~~~~~~~~
5 |
6 | Implements cookie based sessions based on Werkzeug's secure cookie
7 | system.
8 |
9 | :copyright: (c) 2010 by Armin Ronacher.
10 | :license: BSD, see LICENSE for more details.
11 | """
12 |
13 | from werkzeug.contrib.securecookie import SecureCookie
14 |
15 |
16 | class Session(SecureCookie):
17 | """Expands the session with support for switching between permanent
18 | and non-permanent sessions.
19 | """
20 |
21 | def _get_permanent(self):
22 | return self.get('_permanent', False)
23 |
24 | def _set_permanent(self, value):
25 | self['_permanent'] = bool(value)
26 |
27 | permanent = property(_get_permanent, _set_permanent)
28 | del _get_permanent, _set_permanent
29 |
30 |
31 | class _NullSession(Session):
32 | """Class used to generate nicer error messages if sessions are not
33 | available. Will still allow read-only access to the empty session
34 | but fail on setting.
35 | """
36 |
37 | def _fail(self, *args, **kwargs):
38 | raise RuntimeError('the session is unavailable because no secret '
39 | 'key was set. Set the secret_key on the '
40 | 'application to something unique and secret.')
41 | __setitem__ = __delitem__ = clear = pop = popitem = \
42 | update = setdefault = _fail
43 | del _fail
44 |
--------------------------------------------------------------------------------
/flask/signals.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | flask.signals
4 | ~~~~~~~~~~~~~
5 |
6 | Implements signals based on blinker if available, otherwise
7 | falls silently back to a noop
8 |
9 | :copyright: (c) 2010 by Armin Ronacher.
10 | :license: BSD, see LICENSE for more details.
11 | """
12 | signals_available = False
13 | try:
14 | from blinker import Namespace
15 | signals_available = True
16 | except ImportError:
17 | class Namespace(object):
18 | def signal(self, name, doc=None):
19 | return _FakeSignal(name, doc)
20 |
21 | class _FakeSignal(object):
22 | """If blinker is unavailable, create a fake class with the same
23 | interface that allows sending of signals but will fail with an
24 | error on anything else. Instead of doing anything on send, it
25 | will just ignore the arguments and do nothing instead.
26 | """
27 |
28 | def __init__(self, name, doc=None):
29 | self.name = name
30 | self.__doc__ = doc
31 | def _fail(self, *args, **kwargs):
32 | raise RuntimeError('signalling support is unavailable '
33 | 'because the blinker library is '
34 | 'not installed.')
35 | send = lambda *a, **kw: None
36 | connect = disconnect = has_receivers_for = receivers_for = \
37 | temporarily_connected_to = _fail
38 | del _fail
39 |
40 | # the namespace for code signals. If you are not flask code, do
41 | # not put signals in here. Create your own namespace instead.
42 | _signals = Namespace()
43 |
44 |
45 | # core signals. For usage examples grep the sourcecode or consult
46 | # the API documentation in docs/api.rst as well as docs/signals.rst
47 | template_rendered = _signals.signal('template-rendered')
48 | request_started = _signals.signal('request-started')
49 | request_finished = _signals.signal('request-finished')
50 | got_request_exception = _signals.signal('got-request-exception')
51 |
--------------------------------------------------------------------------------
/flask/templating.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | flask.templating
4 | ~~~~~~~~~~~~~~~~
5 |
6 | Implements the bridge to Jinja2.
7 |
8 | :copyright: (c) 2010 by Armin Ronacher.
9 | :license: BSD, see LICENSE for more details.
10 | """
11 | from jinja2 import BaseLoader, TemplateNotFound
12 |
13 | from .globals import _request_ctx_stack
14 | from .signals import template_rendered
15 |
16 |
17 | def _default_template_ctx_processor():
18 | """Default template context processor. Injects `request`,
19 | `session` and `g`.
20 | """
21 | reqctx = _request_ctx_stack.top
22 | return dict(
23 | config=reqctx.app.config,
24 | request=reqctx.request,
25 | session=reqctx.session,
26 | g=reqctx.g
27 | )
28 |
29 |
30 | class _DispatchingJinjaLoader(BaseLoader):
31 | """A loader that looks for templates in the application and all
32 | the module folders.
33 | """
34 |
35 | def __init__(self, app):
36 | self.app = app
37 |
38 | def get_source(self, environment, template):
39 | loader = None
40 | try:
41 | module, name = template.split('/', 1)
42 | loader = self.app.modules[module].jinja_loader
43 | except (ValueError, KeyError):
44 | pass
45 | # if there was a module and it has a loader, try this first
46 | if loader is not None:
47 | try:
48 | return loader.get_source(environment, name)
49 | except TemplateNotFound:
50 | pass
51 | # fall back to application loader if module failed
52 | return self.app.jinja_loader.get_source(environment, template)
53 |
54 | def list_templates(self):
55 | result = self.app.jinja_loader.list_templates()
56 | for name, module in self.app.modules.iteritems():
57 | if module.jinja_loader is not None:
58 | for template in module.jinja_loader.list_templates():
59 | result.append('%s/%s' % (name, template))
60 | return result
61 |
62 |
63 | def _render(template, context, app):
64 | """Renders the template and fires the signal"""
65 | rv = template.render(context)
66 | template_rendered.send(app, template=template, context=context)
67 | return rv
68 |
69 |
70 | def render_template(template_name, **context):
71 | """Renders a template from the template folder with the given
72 | context.
73 |
74 | :param template_name: the name of the template to be rendered
75 | :param context: the variables that should be available in the
76 | context of the template.
77 | """
78 | ctx = _request_ctx_stack.top
79 | ctx.app.update_template_context(context)
80 | return _render(ctx.app.jinja_env.get_template(template_name),
81 | context, ctx.app)
82 |
83 |
84 | def render_template_string(source, **context):
85 | """Renders a template from the given template source string
86 | with the given context.
87 |
88 | :param template_name: the sourcecode of the template to be
89 | rendered
90 | :param context: the variables that should be available in the
91 | context of the template.
92 | """
93 | ctx = _request_ctx_stack.top
94 | ctx.app.update_template_context(context)
95 | return _render(ctx.app.jinja_env.from_string(source),
96 | context, ctx.app)
97 |
--------------------------------------------------------------------------------
/flask/testing.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | flask.testing
4 | ~~~~~~~~~~~~~
5 |
6 | Implements test support helpers. This module is lazily imported
7 | and usually not used in production environments.
8 |
9 | :copyright: (c) 2010 by Armin Ronacher.
10 | :license: BSD, see LICENSE for more details.
11 | """
12 |
13 | from werkzeug import Client
14 | from flask import _request_ctx_stack
15 |
16 |
17 | class FlaskClient(Client):
18 | """Works like a regular Werkzeug test client but has some
19 | knowledge about how Flask works to defer the cleanup of the
20 | request context stack to the end of a with body when used
21 | in a with statement.
22 | """
23 |
24 | preserve_context = context_preserved = False
25 |
26 | def open(self, *args, **kwargs):
27 | if self.context_preserved:
28 | _request_ctx_stack.pop()
29 | self.context_preserved = False
30 | kwargs.setdefault('environ_overrides', {}) \
31 | ['flask._preserve_context'] = self.preserve_context
32 | old = _request_ctx_stack.top
33 | try:
34 | return Client.open(self, *args, **kwargs)
35 | finally:
36 | self.context_preserved = _request_ctx_stack.top is not old
37 |
38 | def __enter__(self):
39 | self.preserve_context = True
40 | return self
41 |
42 | def __exit__(self, exc_type, exc_value, tb):
43 | self.preserve_context = False
44 | if self.context_preserved:
45 | _request_ctx_stack.pop()
46 |
--------------------------------------------------------------------------------
/flask/wrappers.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | flask.wrappers
4 | ~~~~~~~~~~~~~~
5 |
6 | Implements the WSGI wrappers (request and response).
7 |
8 | :copyright: (c) 2010 by Armin Ronacher.
9 | :license: BSD, see LICENSE for more details.
10 | """
11 |
12 | from werkzeug import Request as RequestBase, Response as ResponseBase, \
13 | cached_property
14 |
15 | from .helpers import json, _assert_have_json
16 | from .globals import _request_ctx_stack
17 |
18 |
19 | class Request(RequestBase):
20 | """The request object used by default in flask. Remembers the
21 | matched endpoint and view arguments.
22 |
23 | It is what ends up as :class:`~flask.request`. If you want to replace
24 | the request object used you can subclass this and set
25 | :attr:`~flask.Flask.request_class` to your subclass.
26 | """
27 |
28 | #: the internal URL rule that matched the request. This can be
29 | #: useful to inspect which methods are allowed for the URL from
30 | #: a before/after handler (``request.url_rule.methods``) etc.
31 | #:
32 | #: .. versionadded:: 0.6
33 | url_rule = None
34 |
35 | #: a dict of view arguments that matched the request. If an exception
36 | #: happened when matching, this will be `None`.
37 | view_args = None
38 |
39 | #: if matching the URL failed, this is the exception that will be
40 | #: raised / was raised as part of the request handling. This is
41 | #: usually a :exc:`~werkzeug.exceptions.NotFound` exception or
42 | #: something similar.
43 | routing_exception = None
44 |
45 | @property
46 | def max_content_length(self):
47 | """Read-only view of the `MAX_CONTENT_LENGTH` config key."""
48 | ctx = _request_ctx_stack.top
49 | if ctx is not None:
50 | return ctx.app.config['MAX_CONTENT_LENGTH']
51 |
52 | @property
53 | def endpoint(self):
54 | """The endpoint that matched the request. This in combination with
55 | :attr:`view_args` can be used to reconstruct the same or a
56 | modified URL. If an exception happened when matching, this will
57 | be `None`.
58 | """
59 | if self.url_rule is not None:
60 | return self.url_rule.endpoint
61 |
62 | @property
63 | def module(self):
64 | """The name of the current module"""
65 | if self.url_rule and '.' in self.url_rule.endpoint:
66 | return self.url_rule.endpoint.rsplit('.', 1)[0]
67 |
68 | @cached_property
69 | def json(self):
70 | """If the mimetype is `application/json` this will contain the
71 | parsed JSON data.
72 | """
73 | if __debug__:
74 | _assert_have_json()
75 | if self.mimetype == 'application/json':
76 | return json.loads(self.data)
77 |
78 |
79 | class Response(ResponseBase):
80 | """The response object that is used by default in flask. Works like the
81 | response object from Werkzeug but is set to have a HTML mimetype by
82 | default. Quite often you don't have to create this object yourself because
83 | :meth:`~flask.Flask.make_response` will take care of that for you.
84 |
85 | If you want to replace the response object used you can subclass this and
86 | set :attr:`~flask.Flask.response_class` to your subclass.
87 | """
88 | default_mimetype = 'text/html'
89 |
--------------------------------------------------------------------------------
/index.yaml:
--------------------------------------------------------------------------------
1 | indexes:
2 |
3 | - kind: Entry
4 | properties:
5 | - name: tags
6 | - name: creation_date
7 | direction: desc
8 |
9 | # AUTOGENERATED
10 |
11 | # This index.yaml is automatically updated whenever the dev_appserver
12 | # detects that a new type of query is run. If you want to manage the
13 | # index.yaml file manually, remove the above marker line (the line
14 | # saying "# AUTOGENERATED"). If you want to manage some indexes
15 | # manually, move them above the marker line. The index.yaml file is
16 | # automatically uploaded to the admin console when you next deploy
17 | # your application using appcfg.py.
18 |
--------------------------------------------------------------------------------
/jinja2/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | jinja2
4 | ~~~~~~
5 |
6 | Jinja2 is a template engine written in pure Python. It provides a
7 | Django inspired non-XML syntax but supports inline expressions and
8 | an optional sandboxed environment.
9 |
10 | Nutshell
11 | --------
12 |
13 | Here a small example of a Jinja2 template::
14 |
15 | {% extends 'base.html' %}
16 | {% block title %}Memberlist{% endblock %}
17 | {% block content %}
18 |
23 | {% endblock %}
24 |
25 |
26 | :copyright: (c) 2010 by the Jinja Team.
27 | :license: BSD, see LICENSE for more details.
28 | """
29 | __docformat__ = 'restructuredtext en'
30 | try:
31 | __version__ = __import__('pkg_resources') \
32 | .get_distribution('Jinja2').version
33 | except:
34 | __version__ = 'unknown'
35 |
36 | # high level interface
37 | from jinja2.environment import Environment, Template
38 |
39 | # loaders
40 | from jinja2.loaders import BaseLoader, FileSystemLoader, PackageLoader, \
41 | DictLoader, FunctionLoader, PrefixLoader, ChoiceLoader, \
42 | ModuleLoader
43 |
44 | # bytecode caches
45 | from jinja2.bccache import BytecodeCache, FileSystemBytecodeCache, \
46 | MemcachedBytecodeCache
47 |
48 | # undefined types
49 | from jinja2.runtime import Undefined, DebugUndefined, StrictUndefined
50 |
51 | # exceptions
52 | from jinja2.exceptions import TemplateError, UndefinedError, \
53 | TemplateNotFound, TemplatesNotFound, TemplateSyntaxError, \
54 | TemplateAssertionError
55 |
56 | # decorators and public utilities
57 | from jinja2.filters import environmentfilter, contextfilter, \
58 | evalcontextfilter
59 | from jinja2.utils import Markup, escape, clear_caches, \
60 | environmentfunction, evalcontextfunction, contextfunction, \
61 | is_undefined
62 |
63 | __all__ = [
64 | 'Environment', 'Template', 'BaseLoader', 'FileSystemLoader',
65 | 'PackageLoader', 'DictLoader', 'FunctionLoader', 'PrefixLoader',
66 | 'ChoiceLoader', 'BytecodeCache', 'FileSystemBytecodeCache',
67 | 'MemcachedBytecodeCache', 'Undefined', 'DebugUndefined',
68 | 'StrictUndefined', 'TemplateError', 'UndefinedError', 'TemplateNotFound',
69 | 'TemplatesNotFound', 'TemplateSyntaxError', 'TemplateAssertionError',
70 | 'ModuleLoader', 'environmentfilter', 'contextfilter', 'Markup', 'escape',
71 | 'environmentfunction', 'contextfunction', 'clear_caches', 'is_undefined',
72 | 'evalcontextfilter', 'evalcontextfunction'
73 | ]
74 |
--------------------------------------------------------------------------------
/jinja2/defaults.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | jinja2.defaults
4 | ~~~~~~~~~~~~~~~
5 |
6 | Jinja default filters and tags.
7 |
8 | :copyright: (c) 2010 by the Jinja Team.
9 | :license: BSD, see LICENSE for more details.
10 | """
11 | from jinja2.utils import generate_lorem_ipsum, Cycler, Joiner
12 |
13 |
14 | # defaults for the parser / lexer
15 | BLOCK_START_STRING = '{%'
16 | BLOCK_END_STRING = '%}'
17 | VARIABLE_START_STRING = '{{'
18 | VARIABLE_END_STRING = '}}'
19 | COMMENT_START_STRING = '{#'
20 | COMMENT_END_STRING = '#}'
21 | LINE_STATEMENT_PREFIX = None
22 | LINE_COMMENT_PREFIX = None
23 | TRIM_BLOCKS = False
24 | NEWLINE_SEQUENCE = '\n'
25 |
26 |
27 | # default filters, tests and namespace
28 | from jinja2.filters import FILTERS as DEFAULT_FILTERS
29 | from jinja2.tests import TESTS as DEFAULT_TESTS
30 | DEFAULT_NAMESPACE = {
31 | 'range': xrange,
32 | 'dict': lambda **kw: kw,
33 | 'lipsum': generate_lorem_ipsum,
34 | 'cycler': Cycler,
35 | 'joiner': Joiner
36 | }
37 |
38 |
39 | # export all constants
40 | __all__ = tuple(x for x in locals().keys() if x.isupper())
41 |
--------------------------------------------------------------------------------
/jinja2/optimizer.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | jinja2.optimizer
4 | ~~~~~~~~~~~~~~~~
5 |
6 | The jinja optimizer is currently trying to constant fold a few expressions
7 | and modify the AST in place so that it should be easier to evaluate it.
8 |
9 | Because the AST does not contain all the scoping information and the
10 | compiler has to find that out, we cannot do all the optimizations we
11 | want. For example loop unrolling doesn't work because unrolled loops would
12 | have a different scoping.
13 |
14 | The solution would be a second syntax tree that has the scoping rules stored.
15 |
16 | :copyright: (c) 2010 by the Jinja Team.
17 | :license: BSD.
18 | """
19 | from jinja2 import nodes
20 | from jinja2.visitor import NodeTransformer
21 |
22 |
23 | def optimize(node, environment):
24 | """The context hint can be used to perform an static optimization
25 | based on the context given."""
26 | optimizer = Optimizer(environment)
27 | return optimizer.visit(node)
28 |
29 |
30 | class Optimizer(NodeTransformer):
31 |
32 | def __init__(self, environment):
33 | self.environment = environment
34 |
35 | def visit_If(self, node):
36 | """Eliminate dead code."""
37 | # do not optimize ifs that have a block inside so that it doesn't
38 | # break super().
39 | if node.find(nodes.Block) is not None:
40 | return self.generic_visit(node)
41 | try:
42 | val = self.visit(node.test).as_const()
43 | except nodes.Impossible:
44 | return self.generic_visit(node)
45 | if val:
46 | body = node.body
47 | else:
48 | body = node.else_
49 | result = []
50 | for node in body:
51 | result.extend(self.visit_list(node))
52 | return result
53 |
54 | def fold(self, node):
55 | """Do constant folding."""
56 | node = self.generic_visit(node)
57 | try:
58 | return nodes.Const.from_untrusted(node.as_const(),
59 | lineno=node.lineno,
60 | environment=self.environment)
61 | except nodes.Impossible:
62 | return node
63 |
64 | visit_Add = visit_Sub = visit_Mul = visit_Div = visit_FloorDiv = \
65 | visit_Pow = visit_Mod = visit_And = visit_Or = visit_Pos = visit_Neg = \
66 | visit_Not = visit_Compare = visit_Getitem = visit_Getattr = visit_Call = \
67 | visit_Filter = visit_Test = visit_CondExpr = fold
68 | del fold
69 |
--------------------------------------------------------------------------------
/jinja2/tests.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | jinja2.tests
4 | ~~~~~~~~~~~~
5 |
6 | Jinja test functions. Used with the "is" operator.
7 |
8 | :copyright: (c) 2010 by the Jinja Team.
9 | :license: BSD, see LICENSE for more details.
10 | """
11 | import re
12 | from jinja2.runtime import Undefined
13 |
14 | # nose, nothing here to test
15 | __test__ = False
16 |
17 |
18 | number_re = re.compile(r'^-?\d+(\.\d+)?$')
19 | regex_type = type(number_re)
20 |
21 |
22 | try:
23 | test_callable = callable
24 | except NameError:
25 | def test_callable(x):
26 | return hasattr(x, '__call__')
27 |
28 |
29 | def test_odd(value):
30 | """Return true if the variable is odd."""
31 | return value % 2 == 1
32 |
33 |
34 | def test_even(value):
35 | """Return true if the variable is even."""
36 | return value % 2 == 0
37 |
38 |
39 | def test_divisibleby(value, num):
40 | """Check if a variable is divisible by a number."""
41 | return value % num == 0
42 |
43 |
44 | def test_defined(value):
45 | """Return true if the variable is defined:
46 |
47 | .. sourcecode:: jinja
48 |
49 | {% if variable is defined %}
50 | value of variable: {{ variable }}
51 | {% else %}
52 | variable is not defined
53 | {% endif %}
54 |
55 | See the :func:`default` filter for a simple way to set undefined
56 | variables.
57 | """
58 | return not isinstance(value, Undefined)
59 |
60 |
61 | def test_undefined(value):
62 | """Like :func:`defined` but the other way round."""
63 | return isinstance(value, Undefined)
64 |
65 |
66 | def test_none(value):
67 | """Return true if the variable is none."""
68 | return value is None
69 |
70 |
71 | def test_lower(value):
72 | """Return true if the variable is lowercased."""
73 | return unicode(value).islower()
74 |
75 |
76 | def test_upper(value):
77 | """Return true if the variable is uppercased."""
78 | return unicode(value).isupper()
79 |
80 |
81 | def test_string(value):
82 | """Return true if the object is a string."""
83 | return isinstance(value, basestring)
84 |
85 |
86 | def test_number(value):
87 | """Return true if the variable is a number."""
88 | return isinstance(value, (int, long, float, complex))
89 |
90 |
91 | def test_sequence(value):
92 | """Return true if the variable is a sequence. Sequences are variables
93 | that are iterable.
94 | """
95 | try:
96 | len(value)
97 | value.__getitem__
98 | except:
99 | return False
100 | return True
101 |
102 |
103 | def test_sameas(value, other):
104 | """Check if an object points to the same memory address than another
105 | object:
106 |
107 | .. sourcecode:: jinja
108 |
109 | {% if foo.attribute is sameas false %}
110 | the foo attribute really is the `False` singleton
111 | {% endif %}
112 | """
113 | return value is other
114 |
115 |
116 | def test_iterable(value):
117 | """Check if it's possible to iterate over an object."""
118 | try:
119 | iter(value)
120 | except TypeError:
121 | return False
122 | return True
123 |
124 |
125 | def test_escaped(value):
126 | """Check if the value is escaped."""
127 | return hasattr(value, '__html__')
128 |
129 |
130 | TESTS = {
131 | 'odd': test_odd,
132 | 'even': test_even,
133 | 'divisibleby': test_divisibleby,
134 | 'defined': test_defined,
135 | 'undefined': test_undefined,
136 | 'none': test_none,
137 | 'lower': test_lower,
138 | 'upper': test_upper,
139 | 'string': test_string,
140 | 'number': test_number,
141 | 'sequence': test_sequence,
142 | 'iterable': test_iterable,
143 | 'callable': test_callable,
144 | 'sameas': test_sameas,
145 | 'escaped': test_escaped
146 | }
147 |
--------------------------------------------------------------------------------
/jinja2/testsuite/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | jinja2.testsuite
4 | ~~~~~~~~~~~~~~~~
5 |
6 | All the unittests of Jinja2. These tests can be executed by
7 | either running run-tests.py using multiple Python versions at
8 | the same time.
9 |
10 | :copyright: (c) 2010 by the Jinja Team.
11 | :license: BSD, see LICENSE for more details.
12 | """
13 | import os
14 | import re
15 | import sys
16 | import unittest
17 | from traceback import format_exception
18 | from jinja2 import loaders
19 |
20 |
21 | here = os.path.dirname(os.path.abspath(__file__))
22 |
23 | dict_loader = loaders.DictLoader({
24 | 'justdict.html': 'FOO'
25 | })
26 | package_loader = loaders.PackageLoader('jinja2.testsuite.res', 'templates')
27 | filesystem_loader = loaders.FileSystemLoader(here + '/res/templates')
28 | function_loader = loaders.FunctionLoader({'justfunction.html': 'FOO'}.get)
29 | choice_loader = loaders.ChoiceLoader([dict_loader, package_loader])
30 | prefix_loader = loaders.PrefixLoader({
31 | 'a': filesystem_loader,
32 | 'b': dict_loader
33 | })
34 |
35 |
36 | class JinjaTestCase(unittest.TestCase):
37 |
38 | ### use only these methods for testing. If you need standard
39 | ### unittest method, wrap them!
40 |
41 | def setup(self):
42 | pass
43 |
44 | def teardown(self):
45 | pass
46 |
47 | def setUp(self):
48 | self.setup()
49 |
50 | def tearDown(self):
51 | self.teardown()
52 |
53 | def assert_equal(self, a, b):
54 | return self.assertEqual(a, b)
55 |
56 | def assert_raises(self, *args, **kwargs):
57 | return self.assertRaises(*args, **kwargs)
58 |
59 | def assert_traceback_matches(self, callback, expected_tb):
60 | try:
61 | callback()
62 | except Exception, e:
63 | tb = format_exception(*sys.exc_info())
64 | if re.search(expected_tb.strip(), ''.join(tb)) is None:
65 | raise self.fail('Traceback did not match:\n\n%s\nexpected:\n%s'
66 | % (''.join(tb), expected_tb))
67 | else:
68 | self.fail('Expected exception')
69 |
70 |
71 | def suite():
72 | from jinja2.testsuite import ext, filters, tests, core_tags, \
73 | loader, inheritance, imports, lexnparse, security, api, \
74 | regression, debug, utils, doctests
75 | suite = unittest.TestSuite()
76 | suite.addTest(ext.suite())
77 | suite.addTest(filters.suite())
78 | suite.addTest(tests.suite())
79 | suite.addTest(core_tags.suite())
80 | suite.addTest(loader.suite())
81 | suite.addTest(inheritance.suite())
82 | suite.addTest(imports.suite())
83 | suite.addTest(lexnparse.suite())
84 | suite.addTest(security.suite())
85 | suite.addTest(api.suite())
86 | suite.addTest(regression.suite())
87 | suite.addTest(debug.suite())
88 | suite.addTest(utils.suite())
89 |
90 | # doctests will not run on python 3 currently. Too many issues
91 | # with that, do not test that on that platform.
92 | if sys.version_info < (3, 0):
93 | suite.addTest(doctests.suite())
94 |
95 | return suite
96 |
--------------------------------------------------------------------------------
/jinja2/testsuite/debug.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | jinja2.testsuite.debug
4 | ~~~~~~~~~~~~~~~~~~~~~~
5 |
6 | Tests the debug system.
7 |
8 | :copyright: (c) 2010 by the Jinja Team.
9 | :license: BSD, see LICENSE for more details.
10 | """
11 | import sys
12 | import unittest
13 |
14 | from jinja2.testsuite import JinjaTestCase, filesystem_loader
15 |
16 | from jinja2 import Environment, TemplateSyntaxError
17 |
18 | env = Environment(loader=filesystem_loader)
19 |
20 |
21 | class DebugTestCase(JinjaTestCase):
22 |
23 | if sys.version_info[:2] != (2, 4):
24 | def test_runtime_error(self):
25 | def test():
26 | tmpl.render(fail=lambda: 1 / 0)
27 | tmpl = env.get_template('broken.html')
28 | self.assert_traceback_matches(test, r'''
29 | File ".*?broken.html", line 2, in (top-level template code|)
30 | \{\{ fail\(\) \}\}
31 | File ".*?debug.pyc?", line \d+, in
32 | tmpl\.render\(fail=lambda: 1 / 0\)
33 | ZeroDivisionError: (int(eger)? )?division (or modulo )?by zero
34 | ''')
35 |
36 | def test_syntax_error(self):
37 | # XXX: the .*? is necessary for python3 which does not hide
38 | # some of the stack frames we don't want to show. Not sure
39 | # what's up with that, but that is not that critical. Should
40 | # be fixed though.
41 | self.assert_traceback_matches(lambda: env.get_template('syntaxerror.html'), r'''(?sm)
42 | File ".*?syntaxerror.html", line 4, in (template|)
43 | \{% endif %\}.*?
44 | (jinja2\.exceptions\.)?TemplateSyntaxError: Encountered unknown tag 'endif'. Jinja was looking for the following tags: 'endfor' or 'else'. The innermost block that needs to be closed is 'for'.
45 | ''')
46 |
47 | def test_regular_syntax_error(self):
48 | def test():
49 | raise TemplateSyntaxError('wtf', 42)
50 | self.assert_traceback_matches(test, r'''
51 | File ".*debug.pyc?", line \d+, in test
52 | raise TemplateSyntaxError\('wtf', 42\)
53 | (jinja2\.exceptions\.)?TemplateSyntaxError: wtf
54 | line 42''')
55 |
56 |
57 | def suite():
58 | suite = unittest.TestSuite()
59 | suite.addTest(unittest.makeSuite(DebugTestCase))
60 | return suite
61 |
--------------------------------------------------------------------------------
/jinja2/testsuite/doctests.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | jinja2.testsuite.doctests
4 | ~~~~~~~~~~~~~~~~~~~~~~~~~
5 |
6 | The doctests. Collects all tests we want to test from
7 | the Jinja modules.
8 |
9 | :copyright: (c) 2010 by the Jinja Team.
10 | :license: BSD, see LICENSE for more details.
11 | """
12 | import unittest
13 | import doctest
14 |
15 |
16 | def suite():
17 | from jinja2 import utils, sandbox, runtime, meta, loaders, \
18 | ext, environment, bccache, nodes
19 | suite = unittest.TestSuite()
20 | suite.addTest(doctest.DocTestSuite(utils))
21 | suite.addTest(doctest.DocTestSuite(sandbox))
22 | suite.addTest(doctest.DocTestSuite(runtime))
23 | suite.addTest(doctest.DocTestSuite(meta))
24 | suite.addTest(doctest.DocTestSuite(loaders))
25 | suite.addTest(doctest.DocTestSuite(ext))
26 | suite.addTest(doctest.DocTestSuite(environment))
27 | suite.addTest(doctest.DocTestSuite(bccache))
28 | suite.addTest(doctest.DocTestSuite(nodes))
29 | return suite
30 |
--------------------------------------------------------------------------------
/jinja2/testsuite/res/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/proudlygeek/proudlygeek-blog/5b9359973802197fec7d1c31349a8f5346d0ddc9/jinja2/testsuite/res/__init__.py
--------------------------------------------------------------------------------
/jinja2/testsuite/res/templates/broken.html:
--------------------------------------------------------------------------------
1 | Before
2 | {{ fail() }}
3 | After
4 |
--------------------------------------------------------------------------------
/jinja2/testsuite/res/templates/foo/test.html:
--------------------------------------------------------------------------------
1 | FOO
2 |
--------------------------------------------------------------------------------
/jinja2/testsuite/res/templates/syntaxerror.html:
--------------------------------------------------------------------------------
1 | Foo
2 | {% for item in broken %}
3 | ...
4 | {% endif %}
5 |
--------------------------------------------------------------------------------
/jinja2/testsuite/res/templates/test.html:
--------------------------------------------------------------------------------
1 | BAR
2 |
--------------------------------------------------------------------------------
/jinja2/testsuite/tests.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | jinja2.testsuite.tests
4 | ~~~~~~~~~~~~~~~~~~~~~~
5 |
6 | Who tests the tests?
7 |
8 | :copyright: (c) 2010 by the Jinja Team.
9 | :license: BSD, see LICENSE for more details.
10 | """
11 | import unittest
12 | from jinja2.testsuite import JinjaTestCase
13 |
14 | from jinja2 import Markup, Environment
15 |
16 | env = Environment()
17 |
18 |
19 | class TestsTestCase(JinjaTestCase):
20 |
21 | def test_defined(self):
22 | tmpl = env.from_string('{{ missing is defined }}|{{ true is defined }}')
23 | assert tmpl.render() == 'False|True'
24 |
25 | def test_even(self):
26 | tmpl = env.from_string('''{{ 1 is even }}|{{ 2 is even }}''')
27 | assert tmpl.render() == 'False|True'
28 |
29 | def test_odd(self):
30 | tmpl = env.from_string('''{{ 1 is odd }}|{{ 2 is odd }}''')
31 | assert tmpl.render() == 'True|False'
32 |
33 | def test_lower(self):
34 | tmpl = env.from_string('''{{ "foo" is lower }}|{{ "FOO" is lower }}''')
35 | assert tmpl.render() == 'True|False'
36 |
37 | def test_typechecks(self):
38 | tmpl = env.from_string('''
39 | {{ 42 is undefined }}
40 | {{ 42 is defined }}
41 | {{ 42 is none }}
42 | {{ none is none }}
43 | {{ 42 is number }}
44 | {{ 42 is string }}
45 | {{ "foo" is string }}
46 | {{ "foo" is sequence }}
47 | {{ [1] is sequence }}
48 | {{ range is callable }}
49 | {{ 42 is callable }}
50 | {{ range(5) is iterable }}
51 | ''')
52 | assert tmpl.render().split() == [
53 | 'False', 'True', 'False', 'True', 'True', 'False',
54 | 'True', 'True', 'True', 'True', 'False', 'True'
55 | ]
56 |
57 | def test_sequence(self):
58 | tmpl = env.from_string(
59 | '{{ [1, 2, 3] is sequence }}|'
60 | '{{ "foo" is sequence }}|'
61 | '{{ 42 is sequence }}'
62 | )
63 | assert tmpl.render() == 'True|True|False'
64 |
65 | def test_upper(self):
66 | tmpl = env.from_string('{{ "FOO" is upper }}|{{ "foo" is upper }}')
67 | assert tmpl.render() == 'True|False'
68 |
69 | def test_sameas(self):
70 | tmpl = env.from_string('{{ foo is sameas false }}|'
71 | '{{ 0 is sameas false }}')
72 | assert tmpl.render(foo=False) == 'True|False'
73 |
74 | def test_no_paren_for_arg1(self):
75 | tmpl = env.from_string('{{ foo is sameas none }}')
76 | assert tmpl.render(foo=None) == 'True'
77 |
78 | def test_escaped(self):
79 | env = Environment(autoescape=True)
80 | tmpl = env.from_string('{{ x is escaped }}|{{ y is escaped }}')
81 | assert tmpl.render(x='foo', y=Markup('foo')) == 'False|True'
82 |
83 |
84 | def suite():
85 | suite = unittest.TestSuite()
86 | suite.addTest(unittest.makeSuite(TestsTestCase))
87 | return suite
88 |
--------------------------------------------------------------------------------
/jinja2/testsuite/utils.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | jinja2.testsuite.utils
4 | ~~~~~~~~~~~~~~~~~~~~~~
5 |
6 | Tests utilities jinja uses.
7 |
8 | :copyright: (c) 2010 by the Jinja Team.
9 | :license: BSD, see LICENSE for more details.
10 | """
11 | import os
12 | import gc
13 | import unittest
14 |
15 | import pickle
16 |
17 | from jinja2.testsuite import JinjaTestCase
18 |
19 | from jinja2 import Environment, Undefined, DebugUndefined, \
20 | StrictUndefined, UndefinedError, Template, meta
21 | from jinja2.utils import LRUCache, escape, object_type_repr
22 |
23 |
24 | class LRUCacheTestCase(JinjaTestCase):
25 |
26 | def test_simple(self):
27 | d = LRUCache(3)
28 | d["a"] = 1
29 | d["b"] = 2
30 | d["c"] = 3
31 | d["a"]
32 | d["d"] = 4
33 | assert len(d) == 3
34 | assert 'a' in d and 'c' in d and 'd' in d and 'b' not in d
35 |
36 | def test_pickleable(self):
37 | cache = LRUCache(2)
38 | cache["foo"] = 42
39 | cache["bar"] = 23
40 | cache["foo"]
41 |
42 | for protocol in range(3):
43 | copy = pickle.loads(pickle.dumps(cache, protocol))
44 | assert copy.capacity == cache.capacity
45 | assert copy._mapping == cache._mapping
46 | assert copy._queue == cache._queue
47 |
48 |
49 | class HelpersTestCase(JinjaTestCase):
50 |
51 | def test_object_type_repr(self):
52 | class X(object):
53 | pass
54 | self.assert_equal(object_type_repr(42), 'int object')
55 | self.assert_equal(object_type_repr([]), 'list object')
56 | self.assert_equal(object_type_repr(X()),
57 | 'jinja2.testsuite.utils.X object')
58 | self.assert_equal(object_type_repr(None), 'None')
59 | self.assert_equal(object_type_repr(Ellipsis), 'Ellipsis')
60 |
61 |
62 | class MarkupLeakTestCase(JinjaTestCase):
63 |
64 | def test_markup_leaks(self):
65 | counts = set()
66 | for count in xrange(20):
67 | for item in xrange(1000):
68 | escape("foo")
69 | escape("")
70 | escape(u"foo")
71 | escape(u"")
72 | counts.add(len(gc.get_objects()))
73 | assert len(counts) == 1, 'ouch, c extension seems to leak objects'
74 |
75 |
76 | def suite():
77 | suite = unittest.TestSuite()
78 | suite.addTest(unittest.makeSuite(LRUCacheTestCase))
79 | suite.addTest(unittest.makeSuite(HelpersTestCase))
80 |
81 | # this test only tests the c extension
82 | if not hasattr(escape, 'func_code'):
83 | suite.addTest(unittest.makeSuite(MarkupLeakTestCase))
84 |
85 | return suite
86 |
--------------------------------------------------------------------------------
/jinja2/visitor.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | jinja2.visitor
4 | ~~~~~~~~~~~~~~
5 |
6 | This module implements a visitor for the nodes.
7 |
8 | :copyright: (c) 2010 by the Jinja Team.
9 | :license: BSD.
10 | """
11 | from jinja2.nodes import Node
12 |
13 |
14 | class NodeVisitor(object):
15 | """Walks the abstract syntax tree and call visitor functions for every
16 | node found. The visitor functions may return values which will be
17 | forwarded by the `visit` method.
18 |
19 | Per default the visitor functions for the nodes are ``'visit_'`` +
20 | class name of the node. So a `TryFinally` node visit function would
21 | be `visit_TryFinally`. This behavior can be changed by overriding
22 | the `get_visitor` function. If no visitor function exists for a node
23 | (return value `None`) the `generic_visit` visitor is used instead.
24 | """
25 |
26 | def get_visitor(self, node):
27 | """Return the visitor function for this node or `None` if no visitor
28 | exists for this node. In that case the generic visit function is
29 | used instead.
30 | """
31 | method = 'visit_' + node.__class__.__name__
32 | return getattr(self, method, None)
33 |
34 | def visit(self, node, *args, **kwargs):
35 | """Visit a node."""
36 | f = self.get_visitor(node)
37 | if f is not None:
38 | return f(node, *args, **kwargs)
39 | return self.generic_visit(node, *args, **kwargs)
40 |
41 | def generic_visit(self, node, *args, **kwargs):
42 | """Called if no explicit visitor function exists for a node."""
43 | for node in node.iter_child_nodes():
44 | self.visit(node, *args, **kwargs)
45 |
46 |
47 | class NodeTransformer(NodeVisitor):
48 | """Walks the abstract syntax tree and allows modifications of nodes.
49 |
50 | The `NodeTransformer` will walk the AST and use the return value of the
51 | visitor functions to replace or remove the old node. If the return
52 | value of the visitor function is `None` the node will be removed
53 | from the previous location otherwise it's replaced with the return
54 | value. The return value may be the original node in which case no
55 | replacement takes place.
56 | """
57 |
58 | def generic_visit(self, node, *args, **kwargs):
59 | for field, old_value in node.iter_fields():
60 | if isinstance(old_value, list):
61 | new_values = []
62 | for value in old_value:
63 | if isinstance(value, Node):
64 | value = self.visit(value, *args, **kwargs)
65 | if value is None:
66 | continue
67 | elif not isinstance(value, Node):
68 | new_values.extend(value)
69 | continue
70 | new_values.append(value)
71 | old_value[:] = new_values
72 | elif isinstance(old_value, Node):
73 | new_node = self.visit(old_value, *args, **kwargs)
74 | if new_node is None:
75 | delattr(node, field)
76 | else:
77 | setattr(node, field, new_node)
78 | return node
79 |
80 | def visit_list(self, node, *args, **kwargs):
81 | """As transformers may return lists in some places this method
82 | can be used to enforce a list as return value.
83 | """
84 | rv = self.visit(node, *args, **kwargs)
85 | if not isinstance(rv, list):
86 | rv = [rv]
87 | return rv
88 |
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from blog.views import app
3 |
4 | def main():
5 | if app.config['PLATFORM']=='sqlite':
6 | try:
7 | import sqlite3
8 | except:
9 | raise NameError("Sqlite3 module not found.")
10 |
11 | app.run()
12 |
13 | elif app.config['PLATFORM']=='gae':
14 | try:
15 | from google.appengine.ext.webapp.util import run_wsgi_app
16 | except:
17 | raise NameError ("Google App Engine SDK module not found.")
18 |
19 | run_wsgi_app(app)
20 |
21 | if __name__ == '__main__':
22 | main()
23 |
--------------------------------------------------------------------------------
/markdown/blockparser.py:
--------------------------------------------------------------------------------
1 |
2 | import markdown
3 |
4 | class State(list):
5 | """ Track the current and nested state of the parser.
6 |
7 | This utility class is used to track the state of the BlockParser and
8 | support multiple levels if nesting. It's just a simple API wrapped around
9 | a list. Each time a state is set, that state is appended to the end of the
10 | list. Each time a state is reset, that state is removed from the end of
11 | the list.
12 |
13 | Therefore, each time a state is set for a nested block, that state must be
14 | reset when we back out of that level of nesting or the state could be
15 | corrupted.
16 |
17 | While all the methods of a list object are available, only the three
18 | defined below need be used.
19 |
20 | """
21 |
22 | def set(self, state):
23 | """ Set a new state. """
24 | self.append(state)
25 |
26 | def reset(self):
27 | """ Step back one step in nested state. """
28 | self.pop()
29 |
30 | def isstate(self, state):
31 | """ Test that top (current) level is of given state. """
32 | if len(self):
33 | return self[-1] == state
34 | else:
35 | return False
36 |
37 | class BlockParser:
38 | """ Parse Markdown blocks into an ElementTree object.
39 |
40 | A wrapper class that stitches the various BlockProcessors together,
41 | looping through them and creating an ElementTree object.
42 | """
43 |
44 | def __init__(self):
45 | self.blockprocessors = markdown.odict.OrderedDict()
46 | self.state = State()
47 |
48 | def parseDocument(self, lines):
49 | """ Parse a markdown document into an ElementTree.
50 |
51 | Given a list of lines, an ElementTree object (not just a parent Element)
52 | is created and the root element is passed to the parser as the parent.
53 | The ElementTree object is returned.
54 |
55 | This should only be called on an entire document, not pieces.
56 |
57 | """
58 | # Create a ElementTree from the lines
59 | self.root = markdown.etree.Element(markdown.DOC_TAG)
60 | self.parseChunk(self.root, '\n'.join(lines))
61 | return markdown.etree.ElementTree(self.root)
62 |
63 | def parseChunk(self, parent, text):
64 | """ Parse a chunk of markdown text and attach to given etree node.
65 |
66 | While the ``text`` argument is generally assumed to contain multiple
67 | blocks which will be split on blank lines, it could contain only one
68 | block. Generally, this method would be called by extensions when
69 | block parsing is required.
70 |
71 | The ``parent`` etree Element passed in is altered in place.
72 | Nothing is returned.
73 |
74 | """
75 | self.parseBlocks(parent, text.split('\n\n'))
76 |
77 | def parseBlocks(self, parent, blocks):
78 | """ Process blocks of markdown text and attach to given etree node.
79 |
80 | Given a list of ``blocks``, each blockprocessor is stepped through
81 | until there are no blocks left. While an extension could potentially
82 | call this method directly, it's generally expected to be used internally.
83 |
84 | This is a public method as an extension may need to add/alter additional
85 | BlockProcessors which call this method to recursively parse a nested
86 | block.
87 |
88 | """
89 | while blocks:
90 | for processor in self.blockprocessors.values():
91 | if processor.test(parent, blocks[0]):
92 | processor.run(parent, blocks)
93 | break
94 |
95 |
96 |
--------------------------------------------------------------------------------
/markdown/commandline.py:
--------------------------------------------------------------------------------
1 | """
2 | COMMAND-LINE SPECIFIC STUFF
3 | =============================================================================
4 |
5 | The rest of the code is specifically for handling the case where Python
6 | Markdown is called from the command line.
7 | """
8 |
9 | import markdown
10 | import sys
11 | import logging
12 | from logging import DEBUG, INFO, WARN, ERROR, CRITICAL
13 |
14 | EXECUTABLE_NAME_FOR_USAGE = "python markdown.py"
15 | """ The name used in the usage statement displayed for python versions < 2.3.
16 | (With python 2.3 and higher the usage statement is generated by optparse
17 | and uses the actual name of the executable called.) """
18 |
19 | OPTPARSE_WARNING = """
20 | Python 2.3 or higher required for advanced command line options.
21 | For lower versions of Python use:
22 |
23 | %s INPUT_FILE > OUTPUT_FILE
24 |
25 | """ % EXECUTABLE_NAME_FOR_USAGE
26 |
27 | def parse_options():
28 | """
29 | Define and parse `optparse` options for command-line usage.
30 | """
31 |
32 | try:
33 | optparse = __import__("optparse")
34 | except:
35 | if len(sys.argv) == 2:
36 | return {'input': sys.argv[1],
37 | 'output': None,
38 | 'safe': False,
39 | 'extensions': [],
40 | 'encoding': None }, CRITICAL
41 | else:
42 | print OPTPARSE_WARNING
43 | return None, None
44 |
45 | parser = optparse.OptionParser(usage="%prog INPUTFILE [options]")
46 | parser.add_option("-f", "--file", dest="filename", default=sys.stdout,
47 | help="write output to OUTPUT_FILE",
48 | metavar="OUTPUT_FILE")
49 | parser.add_option("-e", "--encoding", dest="encoding",
50 | help="encoding for input and output files",)
51 | parser.add_option("-q", "--quiet", default = CRITICAL,
52 | action="store_const", const=CRITICAL+10, dest="verbose",
53 | help="suppress all messages")
54 | parser.add_option("-v", "--verbose",
55 | action="store_const", const=INFO, dest="verbose",
56 | help="print info messages")
57 | parser.add_option("-s", "--safe", dest="safe", default=False,
58 | metavar="SAFE_MODE",
59 | help="safe mode ('replace', 'remove' or 'escape' user's HTML tag)")
60 | parser.add_option("-o", "--output_format", dest="output_format",
61 | default='xhtml1', metavar="OUTPUT_FORMAT",
62 | help="Format of output. One of 'xhtml1' (default) or 'html4'.")
63 | parser.add_option("--noisy",
64 | action="store_const", const=DEBUG, dest="verbose",
65 | help="print debug messages")
66 | parser.add_option("-x", "--extension", action="append", dest="extensions",
67 | help = "load extension EXTENSION", metavar="EXTENSION")
68 |
69 | (options, args) = parser.parse_args()
70 |
71 | if not len(args) == 1:
72 | parser.print_help()
73 | return None, None
74 | else:
75 | input_file = args[0]
76 |
77 | if not options.extensions:
78 | options.extensions = []
79 |
80 | return {'input': input_file,
81 | 'output': options.filename,
82 | 'safe_mode': options.safe,
83 | 'extensions': options.extensions,
84 | 'encoding': options.encoding,
85 | 'output_format': options.output_format}, options.verbose
86 |
87 | def run():
88 | """Run Markdown from the command line."""
89 |
90 | # Parse options and adjust logging level if necessary
91 | options, logging_level = parse_options()
92 | if not options: sys.exit(0)
93 | if logging_level: logging.getLogger('MARKDOWN').setLevel(logging_level)
94 |
95 | # Run
96 | markdown.markdownFromFile(**options)
97 |
--------------------------------------------------------------------------------
/markdown/etree_loader.py:
--------------------------------------------------------------------------------
1 |
2 | from markdown import message, CRITICAL
3 | import sys
4 |
5 | ## Import
6 | def importETree():
7 | """Import the best implementation of ElementTree, return a module object."""
8 | etree_in_c = None
9 | try: # Is it Python 2.5+ with C implemenation of ElementTree installed?
10 | import xml.etree.cElementTree as etree_in_c
11 | except ImportError:
12 | try: # Is it Python 2.5+ with Python implementation of ElementTree?
13 | import xml.etree.ElementTree as etree
14 | except ImportError:
15 | try: # An earlier version of Python with cElementTree installed?
16 | import cElementTree as etree_in_c
17 | except ImportError:
18 | try: # An earlier version of Python with Python ElementTree?
19 | import elementtree.ElementTree as etree
20 | except ImportError:
21 | message(CRITICAL, "Failed to import ElementTree")
22 | sys.exit(1)
23 | if etree_in_c and etree_in_c.VERSION < "1.0":
24 | message(CRITICAL, "For cElementTree version 1.0 or higher is required.")
25 | sys.exit(1)
26 | elif etree_in_c :
27 | return etree_in_c
28 | elif etree.VERSION < "1.1":
29 | message(CRITICAL, "For ElementTree version 1.1 or higher is required")
30 | sys.exit(1)
31 | else :
32 | return etree
33 |
34 |
--------------------------------------------------------------------------------
/markdown/extensions/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/proudlygeek/proudlygeek-blog/5b9359973802197fec7d1c31349a8f5346d0ddc9/markdown/extensions/__init__.py
--------------------------------------------------------------------------------
/markdown/extensions/abbr.py:
--------------------------------------------------------------------------------
1 | '''
2 | Abbreviation Extension for Python-Markdown
3 | ==========================================
4 |
5 | This extension adds abbreviation handling to Python-Markdown.
6 |
7 | Simple Usage:
8 |
9 | >>> import markdown
10 | >>> text = """
11 | ... Some text with an ABBR and a REF. Ignore REFERENCE and ref.
12 | ...
13 | ... *[ABBR]: Abbreviation
14 | ... *[REF]: Abbreviation Reference
15 | ... """
16 | >>> markdown.markdown(text, ['abbr'])
17 | u'
Some text with an ABBR and a REF. Ignore REFERENCE and ref.
'
18 |
19 | Copyright 2007-2008
20 | * [Waylan Limberg](http://achinghead.com/)
21 | * [Seemant Kulleen](http://www.kulleen.org/)
22 |
23 |
24 | '''
25 |
26 | import markdown, re
27 | from markdown import etree
28 |
29 | # Global Vars
30 | ABBR_REF_RE = re.compile(r'[*]\[(?P[^\]]*)\][ ]?:\s*(?P.*)')
31 |
32 | class AbbrExtension(markdown.Extension):
33 | """ Abbreviation Extension for Python-Markdown. """
34 |
35 | def extendMarkdown(self, md, md_globals):
36 | """ Insert AbbrPreprocessor before ReferencePreprocessor. """
37 | md.preprocessors.add('abbr', AbbrPreprocessor(md), ' r'(?P[H][T][M][L])'
66 |
67 | Note: we force each char as a literal match (in brackets) as we don't
68 | know what they will be beforehand.
69 |
70 | '''
71 | chars = list(text)
72 | for i in range(len(chars)):
73 | chars[i] = r'[%s]' % chars[i]
74 | return r'(?P\b%s\b)' % (r''.join(chars))
75 |
76 |
77 | class AbbrPattern(markdown.inlinepatterns.Pattern):
78 | """ Abbreviation inline pattern. """
79 |
80 | def __init__(self, pattern, title):
81 | markdown.inlinepatterns.Pattern.__init__(self, pattern)
82 | self.title = title
83 |
84 | def handleMatch(self, m):
85 | abbr = etree.Element('abbr')
86 | abbr.text = m.group('abbr')
87 | abbr.set('title', self.title)
88 | return abbr
89 |
90 | def makeExtension(configs=None):
91 | return AbbrExtension(configs=configs)
92 |
93 | if __name__ == "__main__":
94 | import doctest
95 | doctest.testmod()
96 |
--------------------------------------------------------------------------------
/markdown/extensions/def_list.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env Python
2 | """
3 | Definition List Extension for Python-Markdown
4 | =============================================
5 |
6 | Added parsing of Definition Lists to Python-Markdown.
7 |
8 | A simple example:
9 |
10 | Apple
11 | : Pomaceous fruit of plants of the genus Malus in
12 | the family Rosaceae.
13 | : An american computer company.
14 |
15 | Orange
16 | : The fruit of an evergreen tree of the genus Citrus.
17 |
18 | Copyright 2008 - [Waylan Limberg](http://achinghead.com)
19 |
20 | """
21 |
22 | import markdown, re
23 | from markdown import etree
24 |
25 |
26 | class DefListProcessor(markdown.blockprocessors.BlockProcessor):
27 | """ Process Definition Lists. """
28 |
29 | RE = re.compile(r'(^|\n)[ ]{0,3}:[ ]{1,3}(.*?)(\n|$)')
30 |
31 | def test(self, parent, block):
32 | return bool(self.RE.search(block))
33 |
34 | def run(self, parent, blocks):
35 | block = blocks.pop(0)
36 | m = self.RE.search(block)
37 | terms = [l.strip() for l in block[:m.start()].split('\n') if l.strip()]
38 | d, theRest = self.detab(block[m.end():])
39 | if d:
40 | d = '%s\n%s' % (m.group(2), d)
41 | else:
42 | d = m.group(2)
43 | #import ipdb; ipdb.set_trace()
44 | sibling = self.lastChild(parent)
45 | if not terms and sibling.tag == 'p':
46 | # The previous paragraph contains the terms
47 | state = 'looselist'
48 | terms = sibling.text.split('\n')
49 | parent.remove(sibling)
50 | # Aquire new sibling
51 | sibling = self.lastChild(parent)
52 | else:
53 | state = 'list'
54 |
55 | if sibling and sibling.tag == 'dl':
56 | # This is another item on an existing list
57 | dl = sibling
58 | if len(dl) and dl[-1].tag == 'dd' and len(dl[-1]):
59 | state = 'looselist'
60 | else:
61 | # This is a new list
62 | dl = etree.SubElement(parent, 'dl')
63 | # Add terms
64 | for term in terms:
65 | dt = etree.SubElement(dl, 'dt')
66 | dt.text = term
67 | # Add definition
68 | self.parser.state.set(state)
69 | dd = etree.SubElement(dl, 'dd')
70 | self.parser.parseBlocks(dd, [d])
71 | self.parser.state.reset()
72 |
73 | if theRest:
74 | blocks.insert(0, theRest)
75 |
76 | class DefListIndentProcessor(markdown.blockprocessors.ListIndentProcessor):
77 | """ Process indented children of definition list items. """
78 |
79 | ITEM_TYPES = ['dd']
80 | LIST_TYPES = ['dl']
81 |
82 | def create_item(parent, block):
83 | """ Create a new dd and parse the block with it as the parent. """
84 | dd = markdown.etree.SubElement(parent, 'dd')
85 | self.parser.parseBlocks(dd, [block])
86 |
87 |
88 |
89 | class DefListExtension(markdown.Extension):
90 | """ Add definition lists to Markdown. """
91 |
92 | def extendMarkdown(self, md, md_globals):
93 | """ Add an instance of DefListProcessor to BlockParser. """
94 | md.parser.blockprocessors.add('defindent',
95 | DefListIndentProcessor(md.parser),
96 | '>indent')
97 | md.parser.blockprocessors.add('deflist',
98 | DefListProcessor(md.parser),
99 | '>ulist')
100 |
101 |
102 | def makeExtension(configs={}):
103 | return DefListExtension(configs=configs)
104 |
105 |
--------------------------------------------------------------------------------
/markdown/extensions/extra.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | """
3 | Python-Markdown Extra Extension
4 | ===============================
5 |
6 | A compilation of various Python-Markdown extensions that imitates
7 | [PHP Markdown Extra](http://michelf.com/projects/php-markdown/extra/).
8 |
9 | Note that each of the individual extensions still need to be available
10 | on your PYTHONPATH. This extension simply wraps them all up as a
11 | convenience so that only one extension needs to be listed when
12 | initiating Markdown. See the documentation for each individual
13 | extension for specifics about that extension.
14 |
15 | In the event that one or more of the supported extensions are not
16 | available for import, Markdown will issue a warning and simply continue
17 | without that extension.
18 |
19 | There may be additional extensions that are distributed with
20 | Python-Markdown that are not included here in Extra. Those extensions
21 | are not part of PHP Markdown Extra, and therefore, not part of
22 | Python-Markdown Extra. If you really would like Extra to include
23 | additional extensions, we suggest creating your own clone of Extra
24 | under a differant name. You could also edit the `extensions` global
25 | variable defined below, but be aware that such changes may be lost
26 | when you upgrade to any future version of Python-Markdown.
27 |
28 | """
29 |
30 | import markdown
31 |
32 | extensions = ['fenced_code',
33 | 'footnotes',
34 | 'headerid',
35 | 'def_list',
36 | 'tables',
37 | 'abbr',
38 | ]
39 |
40 |
41 | class ExtraExtension(markdown.Extension):
42 | """ Add various extensions to Markdown class."""
43 |
44 | def extendMarkdown(self, md, md_globals):
45 | """ Register extension instances. """
46 | md.registerExtensions(extensions, self.config)
47 |
48 | def makeExtension(configs={}):
49 | return ExtraExtension(configs=dict(configs))
50 |
--------------------------------------------------------------------------------
/markdown/extensions/fenced_code.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | """
4 | Fenced Code Extension for Python Markdown
5 | =========================================
6 |
7 | This extension adds Fenced Code Blocks to Python-Markdown.
8 |
9 | >>> import markdown
10 | >>> text = '''
11 | ... A paragraph before a fenced code block:
12 | ...
13 | ... ~~~
14 | ... Fenced code block
15 | ... ~~~
16 | ... '''
17 | >>> html = markdown.markdown(text, extensions=['fenced_code'])
18 | >>> html
19 | u'
A paragraph before a fenced code block:
\\n
Fenced code block\\n
'
20 |
21 | Works with safe_mode also (we check this because we are using the HtmlStash):
22 |
23 | >>> markdown.markdown(text, extensions=['fenced_code'], safe_mode='replace')
24 | u'
A paragraph before a fenced code block:
\\n
Fenced code block\\n
'
25 |
26 | Include tilde's in a code block and wrap with blank lines:
27 |
28 | >>> text = '''
29 | ... ~~~~~~~~
30 | ...
31 | ... ~~~~
32 | ...
33 | ... ~~~~~~~~'''
34 | >>> markdown.markdown(text, extensions=['fenced_code'])
35 | u'
")
97 |
98 | elif line[1:6] == "~~~~~" :
99 | rows.append([]) # start a new row
100 | else :
101 | parts = line.split()
102 | line = parts[0]
103 | title = " ".join(parts[1:])
104 |
105 | album, photo = line.split("/")
106 | photo_url = url.get_photo(album, photo,
107 | len(all_images)+1)
108 | all_images.append(photo_url)
109 | rows[-1].append((photo_url, title))
110 |
111 | if not album in albums :
112 | albums.append(album)
113 |
114 | return new_lines
115 |
116 |
117 | def makeExtension(configs):
118 | return ImageLinksExtension(configs)
119 |
120 |
--------------------------------------------------------------------------------
/markdown/extensions/meta.py:
--------------------------------------------------------------------------------
1 | #!usr/bin/python
2 |
3 | """
4 | Meta Data Extension for Python-Markdown
5 | =======================================
6 |
7 | This extension adds Meta Data handling to markdown.
8 |
9 | Basic Usage:
10 |
11 | >>> import markdown
12 | >>> text = '''Title: A Test Doc.
13 | ... Author: Waylan Limberg
14 | ... John Doe
15 | ... Blank_Data:
16 | ...
17 | ... The body. This is paragraph one.
18 | ... '''
19 | >>> md = markdown.Markdown(['meta'])
20 | >>> md.convert(text)
21 | u'
The body. This is paragraph one.
'
22 | >>> md.Meta
23 | {u'blank_data': [u''], u'author': [u'Waylan Limberg', u'John Doe'], u'title': [u'A Test Doc.']}
24 |
25 | Make sure text without Meta Data still works (markdown < 1.6b returns a
).
26 |
27 | >>> text = ' Some Code - not extra lines of meta data.'
28 | >>> md = markdown.Markdown(['meta'])
29 | >>> md.convert(text)
30 | u'
Some Code - not extra lines of meta data.\\n
'
31 | >>> md.Meta
32 | {}
33 |
34 | Copyright 2007-2008 [Waylan Limberg](http://achinghead.com).
35 |
36 | Project website:
37 | Contact: markdown@freewisdom.org
38 |
39 | License: BSD (see ../docs/LICENSE for details)
40 |
41 | """
42 |
43 | import markdown, re
44 |
45 | # Global Vars
46 | META_RE = re.compile(r'^[ ]{0,3}(?P[A-Za-z0-9_-]+):\s*(?P.*)')
47 | META_MORE_RE = re.compile(r'^[ ]{4,}(?P.*)')
48 |
49 | class MetaExtension (markdown.Extension):
50 | """ Meta-Data extension for Python-Markdown. """
51 |
52 | def extendMarkdown(self, md, md_globals):
53 | """ Add MetaPreprocessor to Markdown instance. """
54 |
55 | md.preprocessors.add("meta", MetaPreprocessor(md), "_begin")
56 |
57 |
58 | class MetaPreprocessor(markdown.preprocessors.Preprocessor):
59 | """ Get Meta-Data. """
60 |
61 | def run(self, lines):
62 | """ Parse Meta-Data and store in Markdown.Meta. """
63 | meta = {}
64 | key = None
65 | while 1:
66 | line = lines.pop(0)
67 | if line.strip() == '':
68 | break # blank line - done
69 | m1 = META_RE.match(line)
70 | if m1:
71 | key = m1.group('key').lower().strip()
72 | meta[key] = [m1.group('value').strip()]
73 | else:
74 | m2 = META_MORE_RE.match(line)
75 | if m2 and key:
76 | # Add another line to existing key
77 | meta[key].append(m2.group('value').strip())
78 | else:
79 | lines.insert(0, line)
80 | break # no meta data - done
81 | self.markdown.Meta = meta
82 | return lines
83 |
84 |
85 | def makeExtension(configs={}):
86 | return MetaExtension(configs=configs)
87 |
88 | if __name__ == "__main__":
89 | import doctest
90 | doctest.testmod()
91 |
--------------------------------------------------------------------------------
/markdown/extensions/rss.py:
--------------------------------------------------------------------------------
1 | import markdown
2 | from markdown import etree
3 |
4 | DEFAULT_URL = "http://www.freewisdom.org/projects/python-markdown/"
5 | DEFAULT_CREATOR = "Yuri Takhteyev"
6 | DEFAULT_TITLE = "Markdown in Python"
7 | GENERATOR = "http://www.freewisdom.org/projects/python-markdown/markdown2rss"
8 |
9 | month_map = { "Jan" : "01",
10 | "Feb" : "02",
11 | "March" : "03",
12 | "April" : "04",
13 | "May" : "05",
14 | "June" : "06",
15 | "July" : "07",
16 | "August" : "08",
17 | "September" : "09",
18 | "October" : "10",
19 | "November" : "11",
20 | "December" : "12" }
21 |
22 | def get_time(heading):
23 |
24 | heading = heading.split("-")[0]
25 | heading = heading.strip().replace(",", " ").replace(".", " ")
26 |
27 | month, date, year = heading.split()
28 | month = month_map[month]
29 |
30 | return rdftime(" ".join((month, date, year, "12:00:00 AM")))
31 |
32 | def rdftime(time):
33 |
34 | time = time.replace(":", " ")
35 | time = time.replace("/", " ")
36 | time = time.split()
37 | return "%s-%s-%sT%s:%s:%s-08:00" % (time[0], time[1], time[2],
38 | time[3], time[4], time[5])
39 |
40 |
41 | def get_date(text):
42 | return "date"
43 |
44 | class RssExtension (markdown.Extension):
45 |
46 | def extendMarkdown(self, md, md_globals):
47 |
48 | self.config = { 'URL' : [DEFAULT_URL, "Main URL"],
49 | 'CREATOR' : [DEFAULT_CREATOR, "Feed creator's name"],
50 | 'TITLE' : [DEFAULT_TITLE, "Feed title"] }
51 |
52 | md.xml_mode = True
53 |
54 | # Insert a tree-processor that would actually add the title tag
55 | treeprocessor = RssTreeProcessor(md)
56 | treeprocessor.ext = self
57 | md.treeprocessors['rss'] = treeprocessor
58 | md.stripTopLevelTags = 0
59 | md.docType = '\n'
60 |
61 | class RssTreeProcessor(markdown.treeprocessors.Treeprocessor):
62 |
63 | def run (self, root):
64 |
65 | rss = etree.Element("rss")
66 | rss.set("version", "2.0")
67 |
68 | channel = etree.SubElement(rss, "channel")
69 |
70 | for tag, text in (("title", self.ext.getConfig("TITLE")),
71 | ("link", self.ext.getConfig("URL")),
72 | ("description", None)):
73 |
74 | element = etree.SubElement(channel, tag)
75 | element.text = text
76 |
77 | for child in root:
78 |
79 | if child.tag in ["h1", "h2", "h3", "h4", "h5"]:
80 |
81 | heading = child.text.strip()
82 | item = etree.SubElement(channel, "item")
83 | link = etree.SubElement(item, "link")
84 | link.text = self.ext.getConfig("URL")
85 | title = etree.SubElement(item, "title")
86 | title.text = heading
87 |
88 | guid = ''.join([x for x in heading if x.isalnum()])
89 | guidElem = etree.SubElement(item, "guid")
90 | guidElem.text = guid
91 | guidElem.set("isPermaLink", "false")
92 |
93 | elif child.tag in ["p"]:
94 | try:
95 | description = etree.SubElement(item, "description")
96 | except UnboundLocalError:
97 | # Item not defined - moving on
98 | pass
99 | else:
100 | if len(child):
101 | content = "\n".join([etree.tostring(node)
102 | for node in child])
103 | else:
104 | content = child.text
105 | pholder = self.markdown.htmlStash.store(
106 | "" % content)
107 | description.text = pholder
108 |
109 | return rss
110 |
111 |
112 | def makeExtension(configs):
113 |
114 | return RssExtension(configs)
115 |
--------------------------------------------------------------------------------
/markdown/extensions/tables.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env Python
2 | """
3 | Tables Extension for Python-Markdown
4 | ====================================
5 |
6 | Added parsing of tables to Python-Markdown.
7 |
8 | A simple example:
9 |
10 | First Header | Second Header
11 | ------------- | -------------
12 | Content Cell | Content Cell
13 | Content Cell | Content Cell
14 |
15 | Copyright 2009 - [Waylan Limberg](http://achinghead.com)
16 | """
17 | import markdown
18 | from markdown import etree
19 |
20 |
21 | class TableProcessor(markdown.blockprocessors.BlockProcessor):
22 | """ Process Tables. """
23 |
24 | def test(self, parent, block):
25 | rows = block.split('\n')
26 | return (len(rows) > 2 and '|' in rows[0] and
27 | '|' in rows[1] and '-' in rows[1] and
28 | rows[1][0] in ['|', ':', '-'])
29 |
30 | def run(self, parent, blocks):
31 | """ Parse a table block and build table. """
32 | block = blocks.pop(0).split('\n')
33 | header = block[:2]
34 | rows = block[2:]
35 | # Get format type (bordered by pipes or not)
36 | border = False
37 | if header[0].startswith('|'):
38 | border = True
39 | # Get alignment of columns
40 | align = []
41 | for c in self._split_row(header[1], border):
42 | if c.startswith(':') and c.endswith(':'):
43 | align.append('center')
44 | elif c.startswith(':'):
45 | align.append('left')
46 | elif c.endswith(':'):
47 | align.append('right')
48 | else:
49 | align.append(None)
50 | # Build table
51 | table = etree.SubElement(parent, 'table')
52 | thead = etree.SubElement(table, 'thead')
53 | self._build_row(header[0], thead, align, border)
54 | tbody = etree.SubElement(table, 'tbody')
55 | for row in rows:
56 | self._build_row(row, tbody, align, border)
57 |
58 | def _build_row(self, row, parent, align, border):
59 | """ Given a row of text, build table cells. """
60 | tr = etree.SubElement(parent, 'tr')
61 | tag = 'td'
62 | if parent.tag == 'thead':
63 | tag = 'th'
64 | cells = self._split_row(row, border)
65 | # We use align here rather than cells to ensure every row
66 | # contains the same number of columns.
67 | for i, a in enumerate(align):
68 | c = etree.SubElement(tr, tag)
69 | try:
70 | c.text = cells[i].strip()
71 | except IndexError:
72 | c.text = ""
73 | if a:
74 | c.set('align', a)
75 |
76 | def _split_row(self, row, border):
77 | """ split a row of text into list of cells. """
78 | if border:
79 | if row.startswith('|'):
80 | row = row[1:]
81 | if row.endswith('|'):
82 | row = row[:-1]
83 | return row.split('|')
84 |
85 |
86 | class TableExtension(markdown.Extension):
87 | """ Add tables to Markdown. """
88 |
89 | def extendMarkdown(self, md, md_globals):
90 | """ Add an instance of TableProcessor to BlockParser. """
91 | md.parser.blockprocessors.add('table',
92 | TableProcessor(md.parser),
93 | '%s
" %
56 | (markdown.preprocessors.HTML_PLACEHOLDER % i),
57 | html + "\n")
58 | text = text.replace(markdown.preprocessors.HTML_PLACEHOLDER % i,
59 | html)
60 | return text
61 |
62 | def escape(self, html):
63 | """ Basic html escaping """
64 | html = html.replace('&', '&')
65 | html = html.replace('<', '<')
66 | html = html.replace('>', '>')
67 | return html.replace('"', '"')
68 |
69 |
70 | class AndSubstitutePostprocessor(Postprocessor):
71 | """ Restore valid entities """
72 | def __init__(self):
73 | pass
74 |
75 | def run(self, text):
76 | text = text.replace(markdown.AMP_SUBSTITUTE, "&")
77 | return text
78 |
--------------------------------------------------------------------------------
/pygments/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Pygments
4 | ~~~~~~~~
5 |
6 | Pygments is a syntax highlighting package written in Python.
7 |
8 | It is a generic syntax highlighter for general use in all kinds of software
9 | such as forum systems, wikis or other applications that need to prettify
10 | source code. Highlights are:
11 |
12 | * a wide range of common languages and markup formats is supported
13 | * special attention is paid to details, increasing quality by a fair amount
14 | * support for new languages and formats are added easily
15 | * a number of output formats, presently HTML, LaTeX, RTF, SVG, all image
16 | formats that PIL supports, and ANSI sequences
17 | * it is usable as a command-line tool and as a library
18 | * ... and it highlights even Brainfuck!
19 |
20 | The `Pygments tip`_ is installable with ``easy_install Pygments==dev``.
21 |
22 | .. _Pygments tip:
23 | http://bitbucket.org/birkenfeld/pygments-main/get/tip.zip#egg=Pygments-dev
24 |
25 | :copyright: Copyright 2006-2010 by the Pygments team, see AUTHORS.
26 | :license: BSD, see LICENSE for details.
27 | """
28 |
29 | __version__ = '1.4'
30 | __docformat__ = 'restructuredtext'
31 |
32 | __all__ = ['lex', 'format', 'highlight']
33 |
34 |
35 | import sys
36 |
37 | from pygments.util import StringIO, BytesIO
38 |
39 |
40 | def lex(code, lexer):
41 | """
42 | Lex ``code`` with ``lexer`` and return an iterable of tokens.
43 | """
44 | try:
45 | return lexer.get_tokens(code)
46 | except TypeError, err:
47 | if isinstance(err.args[0], str) and \
48 | 'unbound method get_tokens' in err.args[0]:
49 | raise TypeError('lex() argument must be a lexer instance, '
50 | 'not a class')
51 | raise
52 |
53 |
54 | def format(tokens, formatter, outfile=None):
55 | """
56 | Format a tokenlist ``tokens`` with the formatter ``formatter``.
57 |
58 | If ``outfile`` is given and a valid file object (an object
59 | with a ``write`` method), the result will be written to it, otherwise
60 | it is returned as a string.
61 | """
62 | try:
63 | if not outfile:
64 | #print formatter, 'using', formatter.encoding
65 | realoutfile = formatter.encoding and BytesIO() or StringIO()
66 | formatter.format(tokens, realoutfile)
67 | return realoutfile.getvalue()
68 | else:
69 | formatter.format(tokens, outfile)
70 | except TypeError, err:
71 | if isinstance(err.args[0], str) and \
72 | 'unbound method format' in err.args[0]:
73 | raise TypeError('format() argument must be a formatter instance, '
74 | 'not a class')
75 | raise
76 |
77 |
78 | def highlight(code, lexer, formatter, outfile=None):
79 | """
80 | Lex ``code`` with ``lexer`` and format it with the formatter ``formatter``.
81 |
82 | If ``outfile`` is given and a valid file object (an object
83 | with a ``write`` method), the result will be written to it, otherwise
84 | it is returned as a string.
85 | """
86 | return format(lex(code, lexer), formatter, outfile)
87 |
88 |
89 | if __name__ == '__main__':
90 | from pygments.cmdline import main
91 | sys.exit(main(sys.argv))
92 |
--------------------------------------------------------------------------------
/pygments/console.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | pygments.console
4 | ~~~~~~~~~~~~~~~~
5 |
6 | Format colored console output.
7 |
8 | :copyright: Copyright 2006-2010 by the Pygments team, see AUTHORS.
9 | :license: BSD, see LICENSE for details.
10 | """
11 |
12 | esc = "\x1b["
13 |
14 | codes = {}
15 | codes[""] = ""
16 | codes["reset"] = esc + "39;49;00m"
17 |
18 | codes["bold"] = esc + "01m"
19 | codes["faint"] = esc + "02m"
20 | codes["standout"] = esc + "03m"
21 | codes["underline"] = esc + "04m"
22 | codes["blink"] = esc + "05m"
23 | codes["overline"] = esc + "06m"
24 |
25 | dark_colors = ["black", "darkred", "darkgreen", "brown", "darkblue",
26 | "purple", "teal", "lightgray"]
27 | light_colors = ["darkgray", "red", "green", "yellow", "blue",
28 | "fuchsia", "turquoise", "white"]
29 |
30 | x = 30
31 | for d, l in zip(dark_colors, light_colors):
32 | codes[d] = esc + "%im" % x
33 | codes[l] = esc + "%i;01m" % x
34 | x += 1
35 |
36 | del d, l, x
37 |
38 | codes["darkteal"] = codes["turquoise"]
39 | codes["darkyellow"] = codes["brown"]
40 | codes["fuscia"] = codes["fuchsia"]
41 | codes["white"] = codes["bold"]
42 |
43 |
44 | def reset_color():
45 | return codes["reset"]
46 |
47 |
48 | def colorize(color_key, text):
49 | return codes[color_key] + text + codes["reset"]
50 |
51 |
52 | def ansiformat(attr, text):
53 | """
54 | Format ``text`` with a color and/or some attributes::
55 |
56 | color normal color
57 | *color* bold color
58 | _color_ underlined color
59 | +color+ blinking color
60 | """
61 | result = []
62 | if attr[:1] == attr[-1:] == '+':
63 | result.append(codes['blink'])
64 | attr = attr[1:-1]
65 | if attr[:1] == attr[-1:] == '*':
66 | result.append(codes['bold'])
67 | attr = attr[1:-1]
68 | if attr[:1] == attr[-1:] == '_':
69 | result.append(codes['underline'])
70 | attr = attr[1:-1]
71 | result.append(codes[attr])
72 | result.append(text)
73 | result.append(codes['reset'])
74 | return ''.join(result)
75 |
--------------------------------------------------------------------------------
/pygments/filter.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | pygments.filter
4 | ~~~~~~~~~~~~~~~
5 |
6 | Module that implements the default filter.
7 |
8 | :copyright: Copyright 2006-2010 by the Pygments team, see AUTHORS.
9 | :license: BSD, see LICENSE for details.
10 | """
11 |
12 |
13 | def apply_filters(stream, filters, lexer=None):
14 | """
15 | Use this method to apply an iterable of filters to
16 | a stream. If lexer is given it's forwarded to the
17 | filter, otherwise the filter receives `None`.
18 | """
19 | def _apply(filter_, stream):
20 | for token in filter_.filter(lexer, stream):
21 | yield token
22 | for filter_ in filters:
23 | stream = _apply(filter_, stream)
24 | return stream
25 |
26 |
27 | def simplefilter(f):
28 | """
29 | Decorator that converts a function into a filter::
30 |
31 | @simplefilter
32 | def lowercase(lexer, stream, options):
33 | for ttype, value in stream:
34 | yield ttype, value.lower()
35 | """
36 | return type(f.__name__, (FunctionFilter,), {
37 | 'function': f,
38 | '__module__': getattr(f, '__module__'),
39 | '__doc__': f.__doc__
40 | })
41 |
42 |
43 | class Filter(object):
44 | """
45 | Default filter. Subclass this class or use the `simplefilter`
46 | decorator to create own filters.
47 | """
48 |
49 | def __init__(self, **options):
50 | self.options = options
51 |
52 | def filter(self, lexer, stream):
53 | raise NotImplementedError()
54 |
55 |
56 | class FunctionFilter(Filter):
57 | """
58 | Abstract class used by `simplefilter` to create simple
59 | function filters on the fly. The `simplefilter` decorator
60 | automatically creates subclasses of this class for
61 | functions passed to it.
62 | """
63 | function = None
64 |
65 | def __init__(self, **options):
66 | if not hasattr(self, 'function'):
67 | raise TypeError('%r used without bound function' %
68 | self.__class__.__name__)
69 | Filter.__init__(self, **options)
70 |
71 | def filter(self, lexer, stream):
72 | # pylint: disable-msg=E1102
73 | for ttype, value in self.function(lexer, stream, self.options):
74 | yield ttype, value
75 |
--------------------------------------------------------------------------------
/pygments/formatter.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | pygments.formatter
4 | ~~~~~~~~~~~~~~~~~~
5 |
6 | Base formatter class.
7 |
8 | :copyright: Copyright 2006-2010 by the Pygments team, see AUTHORS.
9 | :license: BSD, see LICENSE for details.
10 | """
11 |
12 | import codecs
13 |
14 | from pygments.util import get_bool_opt
15 | from pygments.styles import get_style_by_name
16 |
17 | __all__ = ['Formatter']
18 |
19 |
20 | def _lookup_style(style):
21 | if isinstance(style, basestring):
22 | return get_style_by_name(style)
23 | return style
24 |
25 |
26 | class Formatter(object):
27 | """
28 | Converts a token stream to text.
29 |
30 | Options accepted:
31 |
32 | ``style``
33 | The style to use, can be a string or a Style subclass
34 | (default: "default"). Not used by e.g. the
35 | TerminalFormatter.
36 | ``full``
37 | Tells the formatter to output a "full" document, i.e.
38 | a complete self-contained document. This doesn't have
39 | any effect for some formatters (default: false).
40 | ``title``
41 | If ``full`` is true, the title that should be used to
42 | caption the document (default: '').
43 | ``encoding``
44 | If given, must be an encoding name. This will be used to
45 | convert the Unicode token strings to byte strings in the
46 | output. If it is "" or None, Unicode strings will be written
47 | to the output file, which most file-like objects do not
48 | support (default: None).
49 | ``outencoding``
50 | Overrides ``encoding`` if given.
51 | """
52 |
53 | #: Name of the formatter
54 | name = None
55 |
56 | #: Shortcuts for the formatter
57 | aliases = []
58 |
59 | #: fn match rules
60 | filenames = []
61 |
62 | #: If True, this formatter outputs Unicode strings when no encoding
63 | #: option is given.
64 | unicodeoutput = True
65 |
66 | def __init__(self, **options):
67 | self.style = _lookup_style(options.get('style', 'default'))
68 | self.full = get_bool_opt(options, 'full', False)
69 | self.title = options.get('title', '')
70 | self.encoding = options.get('encoding', None) or None
71 | self.encoding = options.get('outencoding', None) or self.encoding
72 | self.options = options
73 |
74 | def get_style_defs(self, arg=''):
75 | """
76 | Return the style definitions for the current style as a string.
77 |
78 | ``arg`` is an additional argument whose meaning depends on the
79 | formatter used. Note that ``arg`` can also be a list or tuple
80 | for some formatters like the html formatter.
81 | """
82 | return ''
83 |
84 | def format(self, tokensource, outfile):
85 | """
86 | Format ``tokensource``, an iterable of ``(tokentype, tokenstring)``
87 | tuples and write it into ``outfile``.
88 | """
89 | if self.encoding:
90 | # wrap the outfile in a StreamWriter
91 | outfile = codecs.lookup(self.encoding)[3](outfile)
92 | return self.format_unencoded(tokensource, outfile)
93 |
--------------------------------------------------------------------------------
/pygments/formatters/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | pygments.formatters
4 | ~~~~~~~~~~~~~~~~~~~
5 |
6 | Pygments formatters.
7 |
8 | :copyright: Copyright 2006-2010 by the Pygments team, see AUTHORS.
9 | :license: BSD, see LICENSE for details.
10 | """
11 | import os.path
12 | import fnmatch
13 |
14 | from pygments.formatters._mapping import FORMATTERS
15 | from pygments.plugin import find_plugin_formatters
16 | from pygments.util import ClassNotFound
17 |
18 | ns = globals()
19 | for fcls in FORMATTERS:
20 | ns[fcls.__name__] = fcls
21 | del fcls
22 |
23 | __all__ = ['get_formatter_by_name', 'get_formatter_for_filename',
24 | 'get_all_formatters'] + [cls.__name__ for cls in FORMATTERS]
25 |
26 |
27 | _formatter_alias_cache = {}
28 | _formatter_filename_cache = []
29 |
30 | def _init_formatter_cache():
31 | if _formatter_alias_cache:
32 | return
33 | for cls in get_all_formatters():
34 | for alias in cls.aliases:
35 | _formatter_alias_cache[alias] = cls
36 | for fn in cls.filenames:
37 | _formatter_filename_cache.append((fn, cls))
38 |
39 |
40 | def find_formatter_class(name):
41 | _init_formatter_cache()
42 | cls = _formatter_alias_cache.get(name, None)
43 | return cls
44 |
45 |
46 | def get_formatter_by_name(name, **options):
47 | _init_formatter_cache()
48 | cls = _formatter_alias_cache.get(name, None)
49 | if not cls:
50 | raise ClassNotFound("No formatter found for name %r" % name)
51 | return cls(**options)
52 |
53 |
54 | def get_formatter_for_filename(fn, **options):
55 | _init_formatter_cache()
56 | fn = os.path.basename(fn)
57 | for pattern, cls in _formatter_filename_cache:
58 | if fnmatch.fnmatch(fn, pattern):
59 | return cls(**options)
60 | raise ClassNotFound("No formatter found for file name %r" % fn)
61 |
62 |
63 | def get_all_formatters():
64 | """Return a generator for all formatters."""
65 | for formatter in FORMATTERS:
66 | yield formatter
67 | for _, formatter in find_plugin_formatters():
68 | yield formatter
69 |
--------------------------------------------------------------------------------
/pygments/formatters/bbcode.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | pygments.formatters.bbcode
4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~
5 |
6 | BBcode formatter.
7 |
8 | :copyright: Copyright 2006-2010 by the Pygments team, see AUTHORS.
9 | :license: BSD, see LICENSE for details.
10 | """
11 |
12 |
13 | from pygments.formatter import Formatter
14 | from pygments.util import get_bool_opt
15 |
16 | __all__ = ['BBCodeFormatter']
17 |
18 |
19 | class BBCodeFormatter(Formatter):
20 | """
21 | Format tokens with BBcodes. These formatting codes are used by many
22 | bulletin boards, so you can highlight your sourcecode with pygments before
23 | posting it there.
24 |
25 | This formatter has no support for background colors and borders, as there
26 | are no common BBcode tags for that.
27 |
28 | Some board systems (e.g. phpBB) don't support colors in their [code] tag,
29 | so you can't use the highlighting together with that tag.
30 | Text in a [code] tag usually is shown with a monospace font (which this
31 | formatter can do with the ``monofont`` option) and no spaces (which you
32 | need for indentation) are removed.
33 |
34 | Additional options accepted:
35 |
36 | `style`
37 | The style to use, can be a string or a Style subclass (default:
38 | ``'default'``).
39 |
40 | `codetag`
41 | If set to true, put the output into ``[code]`` tags (default:
42 | ``false``)
43 |
44 | `monofont`
45 | If set to true, add a tag to show the code with a monospace font
46 | (default: ``false``).
47 | """
48 | name = 'BBCode'
49 | aliases = ['bbcode', 'bb']
50 | filenames = []
51 |
52 | def __init__(self, **options):
53 | Formatter.__init__(self, **options)
54 | self._code = get_bool_opt(options, 'codetag', False)
55 | self._mono = get_bool_opt(options, 'monofont', False)
56 |
57 | self.styles = {}
58 | self._make_styles()
59 |
60 | def _make_styles(self):
61 | for ttype, ndef in self.style:
62 | start = end = ''
63 | if ndef['color']:
64 | start += '[color=#%s]' % ndef['color']
65 | end = '[/color]' + end
66 | if ndef['bold']:
67 | start += '[b]'
68 | end = '[/b]' + end
69 | if ndef['italic']:
70 | start += '[i]'
71 | end = '[/i]' + end
72 | if ndef['underline']:
73 | start += '[u]'
74 | end = '[/u]' + end
75 | # there are no common BBcodes for background-color and border
76 |
77 | self.styles[ttype] = start, end
78 |
79 | def format_unencoded(self, tokensource, outfile):
80 | if self._code:
81 | outfile.write('[code]')
82 | if self._mono:
83 | outfile.write('[font=monospace]')
84 |
85 | lastval = ''
86 | lasttype = None
87 |
88 | for ttype, value in tokensource:
89 | while ttype not in self.styles:
90 | ttype = ttype.parent
91 | if ttype == lasttype:
92 | lastval += value
93 | else:
94 | if lastval:
95 | start, end = self.styles[lasttype]
96 | outfile.write(''.join((start, lastval, end)))
97 | lastval = value
98 | lasttype = ttype
99 |
100 | if lastval:
101 | start, end = self.styles[lasttype]
102 | outfile.write(''.join((start, lastval, end)))
103 |
104 | if self._mono:
105 | outfile.write('[/font]')
106 | if self._code:
107 | outfile.write('[/code]')
108 | if self._code or self._mono:
109 | outfile.write('\n')
110 |
--------------------------------------------------------------------------------
/pygments/lexers/special.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | pygments.lexers.special
4 | ~~~~~~~~~~~~~~~~~~~~~~~
5 |
6 | Special lexers.
7 |
8 | :copyright: Copyright 2006-2010 by the Pygments team, see AUTHORS.
9 | :license: BSD, see LICENSE for details.
10 | """
11 |
12 | import re
13 | import cStringIO
14 |
15 | from pygments.lexer import Lexer
16 | from pygments.token import Token, Error, Text
17 | from pygments.util import get_choice_opt, b
18 |
19 |
20 | __all__ = ['TextLexer', 'RawTokenLexer']
21 |
22 |
23 | class TextLexer(Lexer):
24 | """
25 | "Null" lexer, doesn't highlight anything.
26 | """
27 | name = 'Text only'
28 | aliases = ['text']
29 | filenames = ['*.txt']
30 | mimetypes = ['text/plain']
31 |
32 | def get_tokens_unprocessed(self, text):
33 | yield 0, Text, text
34 |
35 |
36 | _ttype_cache = {}
37 |
38 | line_re = re.compile(b('.*?\n'))
39 |
40 | class RawTokenLexer(Lexer):
41 | """
42 | Recreate a token stream formatted with the `RawTokenFormatter`. This
43 | lexer raises exceptions during parsing if the token stream in the
44 | file is malformed.
45 |
46 | Additional options accepted:
47 |
48 | `compress`
49 | If set to ``"gz"`` or ``"bz2"``, decompress the token stream with
50 | the given compression algorithm before lexing (default: ``""``).
51 | """
52 | name = 'Raw token data'
53 | aliases = ['raw']
54 | filenames = []
55 | mimetypes = ['application/x-pygments-tokens']
56 |
57 | def __init__(self, **options):
58 | self.compress = get_choice_opt(options, 'compress',
59 | ['', 'none', 'gz', 'bz2'], '')
60 | Lexer.__init__(self, **options)
61 |
62 | def get_tokens(self, text):
63 | if isinstance(text, unicode):
64 | # raw token stream never has any non-ASCII characters
65 | text = text.encode('ascii')
66 | if self.compress == 'gz':
67 | import gzip
68 | gzipfile = gzip.GzipFile('', 'rb', 9, cStringIO.StringIO(text))
69 | text = gzipfile.read()
70 | elif self.compress == 'bz2':
71 | import bz2
72 | text = bz2.decompress(text)
73 |
74 | # do not call Lexer.get_tokens() because we do not want Unicode
75 | # decoding to occur, and stripping is not optional.
76 | text = text.strip(b('\n')) + b('\n')
77 | for i, t, v in self.get_tokens_unprocessed(text):
78 | yield t, v
79 |
80 | def get_tokens_unprocessed(self, text):
81 | length = 0
82 | for match in line_re.finditer(text):
83 | try:
84 | ttypestr, val = match.group().split(b('\t'), 1)
85 | except ValueError:
86 | val = match.group().decode(self.encoding)
87 | ttype = Error
88 | else:
89 | ttype = _ttype_cache.get(ttypestr)
90 | if not ttype:
91 | ttype = Token
92 | ttypes = ttypestr.split('.')[1:]
93 | for ttype_ in ttypes:
94 | if not ttype_ or not ttype_[0].isupper():
95 | raise ValueError('malformed token name')
96 | ttype = getattr(ttype, ttype_)
97 | _ttype_cache[ttypestr] = ttype
98 | val = val[2:-2].decode('unicode-escape')
99 | yield length, ttype, val
100 | length += len(val)
101 |
--------------------------------------------------------------------------------
/pygments/plugin.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | pygments.plugin
4 | ~~~~~~~~~~~~~~~
5 |
6 | Pygments setuptools plugin interface. The methods defined
7 | here also work if setuptools isn't installed but they just
8 | return nothing.
9 |
10 | lexer plugins::
11 |
12 | [pygments.lexers]
13 | yourlexer = yourmodule:YourLexer
14 |
15 | formatter plugins::
16 |
17 | [pygments.formatters]
18 | yourformatter = yourformatter:YourFormatter
19 | /.ext = yourformatter:YourFormatter
20 |
21 | As you can see, you can define extensions for the formatter
22 | with a leading slash.
23 |
24 | syntax plugins::
25 |
26 | [pygments.styles]
27 | yourstyle = yourstyle:YourStyle
28 |
29 | filter plugin::
30 |
31 | [pygments.filter]
32 | yourfilter = yourfilter:YourFilter
33 |
34 |
35 | :copyright: Copyright 2006-2010 by the Pygments team, see AUTHORS.
36 | :license: BSD, see LICENSE for details.
37 | """
38 | try:
39 | import pkg_resources
40 | except ImportError:
41 | pkg_resources = None
42 |
43 | LEXER_ENTRY_POINT = 'pygments.lexers'
44 | FORMATTER_ENTRY_POINT = 'pygments.formatters'
45 | STYLE_ENTRY_POINT = 'pygments.styles'
46 | FILTER_ENTRY_POINT = 'pygments.filters'
47 |
48 |
49 | def find_plugin_lexers():
50 | if pkg_resources is None:
51 | return
52 | for entrypoint in pkg_resources.iter_entry_points(LEXER_ENTRY_POINT):
53 | yield entrypoint.load()
54 |
55 |
56 | def find_plugin_formatters():
57 | if pkg_resources is None:
58 | return
59 | for entrypoint in pkg_resources.iter_entry_points(FORMATTER_ENTRY_POINT):
60 | yield entrypoint.name, entrypoint.load()
61 |
62 |
63 | def find_plugin_styles():
64 | if pkg_resources is None:
65 | return
66 | for entrypoint in pkg_resources.iter_entry_points(STYLE_ENTRY_POINT):
67 | yield entrypoint.name, entrypoint.load()
68 |
69 |
70 | def find_plugin_filters():
71 | if pkg_resources is None:
72 | return
73 | for entrypoint in pkg_resources.iter_entry_points(FILTER_ENTRY_POINT):
74 | yield entrypoint.name, entrypoint.load()
75 |
--------------------------------------------------------------------------------
/pygments/scanner.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | pygments.scanner
4 | ~~~~~~~~~~~~~~~~
5 |
6 | This library implements a regex based scanner. Some languages
7 | like Pascal are easy to parse but have some keywords that
8 | depend on the context. Because of this it's impossible to lex
9 | that just by using a regular expression lexer like the
10 | `RegexLexer`.
11 |
12 | Have a look at the `DelphiLexer` to get an idea of how to use
13 | this scanner.
14 |
15 | :copyright: Copyright 2006-2010 by the Pygments team, see AUTHORS.
16 | :license: BSD, see LICENSE for details.
17 | """
18 | import re
19 |
20 |
21 | class EndOfText(RuntimeError):
22 | """
23 | Raise if end of text is reached and the user
24 | tried to call a match function.
25 | """
26 |
27 |
28 | class Scanner(object):
29 | """
30 | Simple scanner
31 |
32 | All method patterns are regular expression strings (not
33 | compiled expressions!)
34 | """
35 |
36 | def __init__(self, text, flags=0):
37 | """
38 | :param text: The text which should be scanned
39 | :param flags: default regular expression flags
40 | """
41 | self.data = text
42 | self.data_length = len(text)
43 | self.start_pos = 0
44 | self.pos = 0
45 | self.flags = flags
46 | self.last = None
47 | self.match = None
48 | self._re_cache = {}
49 |
50 | def eos(self):
51 | """`True` if the scanner reached the end of text."""
52 | return self.pos >= self.data_length
53 | eos = property(eos, eos.__doc__)
54 |
55 | def check(self, pattern):
56 | """
57 | Apply `pattern` on the current position and return
58 | the match object. (Doesn't touch pos). Use this for
59 | lookahead.
60 | """
61 | if self.eos:
62 | raise EndOfText()
63 | if pattern not in self._re_cache:
64 | self._re_cache[pattern] = re.compile(pattern, self.flags)
65 | return self._re_cache[pattern].match(self.data, self.pos)
66 |
67 | def test(self, pattern):
68 | """Apply a pattern on the current position and check
69 | if it patches. Doesn't touch pos."""
70 | return self.check(pattern) is not None
71 |
72 | def scan(self, pattern):
73 | """
74 | Scan the text for the given pattern and update pos/match
75 | and related fields. The return value is a boolen that
76 | indicates if the pattern matched. The matched value is
77 | stored on the instance as ``match``, the last value is
78 | stored as ``last``. ``start_pos`` is the position of the
79 | pointer before the pattern was matched, ``pos`` is the
80 | end position.
81 | """
82 | if self.eos:
83 | raise EndOfText()
84 | if pattern not in self._re_cache:
85 | self._re_cache[pattern] = re.compile(pattern, self.flags)
86 | self.last = self.match
87 | m = self._re_cache[pattern].match(self.data, self.pos)
88 | if m is None:
89 | return False
90 | self.start_pos = m.start()
91 | self.pos = m.end()
92 | self.match = m.group()
93 | return True
94 |
95 | def get_char(self):
96 | """Scan exactly one char."""
97 | self.scan('.')
98 |
99 | def __repr__(self):
100 | return '<%s %d/%d>' % (
101 | self.__class__.__name__,
102 | self.pos,
103 | self.data_length
104 | )
105 |
--------------------------------------------------------------------------------
/pygments/styles/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | pygments.styles
4 | ~~~~~~~~~~~~~~~
5 |
6 | Contains built-in styles.
7 |
8 | :copyright: Copyright 2006-2010 by the Pygments team, see AUTHORS.
9 | :license: BSD, see LICENSE for details.
10 | """
11 |
12 | from pygments.plugin import find_plugin_styles
13 | from pygments.util import ClassNotFound
14 |
15 |
16 | #: Maps style names to 'submodule::classname'.
17 | STYLE_MAP = {
18 | 'default': 'default::DefaultStyle',
19 | 'emacs': 'emacs::EmacsStyle',
20 | 'friendly': 'friendly::FriendlyStyle',
21 | 'colorful': 'colorful::ColorfulStyle',
22 | 'autumn': 'autumn::AutumnStyle',
23 | 'murphy': 'murphy::MurphyStyle',
24 | 'manni': 'manni::ManniStyle',
25 | 'monokai': 'monokai::MonokaiStyle',
26 | 'perldoc': 'perldoc::PerldocStyle',
27 | 'pastie': 'pastie::PastieStyle',
28 | 'borland': 'borland::BorlandStyle',
29 | 'trac': 'trac::TracStyle',
30 | 'native': 'native::NativeStyle',
31 | 'fruity': 'fruity::FruityStyle',
32 | 'bw': 'bw::BlackWhiteStyle',
33 | 'vim': 'vim::VimStyle',
34 | 'vs': 'vs::VisualStudioStyle',
35 | 'tango': 'tango::TangoStyle',
36 | }
37 |
38 |
39 | def get_style_by_name(name):
40 | if name in STYLE_MAP:
41 | mod, cls = STYLE_MAP[name].split('::')
42 | builtin = "yes"
43 | else:
44 | for found_name, style in find_plugin_styles():
45 | if name == found_name:
46 | return style
47 | # perhaps it got dropped into our styles package
48 | builtin = ""
49 | mod = name
50 | cls = name.title() + "Style"
51 |
52 | try:
53 | mod = __import__('pygments.styles.' + mod, None, None, [cls])
54 | except ImportError:
55 | raise ClassNotFound("Could not find style module %r" % mod +
56 | (builtin and ", though it should be builtin") + ".")
57 | try:
58 | return getattr(mod, cls)
59 | except AttributeError:
60 | raise ClassNotFound("Could not find style class %r in style module." % cls)
61 |
62 |
63 | def get_all_styles():
64 | """Return an generator for all styles by name,
65 | both builtin and plugin."""
66 | for name in STYLE_MAP:
67 | yield name
68 | for name, _ in find_plugin_styles():
69 | yield name
70 |
--------------------------------------------------------------------------------
/pygments/styles/autumn.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | pygments.styles.autumn
4 | ~~~~~~~~~~~~~~~~~~~~~~
5 |
6 | A colorful style, inspired by the terminal highlighting style.
7 |
8 | :copyright: Copyright 2006-2010 by the Pygments team, see AUTHORS.
9 | :license: BSD, see LICENSE for details.
10 | """
11 |
12 | from pygments.style import Style
13 | from pygments.token import Keyword, Name, Comment, String, Error, \
14 | Number, Operator, Generic, Whitespace
15 |
16 |
17 | class AutumnStyle(Style):
18 | """
19 | A colorful style, inspired by the terminal highlighting style.
20 | """
21 |
22 | default_style = ""
23 |
24 | styles = {
25 | Whitespace: '#bbbbbb',
26 |
27 | Comment: 'italic #aaaaaa',
28 | Comment.Preproc: 'noitalic #4c8317',
29 | Comment.Special: 'italic #0000aa',
30 |
31 | Keyword: '#0000aa',
32 | Keyword.Type: '#00aaaa',
33 |
34 | Operator.Word: '#0000aa',
35 |
36 | Name.Builtin: '#00aaaa',
37 | Name.Function: '#00aa00',
38 | Name.Class: 'underline #00aa00',
39 | Name.Namespace: 'underline #00aaaa',
40 | Name.Variable: '#aa0000',
41 | Name.Constant: '#aa0000',
42 | Name.Entity: 'bold #800',
43 | Name.Attribute: '#1e90ff',
44 | Name.Tag: 'bold #1e90ff',
45 | Name.Decorator: '#888888',
46 |
47 | String: '#aa5500',
48 | String.Symbol: '#0000aa',
49 | String.Regex: '#009999',
50 |
51 | Number: '#009999',
52 |
53 | Generic.Heading: 'bold #000080',
54 | Generic.Subheading: 'bold #800080',
55 | Generic.Deleted: '#aa0000',
56 | Generic.Inserted: '#00aa00',
57 | Generic.Error: '#aa0000',
58 | Generic.Emph: 'italic',
59 | Generic.Strong: 'bold',
60 | Generic.Prompt: '#555555',
61 | Generic.Output: '#888888',
62 | Generic.Traceback: '#aa0000',
63 |
64 | Error: '#F00 bg:#FAA'
65 | }
66 |
--------------------------------------------------------------------------------
/pygments/styles/borland.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | pygments.styles.borland
4 | ~~~~~~~~~~~~~~~~~~~~~~~
5 |
6 | Style similar to the style used in the Borland IDEs.
7 |
8 | :copyright: Copyright 2006-2010 by the Pygments team, see AUTHORS.
9 | :license: BSD, see LICENSE for details.
10 | """
11 |
12 | from pygments.style import Style
13 | from pygments.token import Keyword, Name, Comment, String, Error, \
14 | Number, Operator, Generic, Whitespace
15 |
16 |
17 | class BorlandStyle(Style):
18 | """
19 | Style similar to the style used in the borland IDEs.
20 | """
21 |
22 | default_style = ''
23 |
24 | styles = {
25 | Whitespace: '#bbbbbb',
26 |
27 | Comment: 'italic #008800',
28 | Comment.Preproc: 'noitalic #008080',
29 | Comment.Special: 'noitalic bold',
30 |
31 | String: '#0000FF',
32 | String.Char: '#800080',
33 | Number: '#0000FF',
34 | Keyword: 'bold #000080',
35 | Operator.Word: 'bold',
36 | Name.Tag: 'bold #000080',
37 | Name.Attribute: '#FF0000',
38 |
39 | Generic.Heading: '#999999',
40 | Generic.Subheading: '#aaaaaa',
41 | Generic.Deleted: 'bg:#ffdddd #000000',
42 | Generic.Inserted: 'bg:#ddffdd #000000',
43 | Generic.Error: '#aa0000',
44 | Generic.Emph: 'italic',
45 | Generic.Strong: 'bold',
46 | Generic.Prompt: '#555555',
47 | Generic.Output: '#888888',
48 | Generic.Traceback: '#aa0000',
49 |
50 | Error: 'bg:#e3d2d2 #a61717'
51 | }
52 |
--------------------------------------------------------------------------------
/pygments/styles/bw.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | pygments.styles.bw
4 | ~~~~~~~~~~~~~~~~~~
5 |
6 | Simple black/white only style.
7 |
8 | :copyright: Copyright 2006-2010 by the Pygments team, see AUTHORS.
9 | :license: BSD, see LICENSE for details.
10 | """
11 |
12 | from pygments.style import Style
13 | from pygments.token import Keyword, Name, Comment, String, Error, \
14 | Operator, Generic
15 |
16 |
17 | class BlackWhiteStyle(Style):
18 |
19 | background_color = "#ffffff"
20 | default_style = ""
21 |
22 | styles = {
23 | Comment: "italic",
24 | Comment.Preproc: "noitalic",
25 |
26 | Keyword: "bold",
27 | Keyword.Pseudo: "nobold",
28 | Keyword.Type: "nobold",
29 |
30 | Operator.Word: "bold",
31 |
32 | Name.Class: "bold",
33 | Name.Namespace: "bold",
34 | Name.Exception: "bold",
35 | Name.Entity: "bold",
36 | Name.Tag: "bold",
37 |
38 | String: "italic",
39 | String.Interpol: "bold",
40 | String.Escape: "bold",
41 |
42 | Generic.Heading: "bold",
43 | Generic.Subheading: "bold",
44 | Generic.Emph: "italic",
45 | Generic.Strong: "bold",
46 | Generic.Prompt: "bold",
47 |
48 | Error: "border:#FF0000"
49 | }
50 |
--------------------------------------------------------------------------------
/pygments/styles/colorful.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | pygments.styles.colorful
4 | ~~~~~~~~~~~~~~~~~~~~~~~~
5 |
6 | A colorful style, inspired by CodeRay.
7 |
8 | :copyright: Copyright 2006-2010 by the Pygments team, see AUTHORS.
9 | :license: BSD, see LICENSE for details.
10 | """
11 |
12 | from pygments.style import Style
13 | from pygments.token import Keyword, Name, Comment, String, Error, \
14 | Number, Operator, Generic, Whitespace
15 |
16 |
17 | class ColorfulStyle(Style):
18 | """
19 | A colorful style, inspired by CodeRay.
20 | """
21 |
22 | default_style = ""
23 |
24 | styles = {
25 | Whitespace: "#bbbbbb",
26 |
27 | Comment: "#888",
28 | Comment.Preproc: "#579",
29 | Comment.Special: "bold #cc0000",
30 |
31 | Keyword: "bold #080",
32 | Keyword.Pseudo: "#038",
33 | Keyword.Type: "#339",
34 |
35 | Operator: "#333",
36 | Operator.Word: "bold #000",
37 |
38 | Name.Builtin: "#007020",
39 | Name.Function: "bold #06B",
40 | Name.Class: "bold #B06",
41 | Name.Namespace: "bold #0e84b5",
42 | Name.Exception: "bold #F00",
43 | Name.Variable: "#963",
44 | Name.Variable.Instance: "#33B",
45 | Name.Variable.Class: "#369",
46 | Name.Variable.Global: "bold #d70",
47 | Name.Constant: "bold #036",
48 | Name.Label: "bold #970",
49 | Name.Entity: "bold #800",
50 | Name.Attribute: "#00C",
51 | Name.Tag: "#070",
52 | Name.Decorator: "bold #555",
53 |
54 | String: "bg:#fff0f0",
55 | String.Char: "#04D bg:",
56 | String.Doc: "#D42 bg:",
57 | String.Interpol: "bg:#eee",
58 | String.Escape: "bold #666",
59 | String.Regex: "bg:#fff0ff #000",
60 | String.Symbol: "#A60 bg:",
61 | String.Other: "#D20",
62 |
63 | Number: "bold #60E",
64 | Number.Integer: "bold #00D",
65 | Number.Float: "bold #60E",
66 | Number.Hex: "bold #058",
67 | Number.Oct: "bold #40E",
68 |
69 | Generic.Heading: "bold #000080",
70 | Generic.Subheading: "bold #800080",
71 | Generic.Deleted: "#A00000",
72 | Generic.Inserted: "#00A000",
73 | Generic.Error: "#FF0000",
74 | Generic.Emph: "italic",
75 | Generic.Strong: "bold",
76 | Generic.Prompt: "bold #c65d09",
77 | Generic.Output: "#888",
78 | Generic.Traceback: "#04D",
79 |
80 | Error: "#F00 bg:#FAA"
81 | }
82 |
--------------------------------------------------------------------------------
/pygments/styles/default.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | pygments.styles.default
4 | ~~~~~~~~~~~~~~~~~~~~~~~
5 |
6 | The default highlighting style.
7 |
8 | :copyright: Copyright 2006-2010 by the Pygments team, see AUTHORS.
9 | :license: BSD, see LICENSE for details.
10 | """
11 |
12 | from pygments.style import Style
13 | from pygments.token import Keyword, Name, Comment, String, Error, \
14 | Number, Operator, Generic, Whitespace
15 |
16 |
17 | class DefaultStyle(Style):
18 | """
19 | The default style (inspired by Emacs 22).
20 | """
21 |
22 | background_color = "#f8f8f8"
23 | default_style = ""
24 |
25 | styles = {
26 | Whitespace: "#bbbbbb",
27 | Comment: "italic #408080",
28 | Comment.Preproc: "noitalic #BC7A00",
29 |
30 | #Keyword: "bold #AA22FF",
31 | Keyword: "bold #008000",
32 | Keyword.Pseudo: "nobold",
33 | Keyword.Type: "nobold #B00040",
34 |
35 | Operator: "#666666",
36 | Operator.Word: "bold #AA22FF",
37 |
38 | Name.Builtin: "#008000",
39 | Name.Function: "#0000FF",
40 | Name.Class: "bold #0000FF",
41 | Name.Namespace: "bold #0000FF",
42 | Name.Exception: "bold #D2413A",
43 | Name.Variable: "#19177C",
44 | Name.Constant: "#880000",
45 | Name.Label: "#A0A000",
46 | Name.Entity: "bold #999999",
47 | Name.Attribute: "#7D9029",
48 | Name.Tag: "bold #008000",
49 | Name.Decorator: "#AA22FF",
50 |
51 | String: "#BA2121",
52 | String.Doc: "italic",
53 | String.Interpol: "bold #BB6688",
54 | String.Escape: "bold #BB6622",
55 | String.Regex: "#BB6688",
56 | #String.Symbol: "#B8860B",
57 | String.Symbol: "#19177C",
58 | String.Other: "#008000",
59 | Number: "#666666",
60 |
61 | Generic.Heading: "bold #000080",
62 | Generic.Subheading: "bold #800080",
63 | Generic.Deleted: "#A00000",
64 | Generic.Inserted: "#00A000",
65 | Generic.Error: "#FF0000",
66 | Generic.Emph: "italic",
67 | Generic.Strong: "bold",
68 | Generic.Prompt: "bold #000080",
69 | Generic.Output: "#888",
70 | Generic.Traceback: "#04D",
71 |
72 | Error: "border:#FF0000"
73 | }
74 |
--------------------------------------------------------------------------------
/pygments/styles/emacs.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | pygments.styles.emacs
4 | ~~~~~~~~~~~~~~~~~~~~~
5 |
6 | A highlighting style for Pygments, inspired by Emacs.
7 |
8 | :copyright: Copyright 2006-2010 by the Pygments team, see AUTHORS.
9 | :license: BSD, see LICENSE for details.
10 | """
11 |
12 | from pygments.style import Style
13 | from pygments.token import Keyword, Name, Comment, String, Error, \
14 | Number, Operator, Generic, Whitespace
15 |
16 |
17 | class EmacsStyle(Style):
18 | """
19 | The default style (inspired by Emacs 22).
20 | """
21 |
22 | background_color = "#f8f8f8"
23 | default_style = ""
24 |
25 | styles = {
26 | Whitespace: "#bbbbbb",
27 | Comment: "italic #008800",
28 | Comment.Preproc: "noitalic",
29 | Comment.Special: "noitalic bold",
30 |
31 | Keyword: "bold #AA22FF",
32 | Keyword.Pseudo: "nobold",
33 | Keyword.Type: "bold #00BB00",
34 |
35 | Operator: "#666666",
36 | Operator.Word: "bold #AA22FF",
37 |
38 | Name.Builtin: "#AA22FF",
39 | Name.Function: "#00A000",
40 | Name.Class: "#0000FF",
41 | Name.Namespace: "bold #0000FF",
42 | Name.Exception: "bold #D2413A",
43 | Name.Variable: "#B8860B",
44 | Name.Constant: "#880000",
45 | Name.Label: "#A0A000",
46 | Name.Entity: "bold #999999",
47 | Name.Attribute: "#BB4444",
48 | Name.Tag: "bold #008000",
49 | Name.Decorator: "#AA22FF",
50 |
51 | String: "#BB4444",
52 | String.Doc: "italic",
53 | String.Interpol: "bold #BB6688",
54 | String.Escape: "bold #BB6622",
55 | String.Regex: "#BB6688",
56 | String.Symbol: "#B8860B",
57 | String.Other: "#008000",
58 | Number: "#666666",
59 |
60 | Generic.Heading: "bold #000080",
61 | Generic.Subheading: "bold #800080",
62 | Generic.Deleted: "#A00000",
63 | Generic.Inserted: "#00A000",
64 | Generic.Error: "#FF0000",
65 | Generic.Emph: "italic",
66 | Generic.Strong: "bold",
67 | Generic.Prompt: "bold #000080",
68 | Generic.Output: "#888",
69 | Generic.Traceback: "#04D",
70 |
71 | Error: "border:#FF0000"
72 | }
73 |
--------------------------------------------------------------------------------
/pygments/styles/friendly.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | pygments.styles.friendly
4 | ~~~~~~~~~~~~~~~~~~~~~~~~
5 |
6 | A modern style based on the VIM pyte theme.
7 |
8 | :copyright: Copyright 2006-2010 by the Pygments team, see AUTHORS.
9 | :license: BSD, see LICENSE for details.
10 | """
11 |
12 | from pygments.style import Style
13 | from pygments.token import Keyword, Name, Comment, String, Error, \
14 | Number, Operator, Generic, Whitespace
15 |
16 |
17 | class FriendlyStyle(Style):
18 | """
19 | A modern style based on the VIM pyte theme.
20 | """
21 |
22 | background_color = "#f0f0f0"
23 | default_style = ""
24 |
25 | styles = {
26 | Whitespace: "#bbbbbb",
27 | Comment: "italic #60a0b0",
28 | Comment.Preproc: "noitalic #007020",
29 | Comment.Special: "noitalic bg:#fff0f0",
30 |
31 | Keyword: "bold #007020",
32 | Keyword.Pseudo: "nobold",
33 | Keyword.Type: "nobold #902000",
34 |
35 | Operator: "#666666",
36 | Operator.Word: "bold #007020",
37 |
38 | Name.Builtin: "#007020",
39 | Name.Function: "#06287e",
40 | Name.Class: "bold #0e84b5",
41 | Name.Namespace: "bold #0e84b5",
42 | Name.Exception: "#007020",
43 | Name.Variable: "#bb60d5",
44 | Name.Constant: "#60add5",
45 | Name.Label: "bold #002070",
46 | Name.Entity: "bold #d55537",
47 | Name.Attribute: "#4070a0",
48 | Name.Tag: "bold #062873",
49 | Name.Decorator: "bold #555555",
50 |
51 | String: "#4070a0",
52 | String.Doc: "italic",
53 | String.Interpol: "italic #70a0d0",
54 | String.Escape: "bold #4070a0",
55 | String.Regex: "#235388",
56 | String.Symbol: "#517918",
57 | String.Other: "#c65d09",
58 | Number: "#40a070",
59 |
60 | Generic.Heading: "bold #000080",
61 | Generic.Subheading: "bold #800080",
62 | Generic.Deleted: "#A00000",
63 | Generic.Inserted: "#00A000",
64 | Generic.Error: "#FF0000",
65 | Generic.Emph: "italic",
66 | Generic.Strong: "bold",
67 | Generic.Prompt: "bold #c65d09",
68 | Generic.Output: "#888",
69 | Generic.Traceback: "#04D",
70 |
71 | Error: "border:#FF0000"
72 | }
73 |
--------------------------------------------------------------------------------
/pygments/styles/fruity.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | pygments.styles.fruity
4 | ~~~~~~~~~~~~~~~~~~~~~~
5 |
6 | pygments version of my "fruity" vim theme.
7 |
8 | :copyright: Copyright 2006-2010 by the Pygments team, see AUTHORS.
9 | :license: BSD, see LICENSE for details.
10 | """
11 |
12 | from pygments.style import Style
13 | from pygments.token import Token, Comment, Name, Keyword, \
14 | Generic, Number, String, Whitespace
15 |
16 | class FruityStyle(Style):
17 | """
18 | Pygments version of the "native" vim theme.
19 | """
20 |
21 | background_color = '#111111'
22 | highlight_color = '#333333'
23 |
24 | styles = {
25 | Whitespace: '#888888',
26 | Token: '#ffffff',
27 | Generic.Output: '#444444 bg:#222222',
28 | Keyword: '#fb660a bold',
29 | Keyword.Pseudo: 'nobold',
30 | Number: '#0086f7 bold',
31 | Name.Tag: '#fb660a bold',
32 | Name.Variable: '#fb660a',
33 | Name.Constant: '#fb660a',
34 | Comment: '#008800 bg:#0f140f italic',
35 | Name.Attribute: '#ff0086 bold',
36 | String: '#0086d2',
37 | Name.Function: '#ff0086 bold',
38 | Generic.Heading: '#ffffff bold',
39 | Keyword.Type: '#cdcaa9 bold',
40 | Generic.Subheading: '#ffffff bold',
41 | Name.Constant: '#0086d2',
42 | Comment.Preproc: '#ff0007 bold'
43 | }
44 |
--------------------------------------------------------------------------------
/pygments/styles/manni.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | pygments.styles.manni
4 | ~~~~~~~~~~~~~~~~~~~~~
5 |
6 | A colorful style, inspired by the terminal highlighting style.
7 |
8 | This is a port of the style used in the `php port`_ of pygments
9 | by Manni. The style is called 'default' there.
10 |
11 | :copyright: Copyright 2006-2010 by the Pygments team, see AUTHORS.
12 | :license: BSD, see LICENSE for details.
13 | """
14 |
15 | from pygments.style import Style
16 | from pygments.token import Keyword, Name, Comment, String, Error, \
17 | Number, Operator, Generic, Whitespace
18 |
19 |
20 | class ManniStyle(Style):
21 | """
22 | A colorful style, inspired by the terminal highlighting style.
23 | """
24 |
25 | background_color = '#f0f3f3'
26 |
27 | styles = {
28 | Whitespace: '#bbbbbb',
29 | Comment: 'italic #0099FF',
30 | Comment.Preproc: 'noitalic #009999',
31 | Comment.Special: 'bold',
32 |
33 | Keyword: 'bold #006699',
34 | Keyword.Pseudo: 'nobold',
35 | Keyword.Type: '#007788',
36 |
37 | Operator: '#555555',
38 | Operator.Word: 'bold #000000',
39 |
40 | Name.Builtin: '#336666',
41 | Name.Function: '#CC00FF',
42 | Name.Class: 'bold #00AA88',
43 | Name.Namespace: 'bold #00CCFF',
44 | Name.Exception: 'bold #CC0000',
45 | Name.Variable: '#003333',
46 | Name.Constant: '#336600',
47 | Name.Label: '#9999FF',
48 | Name.Entity: 'bold #999999',
49 | Name.Attribute: '#330099',
50 | Name.Tag: 'bold #330099',
51 | Name.Decorator: '#9999FF',
52 |
53 | String: '#CC3300',
54 | String.Doc: 'italic',
55 | String.Interpol: '#AA0000',
56 | String.Escape: 'bold #CC3300',
57 | String.Regex: '#33AAAA',
58 | String.Symbol: '#FFCC33',
59 | String.Other: '#CC3300',
60 |
61 | Number: '#FF6600',
62 |
63 | Generic.Heading: 'bold #003300',
64 | Generic.Subheading: 'bold #003300',
65 | Generic.Deleted: 'border:#CC0000 bg:#FFCCCC',
66 | Generic.Inserted: 'border:#00CC00 bg:#CCFFCC',
67 | Generic.Error: '#FF0000',
68 | Generic.Emph: 'italic',
69 | Generic.Strong: 'bold',
70 | Generic.Prompt: 'bold #000099',
71 | Generic.Output: '#AAAAAA',
72 | Generic.Traceback: '#99CC66',
73 |
74 | Error: 'bg:#FFAAAA #AA0000'
75 | }
76 |
--------------------------------------------------------------------------------
/pygments/styles/murphy.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | pygments.styles.murphy
4 | ~~~~~~~~~~~~~~~~~~~~~~
5 |
6 | Murphy's style from CodeRay.
7 |
8 | :copyright: Copyright 2006-2010 by the Pygments team, see AUTHORS.
9 | :license: BSD, see LICENSE for details.
10 | """
11 |
12 | from pygments.style import Style
13 | from pygments.token import Keyword, Name, Comment, String, Error, \
14 | Number, Operator, Generic, Whitespace
15 |
16 |
17 | class MurphyStyle(Style):
18 | """
19 | Murphy's style from CodeRay.
20 | """
21 |
22 | default_style = ""
23 |
24 | styles = {
25 | Whitespace: "#bbbbbb",
26 | Comment: "#666 italic",
27 | Comment.Preproc: "#579 noitalic",
28 | Comment.Special: "#c00 bold",
29 |
30 | Keyword: "bold #289",
31 | Keyword.Pseudo: "#08f",
32 | Keyword.Type: "#66f",
33 |
34 | Operator: "#333",
35 | Operator.Word: "bold #000",
36 |
37 | Name.Builtin: "#072",
38 | Name.Function: "bold #5ed",
39 | Name.Class: "bold #e9e",
40 | Name.Namespace: "bold #0e84b5",
41 | Name.Exception: "bold #F00",
42 | Name.Variable: "#036",
43 | Name.Variable.Instance: "#aaf",
44 | Name.Variable.Class: "#ccf",
45 | Name.Variable.Global: "#f84",
46 | Name.Constant: "bold #5ed",
47 | Name.Label: "bold #970",
48 | Name.Entity: "#800",
49 | Name.Attribute: "#007",
50 | Name.Tag: "#070",
51 | Name.Decorator: "bold #555",
52 |
53 | String: "bg:#e0e0ff",
54 | String.Char: "#88F bg:",
55 | String.Doc: "#D42 bg:",
56 | String.Interpol: "bg:#eee",
57 | String.Escape: "bold #666",
58 | String.Regex: "bg:#e0e0ff #000",
59 | String.Symbol: "#fc8 bg:",
60 | String.Other: "#f88",
61 |
62 | Number: "bold #60E",
63 | Number.Integer: "bold #66f",
64 | Number.Float: "bold #60E",
65 | Number.Hex: "bold #058",
66 | Number.Oct: "bold #40E",
67 |
68 | Generic.Heading: "bold #000080",
69 | Generic.Subheading: "bold #800080",
70 | Generic.Deleted: "#A00000",
71 | Generic.Inserted: "#00A000",
72 | Generic.Error: "#FF0000",
73 | Generic.Emph: "italic",
74 | Generic.Strong: "bold",
75 | Generic.Prompt: "bold #c65d09",
76 | Generic.Output: "#888",
77 | Generic.Traceback: "#04D",
78 |
79 | Error: "#F00 bg:#FAA"
80 | }
81 |
--------------------------------------------------------------------------------
/pygments/styles/native.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | pygments.styles.native
4 | ~~~~~~~~~~~~~~~~~~~~~~
5 |
6 | pygments version of my "native" vim theme.
7 |
8 | :copyright: Copyright 2006-2010 by the Pygments team, see AUTHORS.
9 | :license: BSD, see LICENSE for details.
10 | """
11 |
12 | from pygments.style import Style
13 | from pygments.token import Keyword, Name, Comment, String, Error, \
14 | Number, Operator, Generic, Token, Whitespace
15 |
16 |
17 | class NativeStyle(Style):
18 | """
19 | Pygments version of the "native" vim theme.
20 | """
21 |
22 | background_color = '#202020'
23 | highlight_color = '#404040'
24 |
25 | styles = {
26 | Token: '#d0d0d0',
27 | Whitespace: '#666666',
28 |
29 | Comment: 'italic #999999',
30 | Comment.Preproc: 'noitalic bold #cd2828',
31 | Comment.Special: 'noitalic bold #e50808 bg:#520000',
32 |
33 | Keyword: 'bold #6ab825',
34 | Keyword.Pseudo: 'nobold',
35 | Operator.Word: 'bold #6ab825',
36 |
37 | String: '#ed9d13',
38 | String.Other: '#ffa500',
39 |
40 | Number: '#3677a9',
41 |
42 | Name.Builtin: '#24909d',
43 | Name.Variable: '#40ffff',
44 | Name.Constant: '#40ffff',
45 | Name.Class: 'underline #447fcf',
46 | Name.Function: '#447fcf',
47 | Name.Namespace: 'underline #447fcf',
48 | Name.Exception: '#bbbbbb',
49 | Name.Tag: 'bold #6ab825',
50 | Name.Attribute: '#bbbbbb',
51 | Name.Decorator: '#ffa500',
52 |
53 | Generic.Heading: 'bold #ffffff',
54 | Generic.Subheading: 'underline #ffffff',
55 | Generic.Deleted: '#d22323',
56 | Generic.Inserted: '#589819',
57 | Generic.Error: '#d22323',
58 | Generic.Emph: 'italic',
59 | Generic.Strong: 'bold',
60 | Generic.Prompt: '#aaaaaa',
61 | Generic.Output: '#cccccc',
62 | Generic.Traceback: '#d22323',
63 |
64 | Error: 'bg:#e3d2d2 #a61717'
65 | }
66 |
--------------------------------------------------------------------------------
/pygments/styles/pastie.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | pygments.styles.pastie
4 | ~~~~~~~~~~~~~~~~~~~~~~
5 |
6 | Style similar to the `pastie`_ default style.
7 |
8 | .. _pastie: http://pastie.caboo.se/
9 |
10 | :copyright: Copyright 2006-2010 by the Pygments team, see AUTHORS.
11 | :license: BSD, see LICENSE for details.
12 | """
13 |
14 | from pygments.style import Style
15 | from pygments.token import Keyword, Name, Comment, String, Error, \
16 | Number, Operator, Generic, Whitespace
17 |
18 |
19 | class PastieStyle(Style):
20 | """
21 | Style similar to the pastie default style.
22 | """
23 |
24 | default_style = ''
25 |
26 | styles = {
27 | Whitespace: '#bbbbbb',
28 | Comment: '#888888',
29 | Comment.Preproc: 'bold #cc0000',
30 | Comment.Special: 'bg:#fff0f0 bold #cc0000',
31 |
32 | String: 'bg:#fff0f0 #dd2200',
33 | String.Regex: 'bg:#fff0ff #008800',
34 | String.Other: 'bg:#f0fff0 #22bb22',
35 | String.Symbol: '#aa6600',
36 | String.Interpol: '#3333bb',
37 | String.Escape: '#0044dd',
38 |
39 | Operator.Word: '#008800',
40 |
41 | Keyword: 'bold #008800',
42 | Keyword.Pseudo: 'nobold',
43 | Keyword.Type: '#888888',
44 |
45 | Name.Class: 'bold #bb0066',
46 | Name.Exception: 'bold #bb0066',
47 | Name.Function: 'bold #0066bb',
48 | Name.Property: 'bold #336699',
49 | Name.Namespace: 'bold #bb0066',
50 | Name.Builtin: '#003388',
51 | Name.Variable: '#336699',
52 | Name.Variable.Class: '#336699',
53 | Name.Variable.Instance: '#3333bb',
54 | Name.Variable.Global: '#dd7700',
55 | Name.Constant: 'bold #003366',
56 | Name.Tag: 'bold #bb0066',
57 | Name.Attribute: '#336699',
58 | Name.Decorator: '#555555',
59 | Name.Label: 'italic #336699',
60 |
61 | Number: 'bold #0000DD',
62 |
63 | Generic.Heading: '#333',
64 | Generic.Subheading: '#666',
65 | Generic.Deleted: 'bg:#ffdddd #000000',
66 | Generic.Inserted: 'bg:#ddffdd #000000',
67 | Generic.Error: '#aa0000',
68 | Generic.Emph: 'italic',
69 | Generic.Strong: 'bold',
70 | Generic.Prompt: '#555555',
71 | Generic.Output: '#888888',
72 | Generic.Traceback: '#aa0000',
73 |
74 | Error: 'bg:#e3d2d2 #a61717'
75 | }
76 |
--------------------------------------------------------------------------------
/pygments/styles/perldoc.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | pygments.styles.perldoc
4 | ~~~~~~~~~~~~~~~~~~~~~~~
5 |
6 | Style similar to the style used in the `perldoc`_ code blocks.
7 |
8 | .. _perldoc: http://perldoc.perl.org/
9 |
10 | :copyright: Copyright 2006-2010 by the Pygments team, see AUTHORS.
11 | :license: BSD, see LICENSE for details.
12 | """
13 |
14 | from pygments.style import Style
15 | from pygments.token import Keyword, Name, Comment, String, Error, \
16 | Number, Operator, Generic, Whitespace
17 |
18 |
19 | class PerldocStyle(Style):
20 | """
21 | Style similar to the style used in the perldoc code blocks.
22 | """
23 |
24 | background_color = '#eeeedd'
25 | default_style = ''
26 |
27 | styles = {
28 | Whitespace: '#bbbbbb',
29 | Comment: '#228B22',
30 | Comment.Preproc: '#1e889b',
31 | Comment.Special: '#8B008B bold',
32 |
33 | String: '#CD5555',
34 | String.Heredoc: '#1c7e71 italic',
35 | String.Regex: '#B452CD',
36 | String.Other: '#cb6c20',
37 | String.Regex: '#1c7e71',
38 |
39 | Number: '#B452CD',
40 |
41 | Operator.Word: '#8B008B',
42 |
43 | Keyword: '#8B008B bold',
44 | Keyword.Type: '#a7a7a7',
45 |
46 | Name.Class: '#008b45 bold',
47 | Name.Exception: '#008b45 bold',
48 | Name.Function: '#008b45',
49 | Name.Namespace: '#008b45 underline',
50 | Name.Variable: '#00688B',
51 | Name.Constant: '#00688B',
52 | Name.Decorator: '#707a7c',
53 | Name.Tag: '#8B008B bold',
54 | Name.Attribute: '#658b00',
55 | Name.Builtin: '#658b00',
56 |
57 | Generic.Heading: 'bold #000080',
58 | Generic.Subheading: 'bold #800080',
59 | Generic.Deleted: '#aa0000',
60 | Generic.Inserted: '#00aa00',
61 | Generic.Error: '#aa0000',
62 | Generic.Emph: 'italic',
63 | Generic.Strong: 'bold',
64 | Generic.Prompt: '#555555',
65 | Generic.Output: '#888888',
66 | Generic.Traceback: '#aa0000',
67 |
68 | Error: 'bg:#e3d2d2 #a61717'
69 | }
70 |
--------------------------------------------------------------------------------
/pygments/styles/trac.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | pygments.styles.trac
4 | ~~~~~~~~~~~~~~~~~~~~
5 |
6 | Port of the default trac highlighter design.
7 |
8 | :copyright: Copyright 2006-2010 by the Pygments team, see AUTHORS.
9 | :license: BSD, see LICENSE for details.
10 | """
11 |
12 | from pygments.style import Style
13 | from pygments.token import Keyword, Name, Comment, String, Error, \
14 | Number, Operator, Generic, Whitespace
15 |
16 |
17 | class TracStyle(Style):
18 | """
19 | Port of the default trac highlighter design.
20 | """
21 |
22 | default_style = ''
23 |
24 | styles = {
25 | Whitespace: '#bbbbbb',
26 | Comment: 'italic #999988',
27 | Comment.Preproc: 'bold noitalic #999999',
28 | Comment.Special: 'bold #999999',
29 |
30 | Operator: 'bold',
31 |
32 | String: '#bb8844',
33 | String.Regex: '#808000',
34 |
35 | Number: '#009999',
36 |
37 | Keyword: 'bold',
38 | Keyword.Type: '#445588',
39 |
40 | Name.Builtin: '#999999',
41 | Name.Function: 'bold #990000',
42 | Name.Class: 'bold #445588',
43 | Name.Exception: 'bold #990000',
44 | Name.Namespace: '#555555',
45 | Name.Variable: '#008080',
46 | Name.Constant: '#008080',
47 | Name.Tag: '#000080',
48 | Name.Attribute: '#008080',
49 | Name.Entity: '#800080',
50 |
51 | Generic.Heading: '#999999',
52 | Generic.Subheading: '#aaaaaa',
53 | Generic.Deleted: 'bg:#ffdddd #000000',
54 | Generic.Inserted: 'bg:#ddffdd #000000',
55 | Generic.Error: '#aa0000',
56 | Generic.Emph: 'italic',
57 | Generic.Strong: 'bold',
58 | Generic.Prompt: '#555555',
59 | Generic.Output: '#888888',
60 | Generic.Traceback: '#aa0000',
61 |
62 | Error: 'bg:#e3d2d2 #a61717'
63 | }
64 |
--------------------------------------------------------------------------------
/pygments/styles/vim.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | pygments.styles.vim
4 | ~~~~~~~~~~~~~~~~~~~
5 |
6 | A highlighting style for Pygments, inspired by vim.
7 |
8 | :copyright: Copyright 2006-2010 by the Pygments team, see AUTHORS.
9 | :license: BSD, see LICENSE for details.
10 | """
11 |
12 | from pygments.style import Style
13 | from pygments.token import Keyword, Name, Comment, String, Error, \
14 | Number, Operator, Generic, Whitespace, Token
15 |
16 |
17 | class VimStyle(Style):
18 | """
19 | Styles somewhat like vim 7.0
20 | """
21 |
22 | background_color = "#000000"
23 | highlight_color = "#222222"
24 | default_style = "#cccccc"
25 |
26 | styles = {
27 | Token: "#cccccc",
28 | Whitespace: "",
29 | Comment: "#000080",
30 | Comment.Preproc: "",
31 | Comment.Special: "bold #cd0000",
32 |
33 | Keyword: "#cdcd00",
34 | Keyword.Declaration: "#00cd00",
35 | Keyword.Namespace: "#cd00cd",
36 | Keyword.Pseudo: "",
37 | Keyword.Type: "#00cd00",
38 |
39 | Operator: "#3399cc",
40 | Operator.Word: "#cdcd00",
41 |
42 | Name: "",
43 | Name.Class: "#00cdcd",
44 | Name.Builtin: "#cd00cd",
45 | Name.Exception: "bold #666699",
46 | Name.Variable: "#00cdcd",
47 |
48 | String: "#cd0000",
49 | Number: "#cd00cd",
50 |
51 | Generic.Heading: "bold #000080",
52 | Generic.Subheading: "bold #800080",
53 | Generic.Deleted: "#cd0000",
54 | Generic.Inserted: "#00cd00",
55 | Generic.Error: "#FF0000",
56 | Generic.Emph: "italic",
57 | Generic.Strong: "bold",
58 | Generic.Prompt: "bold #000080",
59 | Generic.Output: "#888",
60 | Generic.Traceback: "#04D",
61 |
62 | Error: "border:#FF0000"
63 | }
64 |
--------------------------------------------------------------------------------
/pygments/styles/vs.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | pygments.styles.vs
4 | ~~~~~~~~~~~~~~~~~~
5 |
6 | Simple style with MS Visual Studio colors.
7 |
8 | :copyright: Copyright 2006-2010 by the Pygments team, see AUTHORS.
9 | :license: BSD, see LICENSE for details.
10 | """
11 |
12 | from pygments.style import Style
13 | from pygments.token import Keyword, Name, Comment, String, Error, \
14 | Operator, Generic
15 |
16 |
17 | class VisualStudioStyle(Style):
18 |
19 | background_color = "#ffffff"
20 | default_style = ""
21 |
22 | styles = {
23 | Comment: "#008000",
24 | Comment.Preproc: "#0000ff",
25 | Keyword: "#0000ff",
26 | Operator.Word: "#0000ff",
27 | Keyword.Type: "#2b91af",
28 | Name.Class: "#2b91af",
29 | String: "#a31515",
30 |
31 | Generic.Heading: "bold",
32 | Generic.Subheading: "bold",
33 | Generic.Emph: "italic",
34 | Generic.Strong: "bold",
35 | Generic.Prompt: "bold",
36 |
37 | Error: "border:#FF0000"
38 | }
39 |
--------------------------------------------------------------------------------
/werkzeug/contrib/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | werkzeug.contrib
4 | ~~~~~~~~~~~~~~~~
5 |
6 | Contains user-submitted code that other users may find useful, but which
7 | is not part of the Werkzeug core. Anyone can write code for inclusion in
8 | the `contrib` package. All modules in this package are distributed as an
9 | add-on library and thus are not part of Werkzeug itself.
10 |
11 | This file itself is mostly for informational purposes and to tell the
12 | Python interpreter that `contrib` is a package.
13 |
14 | :copyright: (c) 2010 by the Werkzeug Team, see AUTHORS for more details.
15 | :license: BSD, see LICENSE for more details.
16 | """
17 |
--------------------------------------------------------------------------------
/werkzeug/contrib/limiter.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | werkzeug.contrib.limiter
4 | ~~~~~~~~~~~~~~~~~~~~~~~~
5 |
6 | A middleware that limits incoming data. This works around problems with
7 | Trac_ or Django_ because those directly stream into the memory.
8 |
9 | .. _Trac: http://trac.edgewall.org/
10 | .. _Django: http://www.djangoproject.com/
11 |
12 | :copyright: (c) 2010 by the Werkzeug Team, see AUTHORS for more details.
13 | :license: BSD, see LICENSE for more details.
14 | """
15 | from warnings import warn
16 |
17 | from werkzeug import LimitedStream
18 |
19 |
20 | class StreamLimitMiddleware(object):
21 | """Limits the input stream to a given number of bytes. This is useful if
22 | you have a WSGI application that reads form data into memory (django for
23 | example) and you don't want users to harm the server by uploading tons of
24 | data.
25 |
26 | Default is 10MB
27 | """
28 |
29 | def __init__(self, app, maximum_size=1024 * 1024 * 10):
30 | self.app = app
31 | self.maximum_size = maximum_size
32 |
33 | def __call__(self, environ, start_response):
34 | limit = min(limit, int(environ.get('CONTENT_LENGTH') or 0))
35 | environ['wsgi.input'] = LimitedStream(environ['wsgi.input'], limit)
36 | return self.app(environ, start_response)
37 |
--------------------------------------------------------------------------------
/werkzeug/contrib/testtools.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | werkzeug.contrib.testtools
4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~
5 |
6 | This module implements extended wrappers for simplified testing.
7 |
8 | `TestResponse`
9 | A response wrapper which adds various cached attributes for
10 | simplified assertions on various content types.
11 |
12 | :copyright: (c) 2010 by the Werkzeug Team, see AUTHORS for more details.
13 | :license: BSD, see LICENSE for more details.
14 | """
15 | from werkzeug import Response, cached_property, import_string
16 |
17 |
18 | class ContentAccessors(object):
19 | """
20 | A mixin class for response objects that provides a couple of useful
21 | accessors for unittesting.
22 | """
23 |
24 | def xml(self):
25 | """Get an etree if possible."""
26 | if 'xml' not in self.mimetype:
27 | raise AttributeError(
28 | 'Not a XML response (Content-Type: %s)'
29 | % self.mimetype)
30 | for module in ['xml.etree.ElementTree', 'ElementTree',
31 | 'elementtree.ElementTree']:
32 | etree = import_string(module, silent=True)
33 | if etree is not None:
34 | return etree.XML(self.body)
35 | raise RuntimeError('You must have ElementTree installed '
36 | 'to use TestResponse.xml')
37 | xml = cached_property(xml)
38 |
39 | def lxml(self):
40 | """Get an lxml etree if possible."""
41 | if ('html' not in self.mimetype and 'xml' not in self.mimetype):
42 | raise AttributeError('Not an HTML/XML response')
43 | from lxml import etree
44 | try:
45 | from lxml.html import fromstring
46 | except ImportError:
47 | fromstring = etree.HTML
48 | if self.mimetype=='text/html':
49 | return fromstring(self.data)
50 | return etree.XML(self.data)
51 | lxml = cached_property(lxml)
52 |
53 | def json(self):
54 | """Get the result of simplejson.loads if possible."""
55 | if 'json' not in self.mimetype:
56 | raise AttributeError('Not a JSON response')
57 | try:
58 | from simplejson import loads
59 | except:
60 | from json import loads
61 | return loads(self.data)
62 | json = cached_property(json)
63 |
64 |
65 | class TestResponse(Response, ContentAccessors):
66 | """Pass this to `werkzeug.test.Client` for easier unittesting."""
67 |
--------------------------------------------------------------------------------
/werkzeug/debug/render.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | werkzeug.debug.render
4 | ~~~~~~~~~~~~~~~~~~~~~
5 |
6 | Render the traceback debugging page.
7 |
8 | :copyright: (c) 2010 by the Werkzeug Team, see AUTHORS for more details.
9 | :license: BSD, see LICENSE for more details.
10 | """
11 | import pprint
12 | from os.path import dirname, join
13 |
14 | from werkzeug.templates import Template
15 |
16 |
17 | def get_template(name):
18 | return Template.from_file(join(dirname(__file__), 'shared', name),
19 | unicode_mode=False, errors='ignore')
20 |
21 |
22 | def load_resource(res):
23 | try:
24 | f = file(join(dirname(__file__), 'shared', res))
25 | except IOError:
26 | return ''
27 | try:
28 | return f.read()
29 | finally:
30 | f.close()
31 |
32 |
33 | t_body = get_template('body.tmpl')
34 | t_codetable = get_template('codetable.tmpl')
35 | t_vartable = get_template('vartable.tmpl')
36 |
37 |
38 | def code_table(frame):
39 | from werkzeug.debug.util import Namespace
40 | lines = []
41 | lineno = frame['context_lineno']
42 | if lineno is not None:
43 | lineno += 1
44 | for l in frame['pre_context']:
45 | lines.append(Namespace(mode='pre', lineno=lineno, code=l))
46 | lineno += 1
47 | lines.append(Namespace(mode='cur', lineno=lineno,
48 | code=frame['context_line']))
49 | lineno += 1
50 | for l in frame['post_context']:
51 | lines.append(Namespace(mode='post', lineno=lineno, code=l))
52 | lineno += 1
53 | else:
54 | lines.append(Namespace(mode='cur', lineno=1,
55 | code='Sourcecode not available'))
56 |
57 | return t_codetable.render(lines=lines)
58 |
59 |
60 | def var_table(var):
61 | def safe_pformat(x):
62 | try:
63 | lines = pprint.pformat(x).splitlines()
64 | except:
65 | return '?'
66 | tmp = []
67 | for line in lines:
68 | if len(line) > 79:
69 | line = line[:79] + '...'
70 | tmp.append(line)
71 | return '\n'.join(tmp)
72 |
73 | # dicts
74 | if isinstance(var, dict) or hasattr(var, 'items'):
75 | value = var.items()
76 | if not value:
77 | typ = 'empty'
78 | else:
79 | typ = 'dict'
80 | value.sort()
81 | value = [(repr(key), safe_pformat(val)) for key, val in value]
82 |
83 | # lists
84 | elif isinstance(var, list):
85 | if not var:
86 | typ = 'empty'
87 | else:
88 | typ = 'list'
89 | value = [safe_pformat(item) for item in var]
90 |
91 | # others
92 | else:
93 | typ = 'simple'
94 | value = repr(var)
95 |
96 | return t_vartable.render(type=typ, value=value)
97 |
98 |
99 | def debug_page(context):
100 | tc = context.to_dict()
101 | tc['var_table'] = var_table
102 | tc['code_table'] = code_table
103 | return t_body.render(tc)
104 |
--------------------------------------------------------------------------------
/werkzeug/debug/shared/body.tmpl:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 | $escape(exception_type) in $escape(last_frame['basename']) (Werkzeug Debugger)
6 |
7 |
8 |
9 |
10 |
11 |
12 |
$escape(exception_type)
13 |
$escape(exception_value)
14 |
15 |
16 | $escape(last_frame['filename']) in
17 | $escape(last_frame['function']),
18 | line $last_frame['lineno']
19 |
20 |
21 |
Traceback (toggle raw view)
22 |
23 |
A problem occurred in your Python WSGI application.
24 | Here is the sequence of function calls leading up to the error, in the order
25 | they occurred. Activate a code line to toggle context lines.
26 |
27 | <% for num, frame in enumerate(frames) %>
28 |
29 |
$escape(frame['function']) in $escape(frame['filename'])
18 | In this console you can execute Python expressions in the context of the
19 | application. The initial namespace was created by the debugger automatically.
20 |
35 | The debugger caught an exception in your WSGI application. You can now
36 | look at the traceback which led to the error.
37 | If you enable JavaScript you can also use additional features such as code
38 | execution (if the evalex feature is enabled), automatic pasting of the
39 | exceptions and much more.
40 |
{{ entry.human_date }}
21 |30 | {% for tag in entry.tags %} 31 |-
32 | {{ tag }}
33 |
34 | {% endfor %}
35 |
36 | 37 |