summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Madden <jamadden@gmail.com>2017-11-03 09:44:47 -0500
committerJason Madden <jamadden@gmail.com>2017-11-03 09:44:47 -0500
commit5fda7520e017d2bc85c95f346bb684ed9d7da824 (patch)
tree830277d06121a1d36388dd260c3e32880c807a21
parent8bf7ba6ec1124201ecb2852b3623baaeca58c221 (diff)
downloadzope-tales-5fda7520e017d2bc85c95f346bb684ed9d7da824.tar.gz
Documentation for RTD.
-rw-r--r--.gitignore1
-rw-r--r--CHANGES.rst2
-rw-r--r--MANIFEST.in5
-rw-r--r--README.rst24
-rw-r--r--doc-requirements.txt1
-rw-r--r--docs/changelog.rst1
-rw-r--r--docs/compiler.rst12
-rw-r--r--docs/conf.py280
-rw-r--r--docs/engine.rst17
-rw-r--r--docs/expressions.rst7
-rw-r--r--docs/index.rst26
-rw-r--r--docs/interfaces.rst5
-rw-r--r--docs/other.rst5
-rw-r--r--setup.py10
-rw-r--r--src/zope/tales/engine.py26
-rw-r--r--src/zope/tales/expressions.py55
-rw-r--r--src/zope/tales/interfaces.py26
-rw-r--r--src/zope/tales/pythonexpr.py9
-rw-r--r--src/zope/tales/tales.py108
-rw-r--r--tox.ini11
20 files changed, 573 insertions, 58 deletions
diff --git a/.gitignore b/.gitignore
index f323719..605e07a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,3 +12,4 @@ develop-eggs
parts
.coverage
htmlcov/
+docs/_build/
diff --git a/CHANGES.rst b/CHANGES.rst
index a304996..7e55b33 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -5,7 +5,7 @@
4.2.1 (unreleased)
==================
-- Nothing changed yet.
+- Host documentation at https://zopetales.readthedocs.io
4.2.0 (2017-09-22)
diff --git a/MANIFEST.in b/MANIFEST.in
index f8ca167..7b9f311 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -8,4 +8,9 @@ include .coveragerc
recursive-include src *
+recursive-include docs *.rst
+recursive-include docs *.py
+recursive-include docs Makefile
+recursive-include docs make.bat
+
global-exclude *.pyc
diff --git a/README.rst b/README.rst
index 2344718..522949d 100644
--- a/README.rst
+++ b/README.rst
@@ -1,6 +1,6 @@
-================
- ``zope.tales``
-================
+============
+ zope.tales
+============
.. image:: https://img.shields.io/pypi/v/zope.tales.svg
:target: https://pypi.python.org/pypi/zope.tales/
@@ -16,9 +16,19 @@
.. image:: https://coveralls.io/repos/github/zopefoundation/zope.tales/badge.svg?branch=master
:target: https://coveralls.io/github/zopefoundation/zope.tales?branch=master
-Template Attribute Language - Expression Syntax
+.. image:: https://readthedocs.org/projects/zopetales/badge/?version=latest
+ :target: https://zopetales.readthedocs.io/en/latest/
+ :alt: Documentation Status
-See
-* http://web.archive.org/web/20120814103624/http://wiki.zope.org:80/ZPT/TALESSpecification13
-* https://docs.zope.org/zope2/zope2book/AppendixC.html#tales-overview
+``zope.tales`` (Template Attribute Language - Expression Syntax) is an
+expression language designed to work with `zope.tal
+<https://zopetal.readthedocs.io>`_ (although it can be used
+independently). The two are integrated to produce page templates in
+`zope.pagetemplate <https://zopepagetemplate.readthedocs.io/>`_.
+
+The specification for TAL and TALES can be found at
+http://docs.zope.org/zope2/zope2book/AppendixC.html
+
+Documentation on this implementation and its API can be found at
+https://zopetales.readthedocs.io/
diff --git a/doc-requirements.txt b/doc-requirements.txt
new file mode 100644
index 0000000..e9704b8
--- /dev/null
+++ b/doc-requirements.txt
@@ -0,0 +1 @@
+.[docs]
diff --git a/docs/changelog.rst b/docs/changelog.rst
new file mode 100644
index 0000000..d9e113e
--- /dev/null
+++ b/docs/changelog.rst
@@ -0,0 +1 @@
+.. include:: ../CHANGES.rst
diff --git a/docs/compiler.rst b/docs/compiler.rst
new file mode 100644
index 0000000..a04a3b4
--- /dev/null
+++ b/docs/compiler.rst
@@ -0,0 +1,12 @@
+=====================
+ Expression Compiler
+=====================
+
+.. autoclass:: zope.tales.tales.ExpressionEngine
+
+.. autofunction:: zope.tales.engine.DefaultEngine
+
+.. data:: zope.tales.engine.Engine
+
+ An instance of the default engine (:func:`DefaultEngine`) that can
+ be used for simple shared cases
diff --git a/docs/conf.py b/docs/conf.py
new file mode 100644
index 0000000..63b8d4f
--- /dev/null
+++ b/docs/conf.py
@@ -0,0 +1,280 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# zope.tales documentation build configuration file, created by
+# sphinx-quickstart on Thu Jan 29 11:31:12 2015.
+#
+# This file is execfile()d with the current directory set to its
+# containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys
+import os
+import pkg_resources
+sys.path.append(os.path.abspath('../src'))
+rqmt = pkg_resources.require('zope.tales')[0]
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+
+# -- General configuration ------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = [
+ 'sphinx.ext.autodoc',
+ 'sphinx.ext.doctest',
+ 'sphinx.ext.intersphinx',
+ 'sphinx.ext.viewcode',
+ 'repoze.sphinx.autointerface',
+]
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = 'zope.tales'
+copyright = '2015-2017, Zope Foundation and Contributors'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '%s.%s' % tuple(map(int, rqmt.version.split('.')[:2]))
+# The full version, including alpha/beta/rc tags.
+release = rqmt.version
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['_build']
+
+# The reST default role (used for this markup: `text`) to use for all
+# documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+# If true, keep warnings as "system message" paragraphs in the built documents.
+#keep_warnings = False
+
+
+# -- Options for HTML output ----------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+html_theme = 'default'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+#html_static_path = ['_static']
+
+# Add any extra paths that contain custom files (such as robots.txt or
+# .htaccess) here, relative to this directory. These files are copied
+# directly to the root of the documentation.
+#html_extra_path = []
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'zopetalesdoc'
+
+
+# -- Options for LaTeX output ---------------------------------------------
+
+latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+#'papersize': 'letterpaper',
+
+# The font size ('10pt', '11pt' or '12pt').
+#'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+#'preamble': '',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title,
+# author, documentclass [howto, manual, or own class]).
+latex_documents = [
+ ('index', 'zopetales.tex', 'zope.tales Documentation',
+ 'Zope Foundation and Contributors', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output ---------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ ('index', 'zopetales', 'zope.tales Documentation',
+ ['Zope Foundation and Contributors'], 1)
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+
+# -- Options for Texinfo output -------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+# dir menu entry, description, category)
+texinfo_documents = [
+ ('index', 'zopetales', 'zope.tales Documentation',
+ 'Zope Foundation and Contributors', 'zopetales', 'One line description of project.',
+ 'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+#texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
+
+# If true, do not generate a @detailmenu in the "Top" node's menu.
+#texinfo_no_detailmenu = False
+
+
+# Example configuration for intersphinx: refer to the Python standard library.
+intersphinx_mapping = {
+ 'https://docs.python.org/': None,
+ 'https://zopetal.readthedocs.io/en/latest/': None,
+ 'https://zopepagetemplate.readthedocs.io/en/latest/': None,
+}
+
+autodoc_default_flags = ['members', 'show-inheritance']
+autoclass_content = 'both'
+autodoc_member_order = 'bysource'
diff --git a/docs/engine.rst b/docs/engine.rst
new file mode 100644
index 0000000..f3c95fd
--- /dev/null
+++ b/docs/engine.rst
@@ -0,0 +1,17 @@
+===================
+ Expression Engine
+===================
+
+.. currentmodule:: zope.tales.tales
+
+.. autoclass:: Context
+
+Exceptions
+==========
+
+A number of exceptions are defined.
+
+.. autoclass:: TALESError
+.. autoclass:: Undefined
+.. autoclass:: CompilerError
+.. autoclass:: RegistrationError
diff --git a/docs/expressions.rst b/docs/expressions.rst
new file mode 100644
index 0000000..4281468
--- /dev/null
+++ b/docs/expressions.rst
@@ -0,0 +1,7 @@
+============================
+ Expression Implementations
+============================
+
+.. automodule:: zope.tales.expressions
+
+.. autoclass:: zope.tales.pythonexpr.PythonExpr
diff --git a/docs/index.rst b/docs/index.rst
new file mode 100644
index 0000000..6ed5495
--- /dev/null
+++ b/docs/index.rst
@@ -0,0 +1,26 @@
+.. include:: ../README.rst
+
+
+API Documentation:
+
+.. toctree::
+ :maxdepth: 2
+
+ interfaces
+ expressions
+ compiler
+ engine
+ other
+
+.. toctree::
+ :maxdepth: 1
+
+ changelog
+
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
diff --git a/docs/interfaces.rst b/docs/interfaces.rst
new file mode 100644
index 0000000..8411977
--- /dev/null
+++ b/docs/interfaces.rst
@@ -0,0 +1,5 @@
+============
+ Interfaces
+============
+
+.. automodule:: zope.tales.interfaces
diff --git a/docs/other.rst b/docs/other.rst
new file mode 100644
index 0000000..98bbd29
--- /dev/null
+++ b/docs/other.rst
@@ -0,0 +1,5 @@
+===============
+ Other Objects
+===============
+
+.. autoclass:: zope.tales.tales.Iterator
diff --git a/setup.py b/setup.py
index e1077bf..790bc09 100644
--- a/setup.py
+++ b/setup.py
@@ -60,8 +60,9 @@ setup(name='zope.tales',
'Natural Language :: English',
'Operating System :: OS Independent',
'Topic :: Internet :: WWW/HTTP',
- 'Framework :: Zope3'],
- url='http://github.com/zopefoundation/zope.tales',
+ 'Framework :: Zope3',
+ ],
+ url='https://github.com/zopefoundation/zope.tales',
license='ZPL 2.1',
packages=find_packages('src'),
package_dir={'': 'src'},
@@ -71,6 +72,11 @@ setup(name='zope.tales',
'tal': [
'zope.tal',
],
+ 'docs': [
+ 'Sphinx',
+ 'repoze.sphinx.autointerface',
+ 'zope.tal',
+ ],
},
install_requires=[
'setuptools',
diff --git a/src/zope/tales/engine.py b/src/zope/tales/engine.py
index 14cfecc..7bab8f2 100644
--- a/src/zope/tales/engine.py
+++ b/src/zope/tales/engine.py
@@ -24,7 +24,29 @@ from zope.tales.expressions import LazyExpr
from zope.tales.expressions import SimpleModuleImporter
from zope.tales.pythonexpr import PythonExpr
-def Engine():
+def DefaultEngine():
+ """
+ Create and return an instance of :class:`~.ExpressionEngine` (an
+ implementation of
+ :class:`zope.tal.interfaces.ITALExpressionCompiler`) with the
+ following expression types registered:
+
+ ``string``
+ :class:`.StringExpr`
+ ``python``
+ :class:`.PythonExpr`
+ ``not``
+ :class:`.NotExpr`
+ ``defer``
+ :class:`.DeferExpr`
+ ``lazy``
+ :class:`.LazyExpr`
+ ``modules``
+ :class:`.SimpleModuleImporter`
+
+ In addition, the default ``path`` expressions (``standard``, ``path``, ``exists``
+ and ``nocall``), all implemented by :class:`.PathExpr`, are registered.
+ """
e = ExpressionEngine()
reg = e.registerType
for pt in PathExpr._default_type_names:
@@ -37,4 +59,4 @@ def Engine():
e.registerBaseName('modules', SimpleModuleImporter())
return e
-Engine = Engine()
+Engine = DefaultEngine()
diff --git a/src/zope/tales/expressions.py b/src/zope/tales/expressions.py
index 6203cc7..48be495 100644
--- a/src/zope/tales/expressions.py
+++ b/src/zope/tales/expressions.py
@@ -11,13 +11,22 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
-"""Basic Page Template expression types.
+"""
+Basic Page Template expression types.
+
+Expression objects are created by the :class:`.ExpressionEngine`
+(they must have previously been registered with
+:func:`~zope.tales.tales.ExpressionEngine.registerType`). The expression object itself
+is a callable object taking one argument, *econtext*, which is the local
+expression namespace.
+
"""
import re
-import six
import sys
import types
+import six
+
from zope.interface import implementer
from zope.tales.tales import _valid_name, _parse_expr, NAME_RE, Undefined
from zope.tales.interfaces import ITALESExpression, ITALESFunctionNamespace
@@ -46,6 +55,9 @@ def simpleTraverse(object, path_items, econtext):
class SubPathExpr(object):
+ """
+ Implementation of a single path expression.
+ """
def __init__(self, path, traverser, engine):
self._traverser = traverser
@@ -144,7 +156,10 @@ class SubPathExpr(object):
@implementer(ITALESExpression)
class PathExpr(object):
- """One or more subpath expressions, separated by '|'."""
+ """
+ One or more :class:`subpath expressions <SubPathExpr>`, separated
+ by ``|``.
+ """
# _default_type_names contains the expression type names this
# class is usually registered for.
@@ -162,8 +177,8 @@ class PathExpr(object):
paths = expr.split('|')
self._subexprs = []
add = self._subexprs.append
- for i in range(len(paths)):
- path = paths[i].lstrip()
+ for i, path in enumerate(paths):
+ path = path.lstrip()
if _parse_expr(path):
# This part is the start of another expression type,
# so glue it back together and compile it.
@@ -232,6 +247,12 @@ _interp = re.compile(
@implementer(ITALESExpression)
class StringExpr(object):
+ """
+ An expression that produces a string.
+
+ Sub-sequences of the string that begin with ``$`` are
+ interpreted as path expressions to evaluate.
+ """
def __init__(self, name, expr, engine):
self._s = expr
@@ -275,6 +296,10 @@ class StringExpr(object):
@implementer(ITALESExpression)
class NotExpr(object):
+ """
+ An expression that negates the boolean value
+ of its sub-expression.
+ """
def __init__(self, name, expr, engine):
self._s = expr = expr.lstrip()
@@ -301,6 +326,19 @@ class DeferWrapper(object):
@implementer(ITALESExpression)
class DeferExpr(object):
+ """
+ An expression that will defer evaluation of the sub-expression
+ until necessary, preserving the execution context it was created
+ with.
+
+ This is useful in ``tal:define`` expressions::
+
+ <div tal:define="thing defer:some/path">
+ ...
+ <!-- some/path is only evaluated if condition is true -->
+ <span tal:condition="condition" tal:content="thing"/>
+ </div>
+ """
def __init__(self, name, expr, compiler):
self._s = expr = expr.lstrip()
@@ -328,7 +366,12 @@ class LazyWrapper(DeferWrapper):
return r
class LazyExpr(DeferExpr):
- """lazy: expression handler for lazy initialization of expressions
+ """
+ An expression that will defer evaluation of its
+ sub-expression until the first time it is necessary.
+
+ This is like :class:`DeferExpr`, but caches the result of
+ evaluating the expression.
"""
def __call__(self, econtext):
return LazyWrapper(self._c, econtext)
diff --git a/src/zope/tales/interfaces.py b/src/zope/tales/interfaces.py
index cefae98..158b794 100644
--- a/src/zope/tales/interfaces.py
+++ b/src/zope/tales/interfaces.py
@@ -11,7 +11,8 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
-"""Interface that describes the 'macros' attribute of a PageTemplate.
+"""
+Interface that describes the TALES implementation.
"""
from zope.interface import Interface
@@ -36,25 +37,28 @@ class ITALESExpression(Interface):
"""TALES expression
These are expression handlers that handle a specific type of
- expression in TALES, e.g. path or string expression.
+ expression in TALES, e.g. ``path`` or ``string`` expression.
"""
def __call__(econtext):
- """Evaluate expression according to the given execution
- context 'econtext' and return computed value.
+ """
+ Evaluate expression according to the given execution context
+ *econtext* and return computed value.
"""
class ITALESIterator(ITALIterator):
- """TAL Iterator provided by TALES
+ """TAL Iterator provided by TALES.
- Values of this iterator are assigned to items in the repeat namespace.
+ Values of this iterator are assigned to items in the ``repeat``
+ namespace.
- For example, with a TAL statement like: tal:repeat="item items",
- an iterator will be assigned to "repeat/item". The iterator
- provides a number of handy methods useful in writing TAL loops.
+ For example, with a TAL statement like: ``tal:repeat="item
+ items"``, an iterator will be assigned to ``repeat/item`` (using a
+ path expression). The iterator provides a number of handy methods
+ useful in writing TAL loops.
The results are undefined of calling any of the methods except
- 'length' before the first iteration.
+ ``length`` before the first iteration.
"""
def index():
@@ -66,7 +70,7 @@ class ITALESIterator(ITALIterator):
"""
def even():
- """Return whether the current position is even
+ """Return whether the current position is even.
"""
def odd():
diff --git a/src/zope/tales/pythonexpr.py b/src/zope/tales/pythonexpr.py
index ffa5c84..3f47bed 100644
--- a/src/zope/tales/pythonexpr.py
+++ b/src/zope/tales/pythonexpr.py
@@ -15,7 +15,16 @@
"""
class PythonExpr(object):
+ """
+ Evaluates a python expression by calling :func:`eval` after
+ compiling it with :func:`compile`.
+ """
def __init__(self, name, expr, engine):
+ """
+ :param str expr: The Python expression.
+ :param ExpressionEngine engine: The expression compiler that
+ is creating us.
+ """
text = '\n'.join(expr.splitlines()) # normalize line endings
text = '(' + text + ')' # Put text in parens so newlines don't matter
self.text = text
diff --git a/src/zope/tales/tales.py b/src/zope/tales/tales.py
index 1256153..9765fc8 100644
--- a/src/zope/tales/tales.py
+++ b/src/zope/tales/tales.py
@@ -19,9 +19,11 @@ __docformat__ = "reStructuredText"
import re
from zope.interface import implementer
+from zope.interface import Interface
import six
-from zope.interface import Interface
+from zope.tales.interfaces import ITALESIterator
+
class ITALExpressionEngine(Interface):
pass
class ITALExpressionCompiler(Interface):
@@ -37,7 +39,7 @@ try:
except ImportError:
pass
-from zope.tales.interfaces import ITALESIterator
+
NAME_RE = r"[a-zA-Z][a-zA-Z0-9_]*"
_parse_expr = re.compile(r"(%s):" % NAME_RE).match
@@ -61,7 +63,11 @@ _default = object()
@implementer(ITALESIterator)
class Iterator(object):
- """TALES Iterator
+ """
+ TALES Iterator.
+
+ Default implementation of :class:`zope.tales.interfaces.ITALESIterator`.
+
"""
def __init__(self, name, seq, context):
@@ -511,6 +517,7 @@ class Iterator(object):
class ErrorInfo(object):
"""Information about an exception passed to an on-error handler."""
+ # XXX: This is a duplicate of zope.tal.taldefs.ErrorInfo
value = None
def __init__(self, err, position=(None, None)):
@@ -525,13 +532,23 @@ class ErrorInfo(object):
@implementer(ITALExpressionCompiler)
class ExpressionEngine(object):
- '''Expression Engine
-
- An instance of this class keeps a mutable collection of expression
- type handlers. It can compile expression strings by delegating to
- these handlers. It can provide an expression Context, which is
- capable of holding state and evaluating compiled expressions.
- '''
+ """
+ Expression compiler, an implementation of
+ :class:`zope.tal.interfaces.ITALExpressionCompiler`.
+
+ An instance of this class keeps :meth:`a mutable collection of
+ expression type handlers
+ <zope.tales.tales.ExpressionEngine.registerType>`. It can compile
+ expression strings by delegating to these handlers. It can
+ :meth:`provide an expression engine
+ <zope.tales.tales.ExpressionEngine.getContext>`, which is capable
+ of holding state and evaluating compiled expressions.
+
+ By default, this object does not know how to compile any
+ expression types. See :data:`zope.tales.engine.Engine` and
+ :func:`zope.tales.engine.DefaultEngine` for pre-configured
+ instances supporting the standard expression types.
+ """
def __init__(self):
self.types = {}
@@ -540,23 +557,24 @@ class ExpressionEngine(object):
self.iteratorFactory = Iterator
def registerFunctionNamespace(self, namespacename, namespacecallable):
- """Register a function namespace
+ """
+ Register a function namespace
- namespace - a string containing the name of the namespace to
- be registered
+ :param str namespace: a string containing the name of the namespace to
+ be registered
- namespacecallable - a callable object which takes the following
- parameter:
+ :param callable namespacecallable: a callable object which takes the following
+ parameter:
- context - the object on which the functions
- provided by this namespace will
- be called
+ :context: the object on which the functions
+ provided by this namespace will
+ be called
- This callable should return an object which
- can be traversed to get the functions provided
- by the this namespace.
+ This callable should return an object which
+ can be traversed to get the functions provided
+ by the this namespace.
- example:
+ For example::
class stringFuncs(object):
@@ -569,7 +587,7 @@ class ExpressionEngine(object):
def lower(self):
return self.context.lower()
- engine.registerFunctionNamespace('string',stringFuncs)
+ engine.registerFunctionNamespace('string', stringFuncs)
"""
self.namespaces[namespacename] = namespacecallable
@@ -579,6 +597,12 @@ class ExpressionEngine(object):
return self.namespaces[namespacename]
def registerType(self, name, handler):
+ """
+ Register an expression of *name* to be handled with *handler*.
+
+ :raises RegistrationError: If this is a duplicate registration for *name*,
+ or if *name* is not a valid expression type name.
+ """
if not _valid_name(name):
raise RegistrationError('Invalid expression type name "%s".' % name)
types = self.types
@@ -617,6 +641,16 @@ class ExpressionEngine(object):
return handler(type, expr, self)
def getContext(self, contexts=None, **kwcontexts):
+ """
+ Return a new expression engine.
+
+ The keyword arguments passed in *kwcantexts* become the default
+ variable context for the returned engine. If *contexts* is given, it
+ should be a mapping, and the values it contains will override
+ the keyword arguments.
+
+ :rtype: Context
+ """
if contexts is not None:
if kwcontexts:
kwcontexts.update(contexts)
@@ -630,15 +664,24 @@ class ExpressionEngine(object):
@implementer(ITALExpressionEngine)
class Context(object):
- '''Expression Context
+ """
+ Expression engine, an implementation of
+ :class:`zope.tal.interfaces.ITALExpressionEngine`.
- An instance of this class holds context information that it can
- use to evaluate compiled expressions.
- '''
+ This class is called ``Context`` because an instance of this class
+ holds context information (namespaces) that it uses when evaluating compiled
+ expressions.
+ """
position = (None, None)
source_file = None
def __init__(self, engine, contexts):
+ """
+ :param engine: A :class:`ExpressionEngine` (a
+ :class:`zope.tal.interfaces.ITALExpressionCompiler`)
+ :param contexts: A mapping (namespace) of variables that forms the base
+ variable scope.
+ """
self._engine = engine
self.contexts = contexts
self.setContext('nothing', None)
@@ -656,7 +699,7 @@ class Context(object):
self._scope_stack = []
def setContext(self, name, value):
- # Hook to allow subclasses to do things like adding security proxies
+ """Hook to allow subclasses to do things like adding security proxies."""
self.contexts[name] = value
def beginScope(self):
@@ -705,6 +748,12 @@ class Context(object):
return it
def evaluate(self, expression):
+ """
+ Evaluate the *expression* by calling it, passing in this object,
+ and return the raw results.
+
+ If *expression* is a string, it is first compiled.
+ """
if isinstance(expression, str):
expression = self._engine.compile(expression)
__traceback_supplement__ = (
@@ -714,6 +763,9 @@ class Context(object):
evaluateValue = evaluate
def evaluateBoolean(self, expr):
+ """
+ Evaluate the expression and return the boolean value of its result.
+ """
# "not not", while frowned upon by linters might be faster
# than bool() because it avoids a builtin lookup. Plus it can't be
# reassigned.
diff --git a/tox.ini b/tox.ini
index 927f900..3d18895 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,6 +1,6 @@
[tox]
envlist =
- py27,py34,py35,py36,pypy,pypy3,coverage
+ py27,py34,py35,py36,pypy,pypy3,coverage,docs
[testenv]
commands =
@@ -18,3 +18,12 @@ commands =
deps =
{[testenv]deps}
coverage
+
+[testenv:docs]
+basepython =
+ python2.7
+commands =
+ sphinx-build -b html -d docs/_build/doctrees docs docs/_build/html
+deps =
+ {[testenv]deps}
+ .[docs]