From: DongHun Kwak Date: Thu, 14 Jul 2022 04:33:18 +0000 (+0900) Subject: Imported Upstream version 4.6.4 X-Git-Tag: upstream/4.6.4^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e2ba502d3e8762b6ad53f5b19ae899a2007f475d;p=platform%2Fupstream%2Fpython3-lxml.git Imported Upstream version 4.6.4 --- diff --git a/CHANGES.txt b/CHANGES.txt index 22f4d45..a5fae64 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -2,6 +2,19 @@ lxml changelog ============== +4.6.4 (2021-11-01) +================== + +Features added +-------------- + +* GH#317: A new property ``system_url`` was added to DTD entities. + Patch by Thirdegree. + +* GH#314: The ``STATIC_*`` variables in ``setup.py`` can now be passed via env vars. + Patch by Isaac Jurado. + + 4.6.3 (2021-03-21) ================== diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..a76d0ed --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,29 @@ +Copyright (c) 2004 Infrae. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + 3. Neither the name of Infrae nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INFRAE OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Makefile b/Makefile index a8c9de8..555d851 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ PYTHON3?=python3 TESTFLAGS=-p -v TESTOPTS= SETUPFLAGS= -LXMLVERSION:=$(shell sed -ne '/__version__/s|.*__version__\s*=\s*"\([^"]*\)".*|\1|p' src/lxml/__init__.py) +LXMLVERSION:=$(shell $(PYTHON3) -c 'import re; print(re.findall(r"__version__\s*=\s*\"([^\"]+)\"", open("src/lxml/__init__.py").read())[0])' ) PARALLEL?=$(shell $(PYTHON) -c 'import sys; print("-j7" if sys.version_info >= (3, 5) else "")' ) PARALLEL3?=$(shell $(PYTHON3) -c 'import sys; print("-j7" if sys.version_info >= (3, 5) else "")' ) @@ -12,17 +12,21 @@ PY3_WITH_CYTHON?=$(shell $(PYTHON3) -c 'import Cython.Build.Dependencies' >/dev/ CYTHON_WITH_COVERAGE?=$(shell $(PYTHON) -c 'import Cython.Coverage; import sys; assert not hasattr(sys, "pypy_version_info")' >/dev/null 2>/dev/null && echo " --coverage" || true) CYTHON3_WITH_COVERAGE?=$(shell $(PYTHON3) -c 'import Cython.Coverage; import sys; assert not hasattr(sys, "pypy_version_info")' >/dev/null 2>/dev/null && echo " --coverage" || true) +PYTHON_BUILD_VERSION ?= * MANYLINUX_LIBXML2_VERSION=2.9.10 MANYLINUX_LIBXSLT_VERSION=1.1.34 MANYLINUX_CFLAGS=-O3 -g1 -pipe -fPIC -flto MANYLINUX_LDFLAGS=-flto -MANYLINUX_IMAGE_X86_64=quay.io/pypa/manylinux1_x86_64 -MANYLINUX_IMAGE_686=quay.io/pypa/manylinux1_i686 -MANYLINUX_IMAGE_AARCH64=quay.io/pypa/manylinux2014_aarch64 -AARCH64_ENV=-e AR="/opt/rh/devtoolset-9/root/usr/bin/gcc-ar" \ - -e NM="/opt/rh/devtoolset-9/root/usr/bin/gcc-nm" \ - -e RANLIB="/opt/rh/devtoolset-9/root/usr/bin/gcc-ranlib" +MANYLINUX_IMAGES= \ + manylinux1_x86_64 \ + manylinux1_i686 \ + manylinux_2_24_x86_64 \ + manylinux_2_24_i686 \ + manylinux_2_24_aarch64 \ + manylinux_2_24_ppc64le \ + manylinux_2_24_s390x \ + musllinux_1_1_x86_64 .PHONY: all inplace inplace3 rebuild-sdist sdist build require-cython wheel_manylinux wheel @@ -55,19 +59,22 @@ require-cython: qemu-user-static: docker run --rm --privileged multiarch/qemu-user-static --reset -p yes -wheel_manylinux: wheel_manylinux64 wheel_manylinux32 wheel_manylinuxaarch64 -wheel_manylinuxaarch64: qemu-user-static +wheel_manylinux: $(addprefix wheel_,$(MANYLINUX_IMAGES)) +$(addprefix wheel_,$(filter-out %_x86_64, $(filter-out %_i686, $(MANYLINUX_IMAGES)))): qemu-user-static -wheel_manylinux32 wheel_manylinux64 wheel_manylinuxaarch64: dist/lxml-$(LXMLVERSION).tar.gz +wheel_%: dist/lxml-$(LXMLVERSION).tar.gz time docker run --rm -t \ -v $(shell pwd):/io \ - $(if $(patsubst %aarch64,,$@),,$(AARCH64_ENV)) \ + -e AR=gcc-ar \ + -e NM=gcc-nm \ + -e RANLIB=gcc-ranlib \ -e CFLAGS="$(MANYLINUX_CFLAGS) $(if $(patsubst %aarch64,,$@),-march=core2,-march=armv8-a -mtune=cortex-a72)" \ -e LDFLAGS="$(MANYLINUX_LDFLAGS)" \ -e LIBXML2_VERSION="$(MANYLINUX_LIBXML2_VERSION)" \ -e LIBXSLT_VERSION="$(MANYLINUX_LIBXSLT_VERSION)" \ - -e WHEELHOUSE=wheelhouse_$(subst wheel_,,$@) \ - $(if $(filter $@,wheel_manylinuxaarch64),$(MANYLINUX_IMAGE_AARCH64),$(if $(patsubst %32,,$@),$(MANYLINUX_IMAGE_X86_64),$(MANYLINUX_IMAGE_686))) \ + -e PYTHON_BUILD_VERSION="$(PYTHON_BUILD_VERSION)" \ + -e WHEELHOUSE=$(subst wheel_,wheelhouse/,$@) \ + quay.io/pypa/$(subst wheel_,,$@) \ bash /io/tools/manylinux/build-wheels.sh /io/$< wheel: @@ -89,6 +96,15 @@ valgrind_test_inplace: inplace valgrind --tool=memcheck --leak-check=full --num-callers=30 --suppressions=valgrind-python.supp \ $(PYTHON) test.py +fuzz: clean + $(MAKE) \ + CC="/usr/bin/clang" \ + CFLAGS="$$CFLAGS -fsanitize=fuzzer-no-link -g2" \ + CXX="/usr/bin/clang++" \ + CXXFLAGS="-fsanitize=fuzzer-no-link" \ + inplace3 + $(PYTHON3) src/lxml/tests/fuzz_xml_parse.py + gdb_test_inplace: inplace @echo "file $(PYTHON)\nrun test.py" > .gdb.command gdb -x .gdb.command -d src -d src/lxml diff --git a/PKG-INFO b/PKG-INFO index 6eceeea..8053216 100644 --- a/PKG-INFO +++ b/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: lxml -Version: 4.6.3 +Version: 4.6.4 Summary: Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API. Home-page: https://lxml.de/ Author: lxml dev team @@ -8,48 +8,6 @@ Author-email: lxml-dev@lxml.de Maintainer: lxml dev team Maintainer-email: lxml-dev@lxml.de License: BSD -Description: lxml is a Pythonic, mature binding for the libxml2 and libxslt libraries. It - provides safe and convenient access to these libraries using the ElementTree - API. - - It extends the ElementTree API significantly to offer support for XPath, - RelaxNG, XML Schema, XSLT, C14N and much more. - - To contact the project, go to the `project home page - `_ or see our bug tracker at - https://launchpad.net/lxml - - In case you want to use the current in-development version of lxml, - you can get it from the github repository at - https://github.com/lxml/lxml . Note that this requires Cython to - build the sources, see the build instructions on the project home - page. To the same end, running ``easy_install lxml==dev`` will - install lxml from - https://github.com/lxml/lxml/tarball/master#egg=lxml-dev if you have - an appropriate version of Cython installed. - - - After an official release of a new stable series, bug fixes may become - available at - https://github.com/lxml/lxml/tree/lxml-4.6 . - Running ``easy_install lxml==4.6bugfix`` will install - the unreleased branch state from - https://github.com/lxml/lxml/tarball/lxml-4.6#egg=lxml-4.6bugfix - as soon as a maintenance branch has been established. Note that this - requires Cython to be installed at an appropriate version for the build. - - 4.6.3 (2021-03-21) - ================== - - Bugs fixed - ---------- - - * A vulnerability (CVE-2021-28957) was discovered in the HTML Cleaner by Kevin Chung, - which allowed JavaScript to pass through. The cleaner now removes the HTML5 - ``formaction`` attribute. - - - Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers @@ -64,13 +22,62 @@ Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: C Classifier: Operating System :: OS Independent Classifier: Topic :: Text Processing :: Markup :: HTML Classifier: Topic :: Text Processing :: Markup :: XML Classifier: Topic :: Software Development :: Libraries :: Python Modules Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.* +Provides-Extra: source Provides-Extra: cssselect Provides-Extra: html5 Provides-Extra: htmlsoup -Provides-Extra: source +License-File: LICENSE.txt +License-File: LICENSES.txt + +lxml is a Pythonic, mature binding for the libxml2 and libxslt libraries. It +provides safe and convenient access to these libraries using the ElementTree +API. + +It extends the ElementTree API significantly to offer support for XPath, +RelaxNG, XML Schema, XSLT, C14N and much more. + +To contact the project, go to the `project home page +`_ or see our bug tracker at +https://launchpad.net/lxml + +In case you want to use the current in-development version of lxml, +you can get it from the github repository at +https://github.com/lxml/lxml . Note that this requires Cython to +build the sources, see the build instructions on the project home +page. To the same end, running ``easy_install lxml==dev`` will +install lxml from +https://github.com/lxml/lxml/tarball/master#egg=lxml-dev if you have +an appropriate version of Cython installed. + + +After an official release of a new stable series, bug fixes may become +available at +https://github.com/lxml/lxml/tree/lxml-4.6 . +Running ``easy_install lxml==4.6bugfix`` will install +the unreleased branch state from +https://github.com/lxml/lxml/tarball/lxml-4.6#egg=lxml-4.6bugfix +as soon as a maintenance branch has been established. Note that this +requires Cython to be installed at an appropriate version for the build. + +4.6.4 (2021-11-01) +================== + +Features added +-------------- + +* GH#317: A new property ``system_url`` was added to DTD entities. + Patch by Thirdegree. + +* GH#314: The ``STATIC_*`` variables in ``setup.py`` can now be passed via env vars. + Patch by Isaac Jurado. + + + + diff --git a/README.rst b/README.rst index 3ad1ba1..01962c3 100644 --- a/README.rst +++ b/README.rst @@ -50,6 +50,11 @@ for other ways to support the lxml project, as well as commercial consulting, customisations and trainings on lxml and fast Python XML processing. +Note that we are not accepting donations in crypto currencies. +Much of the development and hosting for lxml is done in a carbon-neutral way +or with compensated and very low emissions. +Crypto currencies do not fit into that ambition. + .. |Donate| image:: https://lxml.de/paypal_btn_donateCC_LG.png :width: 160 :height: 47 @@ -69,6 +74,12 @@ Another supporter of the lxml project is Project income report --------------------- +* Total project income in 2020: EUR 6065,86 (506.49 € / month) + + - Tidelift: EUR 4064.77 + - Paypal: EUR 1401.09 + - other: EUR 600.00 + * Total project income in 2019: EUR 717.52 (59.79 € / month) - Tidelift: EUR 360.30 diff --git a/benchmark/bench_etree.py b/benchmark/bench_etree.py index 0f66db8..69ac520 100644 --- a/benchmark/bench_etree.py +++ b/benchmark/bench_etree.py @@ -1,9 +1,10 @@ import copy +from io import BytesIO from itertools import * import benchbase from benchbase import (with_attributes, with_text, onlylib, - serialized, children, nochange, BytesIO) + serialized, children, nochange) TEXT = "some ASCII text" UTEXT = u"some klingon: \F8D2" diff --git a/benchmark/benchbase.py b/benchmark/benchbase.py index e34e610..a9f9ad8 100644 --- a/benchmark/benchbase.py +++ b/benchmark/benchbase.py @@ -1,4 +1,4 @@ -import sys, re, string, time, copy, gc +import sys, re, string, copy, gc from itertools import * import time @@ -474,6 +474,8 @@ def main(benchmark_class): if import_lxml: from lxml import etree _etrees.append(etree) + print("Using lxml %s (with libxml2 %s)" % ( + etree.__version__, '.'.join(map(str, etree.LIBXML_VERSION)))) try: sys.argv.remove('-fel') @@ -521,6 +523,8 @@ def main(benchmark_class): print("No library to test. Exiting.") sys.exit(1) + print("Running benchmarks in Python %s" % (sys.version_info,)) + print("Preparing test suites and trees ...") selected = set( sys.argv[1:] ) benchmark_suites, benchmarks = \ diff --git a/buildlibxml.py b/buildlibxml.py index f45c860..086d911 100644 --- a/buildlibxml.py +++ b/buildlibxml.py @@ -1,4 +1,4 @@ -import os, re, sys, subprocess +import os, re, sys, subprocess, platform import tarfile from distutils import log, version from contextlib import closing @@ -38,7 +38,13 @@ def download_and_extract_windows_binaries(destdir): if release_path in filename ] - arch = "win64" if sys.maxsize > 2**32 else "win32" + if platform.machine() == 'ARM64': + arch = "win-arm64" + elif sys.maxsize > 2**32: + arch = "win64" + else: + arch = "win32" + if sys.version_info < (3, 5): arch = 'vs2008.' + arch @@ -437,6 +443,15 @@ def build_libxml2xslt(download_dir, build_dir, if not has_current_lib("libxml2", libxml2_dir): cmmi(libxml2_configure_cmd, libxml2_dir, multicore, **call_setup) + # Fix up libxslt configure script (needed up to and including 1.1.34) + # https://gitlab.gnome.org/GNOME/libxslt/-/commit/90c34c8bb90e095a8a8fe8b2ce368bd9ff1837cc + with open(os.path.join(libxslt_dir, "configure"), 'rb') as f: + config_script = f.read() + if b' --libs print ' in config_script: + config_script = config_script.replace(b' --libs print ', b' --libs ') + with open(os.path.join(libxslt_dir, "configure"), 'wb') as f: + f.write(config_script) + # build libxslt libxslt_configure_cmd = configure_cmd + [ '--without-python', diff --git a/doc/FAQ.txt b/doc/FAQ.txt index 24ec8c4..48f69a6 100644 --- a/doc/FAQ.txt +++ b/doc/FAQ.txt @@ -117,11 +117,11 @@ wrote a nice article about high-performance aspects when `parsing large files with lxml`_. .. _`lxml.etree Tutorial`: tutorial.html -.. _`tutorial for ElementTree`: https://effbot.org/zone/element.htm +.. _`tutorial for ElementTree`: https://web.archive.org/web/20200720191942/https://effbot.org/zone/element.htm .. _`extended etree API`: api.html .. _`objectify documentation`: objectify.html -.. _`Python XML processing with lxml`: http://www.nmt.edu/tcc/help/pubs/pylxml/ -.. _`element library`: https://effbot.org/zone/element-lib.htm +.. _`Python XML processing with lxml`: https://web.archive.org/web/20190522191656/http://infohost.nmt.edu/tcc/help/pubs/pylxml/web/index.html +.. _`element library`: https://web.archive.org/web/20200703234431/http://www.effbot.org/zone/element-lib.htm .. _`parsing large files with lxml`: http://www.ibm.com/developerworks/xml/library/x-hiperfparse/ @@ -143,7 +143,7 @@ web page`_. The `generated API documentation`_ is a comprehensive API reference for the lxml package. -.. _`ElementTree API`: https://effbot.org/zone/element-index.htm +.. _`ElementTree API`: https://web.archive.org/web/20200703191710/http://www.effbot.org/zone/element-index.htm .. _`the web page`: https://lxml.de/#documentation .. _`generated API documentation`: api/index.html @@ -1239,8 +1239,8 @@ Element. Its children will then inherit this prefix for serialization. How can I specify a default namespace for XPath expressions? ------------------------------------------------------------ -You can't. In XPath, there is no such thing as a default namespace. Just use -an arbitrary prefix and let the namespace dictionary of the XPath evaluators +You can't. In XPath 1.0, there is no such thing as a default namespace. Just +use an arbitrary prefix and let the namespace dictionary of the XPath evaluators map it to your namespace. See also the question above. diff --git a/doc/capi.txt b/doc/capi.txt index 0167a5a..0471d81 100644 --- a/doc/capi.txt +++ b/doc/capi.txt @@ -7,11 +7,10 @@ C extensions to efficiently access public functions and classes of lxml, without going through the Python API. The API is described in the file `etreepublic.pxd`_, which is directly -c-importable by extension modules implemented in Pyrex_ or Cython_. +c-importable by extension modules implemented in Cython_. .. _`etreepublic.pxd`: https://github.com/lxml/lxml/blob/master/src/lxml/includes/etreepublic.pxd -.. _Cython: http://cython.org -.. _Pyrex: http://www.cosc.canterbury.ac.nz/~greg/python/Pyrex/ +.. _Cython: https://cython.org .. contents:: .. @@ -45,7 +44,7 @@ Writing external modules in Cython ---------------------------------- This is the easiest way of extending lxml at the C level. A Cython_ -(or Pyrex_) module should start like this:: +module should start like this:: # My Cython extension diff --git a/doc/compatibility.txt b/doc/compatibility.txt index e23d181..654cb7c 100644 --- a/doc/compatibility.txt +++ b/doc/compatibility.txt @@ -146,11 +146,11 @@ ElementTree. Nonetheless, some differences and incompatibilities exist: not. This means that a comment text "text" that ElementTree serializes as "" will become "" in lxml. -* When the string '*' is used as tag filter in the ``Element.getiterator()`` - method, ElementTree returns all elements in the tree, including comments and - processing instructions. lxml.etree only returns real Elements, i.e. tree - nodes that have a string tag name. Without a filter, both libraries iterate - over all nodes. +* When the string ``'*'`` is used as tag filter in the ``Element.iter()`` and + ``.find*()`` methods, ElementTree returns all elements in the tree, including + comments and processing instructions. lxml.etree only returns real Elements, + i.e. tree nodes that have a string tag name. Without a filter, both libraries + iterate over all nodes. Note that currently only lxml.etree supports passing the ``Element`` factory function as filter to select only Elements. Both libraries support passing diff --git a/doc/html/FAQ.html b/doc/html/FAQ.html index b96af6f..6a3cb6b 100644 --- a/doc/html/FAQ.html +++ b/doc/html/FAQ.html @@ -2,7 +2,7 @@ - + lxml FAQ - Frequently Asked Questions @@ -26,7 +26,7 @@ function hide_menu() {
-

lxml FAQ - Frequently Asked Questions

+

lxml FAQ - Frequently Asked Questions

Frequently asked questions on lxml. See also the notes on compatibility to ElementTree.

@@ -108,13 +108,13 @@ function hide_menu() { (just as any good documentation), it provides an overview of the most important concepts in lxml.etree. If you want to help out, improving the tutorial is a very good place to start.

-

There is also a tutorial for ElementTree which works for +

There is also a tutorial for ElementTree which works for lxml.etree. The documentation of the extended etree API also -contains many examples for lxml.etree. Fredrik Lundh's element +contains many examples for lxml.etree. Fredrik Lundh's element library contains a lot of nice recipes that show how to solve common tasks in ElementTree and lxml.etree. To learn using lxml.objectify, read the objectify documentation.

-

John Shipman has written another tutorial called Python XML +

John Shipman has written another tutorial called Python XML processing with lxml that contains lots of examples. Liza Daly wrote a nice article about high-performance aspects when parsing large files with lxml.

@@ -123,8 +123,8 @@ large files with lxml.

Where can I find more documentation about lxml?

There is a lot of documentation on the web and also in the Python standard library documentation, as lxml implements the well-known -ElementTree API and tries to follow its documentation as closely as -possible. The recipes in Fredrik Lundh's element library are +ElementTree API and tries to follow its documentation as closely as +possible. The recipes in Fredrik Lundh's element library are generally worth taking a look at. There are a couple of issues where lxml cannot keep up compatibility. They are described in the compatibility documentation.

@@ -272,7 +272,7 @@ also the section on threading
>>> root = etree.XML("<root><tag>text<child/></tag>tail</root>")
->>> print(etree.tostring(root[0]))
+>>> print(etree.tostring(root[0]))
 <tag>text<child/></tag>tail
 

Here is an example that shows why not serialising the tail would be @@ -280,15 +280,15 @@ even more surprising from an object point of view:

>>> root = etree.Element("test")
 
 >>> root.text = "TEXT"
->>> print(etree.tostring(root))
+>>> print(etree.tostring(root))
 <test>TEXT</test>
 
 >>> root.tail = "TAIL"
->>> print(etree.tostring(root))
+>>> print(etree.tostring(root))
 <test>TEXT</test>TAIL
 
->>> root.tail = None
->>> print(etree.tostring(root))
+>>> root.tail = None
+>>> print(etree.tostring(root))
 <test>TEXT</test>
 

Just imagine a Python list where you append an item and it doesn't @@ -534,12 +534,12 @@ versions of libxml2 and libxslt - and make sure they are used.

import sys
 from lxml import etree
 
-print("%-20s: %s" % ('Python',           sys.version_info))
-print("%-20s: %s" % ('lxml.etree',       etree.LXML_VERSION))
-print("%-20s: %s" % ('libxml used',      etree.LIBXML_VERSION))
-print("%-20s: %s" % ('libxml compiled',  etree.LIBXML_COMPILED_VERSION))
-print("%-20s: %s" % ('libxslt used',     etree.LIBXSLT_VERSION))
-print("%-20s: %s" % ('libxslt compiled', etree.LIBXSLT_COMPILED_VERSION))
+print("%-20s: %s" % ('Python',           sys.version_info))
+print("%-20s: %s" % ('lxml.etree',       etree.LXML_VERSION))
+print("%-20s: %s" % ('libxml used',      etree.LIBXML_VERSION))
+print("%-20s: %s" % ('libxml compiled',  etree.LIBXML_COMPILED_VERSION))
+print("%-20s: %s" % ('libxslt used',     etree.LIBXSLT_VERSION))
+print("%-20s: %s" % ('libxslt compiled', etree.LIBXSLT_COMPILED_VERSION))
 

If you can figure that the problem is not in lxml but in the underlying libxml2 or libxslt, you can ask right on the respective @@ -756,7 +756,7 @@ only added between nodes that do not contain data. This is always the case for trees constructed element-by-element, so no problems should be expected here. For parsed trees, a good way to assure that no conflicting whitespace is left in the tree is the remove_blank_text option:

-
>>> parser = etree.XMLParser(remove_blank_text=True)
+
>>> parser = etree.XMLParser(remove_blank_text=True)
 >>> tree = etree.parse(filename, parser)
 

This will allow the parser to drop blank text nodes when constructing the @@ -782,7 +782,7 @@ use either a DTD to tell the parser which whitespace it can safely ignore, or remove the ignorable whitespace manually after parsing, e.g. by setting all tail text to None:

for element in root.iter():
-    element.tail = None
+    element.tail = None
 

Fredrik Lundh also has a Python-level function for indenting XML by appending whitespace to tags. It can be found on his element library @@ -975,7 +975,7 @@ you can apply the following function:

XPath and Document Traversal

What are the findall() and xpath() methods on Element(Tree)?

-

findall() is part of the original ElementTree API. It supports a +

findall() is part of the original ElementTree API. It supports a simple subset of the XPath language, without predicates, conditions and other advanced features. It is very handy for finding specific tags in a tree. Another important difference is namespace handling, which uses the @@ -1014,8 +1014,8 @@ Element. Its children will then inherit this prefix for serialization.

How can I specify a default namespace for XPath expressions?

-

You can't. In XPath, there is no such thing as a default namespace. Just use -an arbitrary prefix and let the namespace dictionary of the XPath evaluators +

You can't. In XPath 1.0, there is no such thing as a default namespace. Just +use an arbitrary prefix and let the namespace dictionary of the XPath evaluators map it to your namespace. See also the question above.

@@ -1050,7 +1050,7 @@ advance beyond the critical point before touching the tree structure.

diff --git a/doc/html/api.html b/doc/html/api.html index c90579f..89254ec 100644 --- a/doc/html/api.html +++ b/doc/html/api.html @@ -2,7 +2,7 @@ - + APIs specific to lxml.etree
-

APIs specific to lxml.etree

+

APIs specific to lxml.etree

lxml.etree tries to follow established APIs wherever possible. Sometimes, however, the need to expose a feature in an easy way led to the invention of a @@ -93,22 +93,22 @@ model. It knows about parents and siblings of elements:

>>> e = etree.SubElement(d, "e") >>> b.getparent() == root True ->>> print(b.getnext().tag) +>>> print(b.getnext().tag) c ->>> print(c.getprevious().tag) +>>> print(c.getprevious().tag) b

Elements always live within a document context in lxml. This implies that there is also a notion of an absolute document root. You can retrieve an ElementTree for the root node of a document from any of its elements.

>>> tree = d.getroottree()
->>> print(tree.getroot().tag)
+>>> print(tree.getroot().tag)
 root
 

Note that this is different from wrapping an Element in an ElementTree. You can use ElementTrees to create XML trees with an explicit root node:

>>> tree = etree.ElementTree(d)
->>> print(tree.getroot().tag)
+>>> print(tree.getroot().tag)
 d
 >>> etree.tostring(tree)
 b'<d><e/></d>'
@@ -120,11 +120,11 @@ will understand the explicitly chosen root as root node of a document.  They
 will not see any elements outside the ElementTree.  However, ElementTrees do
 not modify their Elements:

>>> element = tree.getroot()
->>> print(element.tag)
+>>> print(element.tag)
 d
->>> print(element.getparent().tag)
+>>> print(element.getparent().tag)
 root
->>> print(element.getroottree().getroot().tag)
+>>> print(element.getroottree().getroot().tag)
 root
 

The rule is that all operations that are applied to Elements use either the @@ -149,11 +149,11 @@ iteration over the children, following/preceding siblings, ancestors and descendants of an element, as defined by the respective XPath axis:

>>> [ child.tag for child in root.iterchildren() ]
 ['a', 'b', 'c', 'd']
->>> [ child.tag for child in root.iterchildren(reversed=True) ]
+>>> [ child.tag for child in root.iterchildren(reversed=True) ]
 ['d', 'c', 'b', 'a']
 >>> [ sibling.tag for sibling in b.itersiblings() ]
 ['c', 'd']
->>> [ sibling.tag for sibling in c.itersiblings(preceding=True) ]
+>>> [ sibling.tag for sibling in c.itersiblings(preceding=True) ]
 ['b', 'a']
 >>> [ ancestor.tag for ancestor in e.iterancestors() ]
 ['d', 'root']
@@ -187,7 +187,7 @@ traverses the tree in document order.  This is implemented by the
 breadth-first traversal, it is almost as simple if you use the
 collections.deque type.

>>> root = etree.XML('<root><a><b/><c/></a><d><e/></d></root>')
->>> print(etree.tostring(root, pretty_print=True, encoding='unicode'))
+>>> print(etree.tostring(root, pretty_print=True, encoding='unicode'))
 <root>
   <a>
     <b/>
@@ -203,7 +203,7 @@ breadth-first traversal, it is almost as simple if you use the
 >>> while queue:
 ...    el = queue.popleft()  # pop next element
 ...    queue.extend(el)      # append its children
-...    print(el.tag)
+...    print(el.tag)
 root
 a
 d
@@ -239,7 +239,7 @@ copy attached to the exception:

to retrieve the log entries or filter them by a specific type, error domain or error level:

>>> log = e.error_log.filter_from_level(etree.ErrorLevels.FATAL)
->>> print(log[0])
+>>> print(log[0])
 <string>:4:8:FATAL:PARSER:ERR_TAG_NAME_MISMATCH: Opening and ending tag mismatch: a line 3 and root
 

This might look a little cryptic at first, but it is the information that @@ -250,11 +250,11 @@ or the filename if available). Here, PARSER is the so-called error domain, see lxml.etree.ErrorDomains for that. You can get it from a log entry like this:

>>> entry = log[0]
->>> print(entry.domain_name)
+>>> print(entry.domain_name)
 PARSER
->>> print(entry.type_name)
+>>> print(entry.type_name)
 ERR_TAG_NAME_MISMATCH
->>> print(entry.filename)
+>>> print(entry.filename)
 <string>
 

There is also a convenience attribute error_log.last_error that returns the @@ -284,7 +284,7 @@ to convert serialised XML to its canonical form directly, without creating a tree in memory. By default, it returns the canonical output, but can be directed to write it to a file instead.

>>> c14n_xml = etree.canonicalize("<root><test z='1' y='2'/></root>")
->>> print(c14n_xml)
+>>> print(c14n_xml)
 <root><test y="2" z="1"></test></root>
 
@@ -296,7 +296,7 @@ printing XML through a keyword argument:

>>> etree.tostring(root) b'<root><test/></root>' ->>> print(etree.tostring(root, pretty_print=True)) +>>> print(etree.tostring(root, pretty_print=True)) <root> <test/> </root> @@ -313,27 +313,27 @@ is required by the standard:

>>> etree.tostring(unicode_root, encoding="utf-8") b'<t\xe3\x84\xa0st>t\xe0\xa8\x8ast</t\xe3\x84\xa0st>' ->>> print(etree.tostring(unicode_root, encoding="iso-8859-1")) +>>> print(etree.tostring(unicode_root, encoding="iso-8859-1")) <?xml version='1.0' encoding='iso-8859-1'?> <t&#12576;st>t&#2570;st</t&#12576;st>

Also see the general remarks on Unicode support.

You can enable or disable the declaration explicitly by passing another keyword argument for the serialisation:

-
>>> print(etree.tostring(root, xml_declaration=True))
+
>>> print(etree.tostring(root, xml_declaration=True))
 <?xml version='1.0' encoding='ASCII'?>
 <root><test/></root>
 
 >>> unicode_root.clear()
 >>> etree.tostring(unicode_root, encoding="UTF-16LE",
-...                              xml_declaration=False)
+...                              xml_declaration=False)
 b'<\x00t\x00 1s\x00t\x00/\x00>\x00'
 

Note that a standard compliant XML parser will not consider the last line well-formed XML if the encoding is not explicitly provided somehow, e.g. in an underlying transport protocol:

>>> notxml = etree.tostring(unicode_root, encoding="UTF-16LE",
-...                                       xml_declaration=False)
+...                                       xml_declaration=False)
 >>> root = etree.XML(notxml)        #doctest: +ELLIPSIS
 Traceback (most recent call last):
   ...
@@ -344,11 +344,11 @@ of the document with a user provided DOCTYPE:

>>> xml = '<!DOCTYPE root>\n<root/>'
 >>> tree = etree.parse(StringIO(xml))
 
->>> print(etree.tostring(tree))
+>>> print(etree.tostring(tree))
 <!DOCTYPE root>
 <root/>
 
->>> print(etree.tostring(tree,
+>>> print(etree.tostring(tree,
 ...     doctype='<!DOCTYPE root SYSTEM "/tmp/test.dtd">'))
 <!DOCTYPE root SYSTEM "/tmp/test.dtd">
 <root/>
@@ -480,7 +480,7 @@ CDATA are rare, this is the best way to deal with this issue.

document is required to adhere to existing XML language definitions. For these special cases, you can instruct the parser to leave CDATA sections in the document:

-
>>> parser = etree.XMLParser(strip_cdata=False)
+
>>> parser = etree.XMLParser(strip_cdata=False)
 >>> root = etree.XML('<root><![CDATA[test]]></root>', parser)
 >>> root.text
 'test'
@@ -519,7 +519,7 @@ xinclude() method on a tree:

>>> tree = etree.parse(data) >>> tree.xinclude() ->>> print(etree.tostring(tree.getroot())) +>>> print(etree.tostring(tree.getroot())) <doc xmlns:xi="http://www.w3.org/2001/XInclude"> <foo/> <a xml:base="doc/test.xml"/> @@ -534,7 +534,7 @@ resolvers, you have to stick to the external Python module.

diff --git a/doc/html/apidoc/_modules/collections/abc.html b/doc/html/apidoc/_modules/collections/abc.html deleted file mode 100644 index 7784193..0000000 --- a/doc/html/apidoc/_modules/collections/abc.html +++ /dev/null @@ -1,230 +0,0 @@ - - - - - - - - - - collections.abc — lxml documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • »
  • - -
  • Module code »
  • - -
  • collections.abc
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for collections.abc

-from _collections_abc import *
-from _collections_abc import __all__
-
- -
- -
-
- - -
- -
-

- - © Copyright 2020, lxml dev team - -

-
- - - - Built with Sphinx using a - - theme - - provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - \ No newline at end of file diff --git a/doc/html/apidoc/_modules/index.html b/doc/html/apidoc/_modules/index.html index 8b7ffcc..3911768 100644 --- a/doc/html/apidoc/_modules/index.html +++ b/doc/html/apidoc/_modules/index.html @@ -1,73 +1,35 @@ - - - - - - + + Overview: module code — lxml documentation - - - - - - - - - - - - + + - - + - - - - - + - - - +
- -
- - -
- - - - - - - - + \ No newline at end of file diff --git a/doc/html/apidoc/_modules/lxml.html b/doc/html/apidoc/_modules/lxml.html index 0640590..5c21151 100644 --- a/doc/html/apidoc/_modules/lxml.html +++ b/doc/html/apidoc/_modules/lxml.html @@ -1,73 +1,35 @@ - - - - - - + + lxml — lxml documentation - - - - - - - - - - - - + + - - + - - - - - + - - - +
- -
- - -
- - - - - - - - + \ No newline at end of file diff --git a/doc/html/apidoc/_modules/lxml/ElementInclude.html b/doc/html/apidoc/_modules/lxml/ElementInclude.html index 1d76824..55d0e0e 100644 --- a/doc/html/apidoc/_modules/lxml/ElementInclude.html +++ b/doc/html/apidoc/_modules/lxml/ElementInclude.html @@ -1,73 +1,35 @@ - - - - - - + + lxml.ElementInclude — lxml documentation - - - - - - - - - - - - + + - - + - - - - - + - - - +
- -
- - -
- - - - - - - - + \ No newline at end of file diff --git a/doc/html/apidoc/_modules/lxml/doctestcompare.html b/doc/html/apidoc/_modules/lxml/doctestcompare.html index 6db6349..e0514c2 100644 --- a/doc/html/apidoc/_modules/lxml/doctestcompare.html +++ b/doc/html/apidoc/_modules/lxml/doctestcompare.html @@ -1,73 +1,35 @@ - - - - - - + + lxml.doctestcompare — lxml documentation - - - - - - - - - - - - + + - - + - - - - - + - - - +
- -
- - -
- - - - - - - - + \ No newline at end of file diff --git a/doc/html/apidoc/_modules/lxml/html.html b/doc/html/apidoc/_modules/lxml/html.html index 966c713..d224ec7 100644 --- a/doc/html/apidoc/_modules/lxml/html.html +++ b/doc/html/apidoc/_modules/lxml/html.html @@ -1,73 +1,35 @@ - - - - - - + + lxml.html — lxml documentation - - - - - - - - - - - - + + - - + - - - - - + - - - +
- -
- - -
- - - - - - - - + \ No newline at end of file diff --git a/doc/html/apidoc/_modules/lxml/html/_diffcommand.html b/doc/html/apidoc/_modules/lxml/html/_diffcommand.html index 5a9d6b0..71b91cb 100644 --- a/doc/html/apidoc/_modules/lxml/html/_diffcommand.html +++ b/doc/html/apidoc/_modules/lxml/html/_diffcommand.html @@ -1,73 +1,35 @@ - - - - - - + + lxml.html._diffcommand — lxml documentation - - - - - - - - - - - - + + - - + - - - - - + - - - +
- -
- - -
- - - - - - - - + \ No newline at end of file diff --git a/doc/html/apidoc/_modules/lxml/html/_setmixin.html b/doc/html/apidoc/_modules/lxml/html/_setmixin.html index 9ddca7c..1176a61 100644 --- a/doc/html/apidoc/_modules/lxml/html/_setmixin.html +++ b/doc/html/apidoc/_modules/lxml/html/_setmixin.html @@ -1,73 +1,35 @@ - - - - - - + + lxml.html._setmixin — lxml documentation - - - - - - - - - - - - + + - - + - - - - - + - - - +
- -
- - -
- - - - - - - - + \ No newline at end of file diff --git a/doc/html/apidoc/_modules/lxml/html/builder.html b/doc/html/apidoc/_modules/lxml/html/builder.html index a04ddce..4e3b757 100644 --- a/doc/html/apidoc/_modules/lxml/html/builder.html +++ b/doc/html/apidoc/_modules/lxml/html/builder.html @@ -1,73 +1,35 @@ - - - - - - + + lxml.html.builder — lxml documentation - - - - - - - - - - - - + + - - + - - - - - + - - - +
- -
- - -
- - - - - - - - + \ No newline at end of file diff --git a/doc/html/apidoc/_modules/lxml/html/formfill.html b/doc/html/apidoc/_modules/lxml/html/formfill.html index a7928ac..e464654 100644 --- a/doc/html/apidoc/_modules/lxml/html/formfill.html +++ b/doc/html/apidoc/_modules/lxml/html/formfill.html @@ -1,73 +1,35 @@ - - - - - - + + lxml.html.formfill — lxml documentation - - - - - - - - - - - - + + - - + - - - - - + - - - +
- -
- - -
- - - - - - - - + \ No newline at end of file diff --git a/doc/html/apidoc/_modules/lxml/isoschematron.html b/doc/html/apidoc/_modules/lxml/isoschematron.html index 8ebc1b9..ff0d7b7 100644 --- a/doc/html/apidoc/_modules/lxml/isoschematron.html +++ b/doc/html/apidoc/_modules/lxml/isoschematron.html @@ -1,73 +1,35 @@ - - - - - - + + lxml.isoschematron — lxml documentation - - - - - - - - - - - - + + - - + - - - - - + - - - +
- -
- - -
- - - - - - - - + \ No newline at end of file diff --git a/doc/html/apidoc/_static/basic.css b/doc/html/apidoc/_static/basic.css index 24bc73e..912859b 100644 --- a/doc/html/apidoc/_static/basic.css +++ b/doc/html/apidoc/_static/basic.css @@ -4,7 +4,7 @@ * * Sphinx stylesheet -- basic theme. * - * :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ @@ -130,7 +130,7 @@ ul.search li a { font-weight: bold; } -ul.search li div.context { +ul.search li p.context { color: #888; margin: 2px 0 0 30px; text-align: left; @@ -277,25 +277,25 @@ p.rubric { font-weight: bold; } -img.align-left, .figure.align-left, object.align-left { +img.align-left, figure.align-left, .figure.align-left, object.align-left { clear: left; float: left; margin-right: 1em; } -img.align-right, .figure.align-right, object.align-right { +img.align-right, figure.align-right, .figure.align-right, object.align-right { clear: right; float: right; margin-left: 1em; } -img.align-center, .figure.align-center, object.align-center { +img.align-center, figure.align-center, .figure.align-center, object.align-center { display: block; margin-left: auto; margin-right: auto; } -img.align-default, .figure.align-default { +img.align-default, figure.align-default, .figure.align-default { display: block; margin-left: auto; margin-right: auto; @@ -319,7 +319,8 @@ img.align-default, .figure.align-default { /* -- sidebars -------------------------------------------------------------- */ -div.sidebar { +div.sidebar, +aside.sidebar { margin: 0 0 0.5em 1em; border: 1px solid #ddb; padding: 7px; @@ -377,12 +378,14 @@ div.body p.centered { /* -- content of sidebars/topics/admonitions -------------------------------- */ div.sidebar > :last-child, +aside.sidebar > :last-child, div.topic > :last-child, div.admonition > :last-child { margin-bottom: 0; } div.sidebar::after, +aside.sidebar::after, div.topic::after, div.admonition::after, blockquote::after { @@ -455,20 +458,22 @@ td > :last-child { /* -- figures --------------------------------------------------------------- */ -div.figure { +div.figure, figure { margin: 0.5em; padding: 0.5em; } -div.figure p.caption { +div.figure p.caption, figcaption { padding: 0.3em; } -div.figure p.caption span.caption-number { +div.figure p.caption span.caption-number, +figcaption span.caption-number { font-style: italic; } -div.figure p.caption span.caption-text { +div.figure p.caption span.caption-text, +figcaption span.caption-text { } /* -- field list styles ----------------------------------------------------- */ @@ -503,6 +508,63 @@ table.hlist td { vertical-align: top; } +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + /* -- other body styles ----------------------------------------------------- */ @@ -629,14 +691,6 @@ dl.glossary dt { font-size: 1.1em; } -.optional { - font-size: 1.3em; -} - -.sig-paren { - font-size: larger; -} - .versionmodified { font-style: italic; } @@ -764,8 +818,13 @@ div.code-block-caption code { } table.highlighttable td.linenos, -div.doctest > div.highlight span.gp { /* gp: Generic.Prompt */ - user-select: none; +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ } div.code-block-caption span.caption-number { @@ -780,16 +839,6 @@ div.literal-block-wrapper { margin: 1em 0; } -code.descname { - background-color: transparent; - font-weight: bold; - font-size: 1.2em; -} - -code.descclassname { - background-color: transparent; -} - code.xref, a code { background-color: transparent; font-weight: bold; diff --git a/doc/html/apidoc/_static/css/theme.css b/doc/html/apidoc/_static/css/theme.css index 8cd4f10..0d9ae7e 100644 --- a/doc/html/apidoc/_static/css/theme.css +++ b/doc/html/apidoc/_static/css/theme.css @@ -1,4 +1,4 @@ -html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden],audio:not([controls]){display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;text-decoration:none}ins,mark{color:#000}mark{background:#ff0;font-style:italic;font-weight:700}.rst-content code,.rst-content tt,code,kbd,pre,samp{font-family:monospace,serif;_font-family:courier new,monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:after,q:before{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,ol,ul{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure,form{margin:0}label{cursor:pointer}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type=button],input[type=reset],input[type=submit]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}textarea{resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none!important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{body,html,section{background:none!important}*{box-shadow:none!important;text-shadow:none!important;filter:none!important;-ms-filter:none!important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}.rst-content .toctree-wrapper>p.caption,h2,h3,p{orphans:3;widows:3}.rst-content .toctree-wrapper>p.caption,h2,h3{page-break-after:avoid}}.btn,.fa:before,.icon:before,.rst-content .admonition,.rst-content .admonition-title:before,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .code-block-caption .headerlink:before,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-alert,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a,.wy-menu-vertical li.current>a span.toctree-expand:before,.wy-menu-vertical li.on a,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li span.toctree-expand:before,.wy-nav-top a,.wy-side-nav-search .wy-dropdown>a,.wy-side-nav-search>a,input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week],select,textarea{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}/*! +html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden],audio:not([controls]){display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;text-decoration:none}ins,mark{color:#000}mark{background:#ff0;font-style:italic;font-weight:700}.rst-content code,.rst-content tt,code,kbd,pre,samp{font-family:monospace,serif;_font-family:courier new,monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:after,q:before{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,ol,ul{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure,form{margin:0}label{cursor:pointer}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type=button],input[type=reset],input[type=submit]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}textarea{resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none!important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{body,html,section{background:none!important}*{box-shadow:none!important;text-shadow:none!important;filter:none!important;-ms-filter:none!important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}.rst-content .toctree-wrapper>p.caption,h2,h3,p{orphans:3;widows:3}.rst-content .toctree-wrapper>p.caption,h2,h3{page-break-after:avoid}}.btn,.fa:before,.icon:before,.rst-content .admonition,.rst-content .admonition-title:before,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .code-block-caption .headerlink:before,.rst-content .danger,.rst-content .eqno .headerlink:before,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-alert,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before,.wy-nav-top a,.wy-side-nav-search .wy-dropdown>a,.wy-side-nav-search>a,input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week],select,textarea{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}/*! * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) - */@font-face{font-family:FontAwesome;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713);src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix&v=4.7.0) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#fontawesomeregular) format("svg");font-weight:400;font-style:normal}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-menu-vertical li.current>a span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li span.toctree-expand{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa-pull-left.icon,.fa.fa-pull-left,.rst-content .code-block-caption .fa-pull-left.headerlink,.rst-content .fa-pull-left.admonition-title,.rst-content code.download span.fa-pull-left:first-child,.rst-content dl dt .fa-pull-left.headerlink,.rst-content h1 .fa-pull-left.headerlink,.rst-content h2 .fa-pull-left.headerlink,.rst-content h3 .fa-pull-left.headerlink,.rst-content h4 .fa-pull-left.headerlink,.rst-content h5 .fa-pull-left.headerlink,.rst-content h6 .fa-pull-left.headerlink,.rst-content p.caption .fa-pull-left.headerlink,.rst-content table>caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.wy-menu-vertical li.current>a span.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a span.fa-pull-left.toctree-expand,.wy-menu-vertical li span.fa-pull-left.toctree-expand{margin-right:.3em}.fa-pull-right.icon,.fa.fa-pull-right,.rst-content .code-block-caption .fa-pull-right.headerlink,.rst-content .fa-pull-right.admonition-title,.rst-content code.download span.fa-pull-right:first-child,.rst-content dl dt .fa-pull-right.headerlink,.rst-content h1 .fa-pull-right.headerlink,.rst-content h2 .fa-pull-right.headerlink,.rst-content h3 .fa-pull-right.headerlink,.rst-content h4 .fa-pull-right.headerlink,.rst-content h5 .fa-pull-right.headerlink,.rst-content h6 .fa-pull-right.headerlink,.rst-content p.caption .fa-pull-right.headerlink,.rst-content table>caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.wy-menu-vertical li.current>a span.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a span.fa-pull-right.toctree-expand,.wy-menu-vertical li span.fa-pull-right.toctree-expand{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.pull-left.icon,.rst-content .code-block-caption .pull-left.headerlink,.rst-content .pull-left.admonition-title,.rst-content code.download span.pull-left:first-child,.rst-content dl dt .pull-left.headerlink,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content p.caption .pull-left.headerlink,.rst-content table>caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.wy-menu-vertical li.current>a span.pull-left.toctree-expand,.wy-menu-vertical li.on a span.pull-left.toctree-expand,.wy-menu-vertical li span.pull-left.toctree-expand{margin-right:.3em}.fa.pull-right,.pull-right.icon,.rst-content .code-block-caption .pull-right.headerlink,.rst-content .pull-right.admonition-title,.rst-content code.download span.pull-right:first-child,.rst-content dl dt .pull-right.headerlink,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content p.caption .pull-right.headerlink,.rst-content table>caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.wy-menu-vertical li.current>a span.pull-right.toctree-expand,.wy-menu-vertical li.on a span.pull-right.toctree-expand,.wy-menu-vertical li span.pull-right.toctree-expand{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);-ms-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scaleY(-1);-ms-transform:scaleY(-1);transform:scaleY(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-close:before,.fa-remove:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-cog:before,.fa-gear:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-repeat:before,.fa-rotate-right:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.rst-content .admonition-title:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-exclamation-triangle:before,.fa-warning:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-cogs:before,.fa-gears:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook-f:before,.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-feed:before,.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-floppy-o:before,.fa-save:before{content:""}.fa-square:before{content:""}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.icon-caret-down:before,.wy-dropdown .caret:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-sort:before,.fa-unsorted:before{content:""}.fa-sort-desc:before,.fa-sort-down:before{content:""}.fa-sort-asc:before,.fa-sort-up:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-gavel:before,.fa-legal:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-bolt:before,.fa-flash:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-clipboard:before,.fa-paste:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-chain-broken:before,.fa-unlink:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.current>a span.toctree-expand:before,.wy-menu-vertical li.on a span.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:""}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:""}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:""}.fa-eur:before,.fa-euro:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-inr:before,.fa-rupee:before{content:""}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:""}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:""}.fa-krw:before,.fa-won:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-try:before,.fa-turkish-lira:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li span.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-bank:before,.fa-institution:before,.fa-university:before{content:""}.fa-graduation-cap:before,.fa-mortar-board:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper-pp:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:""}.fa-file-archive-o:before,.fa-file-zip-o:before{content:""}.fa-file-audio-o:before,.fa-file-sound-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-rebel:before,.fa-resistance:before{content:""}.fa-empire:before,.fa-ge:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-hacker-news:before,.fa-y-combinator-square:before,.fa-yc-square:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-paper-plane:before,.fa-send:before{content:""}.fa-paper-plane-o:before,.fa-send-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:""}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:""}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:""}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-bed:before,.fa-hotel:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-y-combinator:before,.fa-yc:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery-full:before,.fa-battery:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:""}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:""}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:""}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-paper-o:before,.fa-hand-stop-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:""}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-television:before,.fa-tv:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:""}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:""}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:""}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}.fa-gitlab:before,.icon-gitlab:before{content:""}.fa-wpbeginner:before{content:""}.fa-wpforms:before{content:""}.fa-envira:before{content:""}.fa-universal-access:before{content:""}.fa-wheelchair-alt:before{content:""}.fa-question-circle-o:before{content:""}.fa-blind:before{content:""}.fa-audio-description:before{content:""}.fa-volume-control-phone:before{content:""}.fa-braille:before{content:""}.fa-assistive-listening-systems:before{content:""}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before{content:""}.fa-deaf:before,.fa-deafness:before,.fa-hard-of-hearing:before{content:""}.fa-glide:before{content:""}.fa-glide-g:before{content:""}.fa-sign-language:before,.fa-signing:before{content:""}.fa-low-vision:before{content:""}.fa-viadeo:before{content:""}.fa-viadeo-square:before{content:""}.fa-snapchat:before{content:""}.fa-snapchat-ghost:before{content:""}.fa-snapchat-square:before{content:""}.fa-pied-piper:before{content:""}.fa-first-order:before{content:""}.fa-yoast:before{content:""}.fa-themeisle:before{content:""}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:""}.fa-fa:before,.fa-font-awesome:before{content:""}.fa-handshake-o:before{content:""}.fa-envelope-open:before{content:""}.fa-envelope-open-o:before{content:""}.fa-linode:before{content:""}.fa-address-book:before{content:""}.fa-address-book-o:before{content:""}.fa-address-card:before,.fa-vcard:before{content:""}.fa-address-card-o:before,.fa-vcard-o:before{content:""}.fa-user-circle:before{content:""}.fa-user-circle-o:before{content:""}.fa-user-o:before{content:""}.fa-id-badge:before{content:""}.fa-drivers-license:before,.fa-id-card:before{content:""}.fa-drivers-license-o:before,.fa-id-card-o:before{content:""}.fa-quora:before{content:""}.fa-free-code-camp:before{content:""}.fa-telegram:before{content:""}.fa-thermometer-4:before,.fa-thermometer-full:before,.fa-thermometer:before{content:""}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:""}.fa-thermometer-2:before,.fa-thermometer-half:before{content:""}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:""}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:""}.fa-shower:before{content:""}.fa-bath:before,.fa-bathtub:before,.fa-s15:before{content:""}.fa-podcast:before{content:""}.fa-window-maximize:before{content:""}.fa-window-minimize:before{content:""}.fa-window-restore:before{content:""}.fa-times-rectangle:before,.fa-window-close:before{content:""}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:""}.fa-bandcamp:before{content:""}.fa-grav:before{content:""}.fa-etsy:before{content:""}.fa-imdb:before{content:""}.fa-ravelry:before{content:""}.fa-eercast:before{content:""}.fa-microchip:before{content:""}.fa-snowflake-o:before{content:""}.fa-superpowers:before{content:""}.fa-wpexplorer:before{content:""}.fa-meetup:before{content:""}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-menu-vertical li.current>a span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li span.toctree-expand{font-family:inherit}.fa:before,.icon:before,.rst-content .admonition-title:before,.rst-content .code-block-caption .headerlink:before,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a span.toctree-expand:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li span.toctree-expand:before{font-family:FontAwesome;display:inline-block;font-style:normal;font-weight:400;line-height:1;text-decoration:inherit}.rst-content .code-block-caption a .headerlink,.rst-content a .admonition-title,.rst-content code.download a span:first-child,.rst-content dl dt a .headerlink,.rst-content h1 a .headerlink,.rst-content h2 a .headerlink,.rst-content h3 a .headerlink,.rst-content h4 a .headerlink,.rst-content h5 a .headerlink,.rst-content h6 a .headerlink,.rst-content p.caption a .headerlink,.rst-content table>caption a .headerlink,.rst-content tt.download a span:first-child,.wy-menu-vertical li.current>a span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li a span.toctree-expand,a .fa,a .icon,a .rst-content .admonition-title,a .rst-content .code-block-caption .headerlink,a .rst-content code.download span:first-child,a .rst-content dl dt .headerlink,a .rst-content h1 .headerlink,a .rst-content h2 .headerlink,a .rst-content h3 .headerlink,a .rst-content h4 .headerlink,a .rst-content h5 .headerlink,a .rst-content h6 .headerlink,a .rst-content p.caption .headerlink,a .rst-content table>caption .headerlink,a .rst-content tt.download span:first-child,a .wy-menu-vertical li span.toctree-expand{display:inline-block;text-decoration:inherit}.btn .fa,.btn .icon,.btn .rst-content .admonition-title,.btn .rst-content .code-block-caption .headerlink,.btn .rst-content code.download span:first-child,.btn .rst-content dl dt .headerlink,.btn .rst-content h1 .headerlink,.btn .rst-content h2 .headerlink,.btn .rst-content h3 .headerlink,.btn .rst-content h4 .headerlink,.btn .rst-content h5 .headerlink,.btn .rst-content h6 .headerlink,.btn .rst-content p.caption .headerlink,.btn .rst-content table>caption .headerlink,.btn .rst-content tt.download span:first-child,.btn .wy-menu-vertical li.current>a span.toctree-expand,.btn .wy-menu-vertical li.on a span.toctree-expand,.btn .wy-menu-vertical li span.toctree-expand,.nav .fa,.nav .icon,.nav .rst-content .admonition-title,.nav .rst-content .code-block-caption .headerlink,.nav .rst-content code.download span:first-child,.nav .rst-content dl dt .headerlink,.nav .rst-content h1 .headerlink,.nav .rst-content h2 .headerlink,.nav .rst-content h3 .headerlink,.nav .rst-content h4 .headerlink,.nav .rst-content h5 .headerlink,.nav .rst-content h6 .headerlink,.nav .rst-content p.caption .headerlink,.nav .rst-content table>caption .headerlink,.nav .rst-content tt.download span:first-child,.nav .wy-menu-vertical li.current>a span.toctree-expand,.nav .wy-menu-vertical li.on a span.toctree-expand,.nav .wy-menu-vertical li span.toctree-expand,.rst-content .btn .admonition-title,.rst-content .code-block-caption .btn .headerlink,.rst-content .code-block-caption .nav .headerlink,.rst-content .nav .admonition-title,.rst-content code.download .btn span:first-child,.rst-content code.download .nav span:first-child,.rst-content dl dt .btn .headerlink,.rst-content dl dt .nav .headerlink,.rst-content h1 .btn .headerlink,.rst-content h1 .nav .headerlink,.rst-content h2 .btn .headerlink,.rst-content h2 .nav .headerlink,.rst-content h3 .btn .headerlink,.rst-content h3 .nav .headerlink,.rst-content h4 .btn .headerlink,.rst-content h4 .nav .headerlink,.rst-content h5 .btn .headerlink,.rst-content h5 .nav .headerlink,.rst-content h6 .btn .headerlink,.rst-content h6 .nav .headerlink,.rst-content p.caption .btn .headerlink,.rst-content p.caption .nav .headerlink,.rst-content table>caption .btn .headerlink,.rst-content table>caption .nav .headerlink,.rst-content tt.download .btn span:first-child,.rst-content tt.download .nav span:first-child,.wy-menu-vertical li .btn span.toctree-expand,.wy-menu-vertical li.current>a .btn span.toctree-expand,.wy-menu-vertical li.current>a .nav span.toctree-expand,.wy-menu-vertical li .nav span.toctree-expand,.wy-menu-vertical li.on a .btn span.toctree-expand,.wy-menu-vertical li.on a .nav span.toctree-expand{display:inline}.btn .fa-large.icon,.btn .fa.fa-large,.btn .rst-content .code-block-caption .fa-large.headerlink,.btn .rst-content .fa-large.admonition-title,.btn .rst-content code.download span.fa-large:first-child,.btn .rst-content dl dt .fa-large.headerlink,.btn .rst-content h1 .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.btn .rst-content p.caption .fa-large.headerlink,.btn .rst-content table>caption .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.btn .wy-menu-vertical li span.fa-large.toctree-expand,.nav .fa-large.icon,.nav .fa.fa-large,.nav .rst-content .code-block-caption .fa-large.headerlink,.nav .rst-content .fa-large.admonition-title,.nav .rst-content code.download span.fa-large:first-child,.nav .rst-content dl dt .fa-large.headerlink,.nav .rst-content h1 .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.nav .rst-content p.caption .fa-large.headerlink,.nav .rst-content table>caption .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.nav .wy-menu-vertical li span.fa-large.toctree-expand,.rst-content .btn .fa-large.admonition-title,.rst-content .code-block-caption .btn .fa-large.headerlink,.rst-content .code-block-caption .nav .fa-large.headerlink,.rst-content .nav .fa-large.admonition-title,.rst-content code.download .btn span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.rst-content dl dt .btn .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.rst-content p.caption .btn .fa-large.headerlink,.rst-content p.caption .nav .fa-large.headerlink,.rst-content table>caption .btn .fa-large.headerlink,.rst-content table>caption .nav .fa-large.headerlink,.rst-content tt.download .btn span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.wy-menu-vertical li .btn span.fa-large.toctree-expand,.wy-menu-vertical li .nav span.fa-large.toctree-expand{line-height:.9em}.btn .fa-spin.icon,.btn .fa.fa-spin,.btn .rst-content .code-block-caption .fa-spin.headerlink,.btn .rst-content .fa-spin.admonition-title,.btn .rst-content code.download span.fa-spin:first-child,.btn .rst-content dl dt .fa-spin.headerlink,.btn .rst-content h1 .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.btn .rst-content p.caption .fa-spin.headerlink,.btn .rst-content table>caption .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.btn .wy-menu-vertical li span.fa-spin.toctree-expand,.nav .fa-spin.icon,.nav .fa.fa-spin,.nav .rst-content .code-block-caption .fa-spin.headerlink,.nav .rst-content .fa-spin.admonition-title,.nav .rst-content code.download span.fa-spin:first-child,.nav .rst-content dl dt .fa-spin.headerlink,.nav .rst-content h1 .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.nav .rst-content p.caption .fa-spin.headerlink,.nav .rst-content table>caption .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.nav .wy-menu-vertical li span.fa-spin.toctree-expand,.rst-content .btn .fa-spin.admonition-title,.rst-content .code-block-caption .btn .fa-spin.headerlink,.rst-content .code-block-caption .nav .fa-spin.headerlink,.rst-content .nav .fa-spin.admonition-title,.rst-content code.download .btn span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.rst-content dl dt .btn .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.rst-content p.caption .btn .fa-spin.headerlink,.rst-content p.caption .nav .fa-spin.headerlink,.rst-content table>caption .btn .fa-spin.headerlink,.rst-content table>caption .nav .fa-spin.headerlink,.rst-content tt.download .btn span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.wy-menu-vertical li .btn span.fa-spin.toctree-expand,.wy-menu-vertical li .nav span.fa-spin.toctree-expand{display:inline-block}.btn.fa:before,.btn.icon:before,.rst-content .btn.admonition-title:before,.rst-content .code-block-caption .btn.headerlink:before,.rst-content code.download span.btn:first-child:before,.rst-content dl dt .btn.headerlink:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content p.caption .btn.headerlink:before,.rst-content table>caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.wy-menu-vertical li span.btn.toctree-expand:before{opacity:.5;-webkit-transition:opacity .05s ease-in;-moz-transition:opacity .05s ease-in;transition:opacity .05s ease-in}.btn.fa:hover:before,.btn.icon:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content .code-block-caption .btn.headerlink:hover:before,.rst-content code.download span.btn:first-child:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content p.caption .btn.headerlink:hover:before,.rst-content table>caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.wy-menu-vertical li span.btn.toctree-expand:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .icon:before,.btn-mini .rst-content .admonition-title:before,.btn-mini .rst-content .code-block-caption .headerlink:before,.btn-mini .rst-content code.download span:first-child:before,.btn-mini .rst-content dl dt .headerlink:before,.btn-mini .rst-content h1 .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.btn-mini .rst-content p.caption .headerlink:before,.btn-mini .rst-content table>caption .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.btn-mini .wy-menu-vertical li span.toctree-expand:before,.rst-content .btn-mini .admonition-title:before,.rst-content .code-block-caption .btn-mini .headerlink:before,.rst-content code.download .btn-mini span:first-child:before,.rst-content dl dt .btn-mini .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.rst-content p.caption .btn-mini .headerlink:before,.rst-content table>caption .btn-mini .headerlink:before,.rst-content tt.download .btn-mini span:first-child:before,.wy-menu-vertical li .btn-mini span.toctree-expand:before{font-size:14px;vertical-align:-15%}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.wy-alert{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.rst-content .admonition-title,.wy-alert-title{font-weight:700;display:block;color:#fff;background:#6ab0de;padding:6px 12px;margin:-12px -12px 12px}.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.admonition,.rst-content .wy-alert-danger.admonition-todo,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.wy-alert.wy-alert-danger{background:#fdf3f2}.rst-content .danger .admonition-title,.rst-content .danger .wy-alert-title,.rst-content .error .admonition-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.rst-content .wy-alert-danger.admonition .admonition-title,.rst-content .wy-alert-danger.admonition .wy-alert-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.wy-alert.wy-alert-danger .wy-alert-title{background:#f29f97}.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .warning,.rst-content .wy-alert-warning.admonition,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.note,.rst-content .wy-alert-warning.seealso,.rst-content .wy-alert-warning.tip,.wy-alert.wy-alert-warning{background:#ffedcc}.rst-content .admonition-todo .admonition-title,.rst-content .admonition-todo .wy-alert-title,.rst-content .attention .admonition-title,.rst-content .attention .wy-alert-title,.rst-content .caution .admonition-title,.rst-content .caution .wy-alert-title,.rst-content .warning .admonition-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.admonition .admonition-title,.rst-content .wy-alert-warning.admonition .wy-alert-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.wy-alert.wy-alert-warning .wy-alert-title{background:#f0b37e}.rst-content .note,.rst-content .seealso,.rst-content .wy-alert-info.admonition,.rst-content .wy-alert-info.admonition-todo,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.wy-alert.wy-alert-info{background:#e7f2fa}.rst-content .note .admonition-title,.rst-content .note .wy-alert-title,.rst-content .seealso .admonition-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .admonition-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.rst-content .wy-alert-info.admonition .admonition-title,.rst-content .wy-alert-info.admonition .wy-alert-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.wy-alert.wy-alert-info .wy-alert-title{background:#6ab0de}.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.admonition,.rst-content .wy-alert-success.admonition-todo,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.warning,.wy-alert.wy-alert-success{background:#dbfaf4}.rst-content .hint .admonition-title,.rst-content .hint .wy-alert-title,.rst-content .important .admonition-title,.rst-content .important .wy-alert-title,.rst-content .tip .admonition-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .admonition-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.rst-content .wy-alert-success.admonition .admonition-title,.rst-content .wy-alert-success.admonition .wy-alert-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.wy-alert.wy-alert-success .wy-alert-title{background:#1abc9c}.rst-content .wy-alert-neutral.admonition,.rst-content .wy-alert-neutral.admonition-todo,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.wy-alert.wy-alert-neutral{background:#f3f6f6}.rst-content .wy-alert-neutral.admonition-todo .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.rst-content .wy-alert-neutral.admonition .admonition-title,.rst-content .wy-alert-neutral.admonition .wy-alert-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.wy-alert.wy-alert-neutral .wy-alert-title{color:#404040;background:#e1e4e5}.rst-content .wy-alert-neutral.admonition-todo a,.rst-content .wy-alert-neutral.admonition a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.wy-alert.wy-alert-neutral a{color:#2980b9}.rst-content .admonition-todo p:last-child,.rst-content .admonition p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .note p:last-child,.rst-content .seealso p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.wy-alert p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all .3s ease-in;-moz-transition:all .3s ease-in;transition:all .3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27ae60}.wy-tray-container li.wy-tray-item-info{background:#2980b9}.wy-tray-container li.wy-tray-item-warning{background:#e67e22}.wy-tray-container li.wy-tray-item-danger{background:#e74c3c}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width:768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px;color:#fff;border:1px solid rgba(0,0,0,.1);background-color:#27ae60;text-decoration:none;font-weight:400;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 2px -1px hsla(0,0%,100%,.5),inset 0 -2px 0 0 rgba(0,0,0,.1);outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;transition:all .1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:inset 0 -1px 0 0 rgba(0,0,0,.05),inset 0 2px 0 0 rgba(0,0,0,.1);padding:8px 12px 6px}.btn:visited{color:#fff}.btn-disabled,.btn-disabled:active,.btn-disabled:focus,.btn-disabled:hover,.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980b9!important}.btn-info:hover{background-color:#2e8ece!important}.btn-neutral{background-color:#f3f6f6!important;color:#404040!important}.btn-neutral:hover{background-color:#e5ebeb!important;color:#404040}.btn-neutral:visited{color:#404040!important}.btn-success{background-color:#27ae60!important}.btn-success:hover{background-color:#295!important}.btn-danger{background-color:#e74c3c!important}.btn-danger:hover{background-color:#ea6153!important}.btn-warning{background-color:#e67e22!important}.btn-warning:hover{background-color:#e98b39!important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f!important}.btn-link{background-color:transparent!important;color:#2980b9;box-shadow:none;border-color:transparent!important}.btn-link:active,.btn-link:hover{background-color:transparent!important;color:#409ad5!important;box-shadow:none}.btn-link:visited{color:#9b59b6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:after,.wy-btn-group:before{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:1px solid #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980b9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:1px solid #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type=search]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980b9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned .wy-help-inline,.wy-form-aligned input,.wy-form-aligned label,.wy-form-aligned select,.wy-form-aligned textarea{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{margin:0}fieldset,legend{border:0;padding:0}legend{width:100%;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label,legend{display:block}label{margin:0 0 .3125em;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;max-width:1200px;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:after,.wy-control-group:before{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#e74c3c}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full input[type=color],.wy-control-group .wy-form-full input[type=date],.wy-control-group .wy-form-full input[type=datetime-local],.wy-control-group .wy-form-full input[type=datetime],.wy-control-group .wy-form-full input[type=email],.wy-control-group .wy-form-full input[type=month],.wy-control-group .wy-form-full input[type=number],.wy-control-group .wy-form-full input[type=password],.wy-control-group .wy-form-full input[type=search],.wy-control-group .wy-form-full input[type=tel],.wy-control-group .wy-form-full input[type=text],.wy-control-group .wy-form-full input[type=time],.wy-control-group .wy-form-full input[type=url],.wy-control-group .wy-form-full input[type=week],.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves input[type=color],.wy-control-group .wy-form-halves input[type=date],.wy-control-group .wy-form-halves input[type=datetime-local],.wy-control-group .wy-form-halves input[type=datetime],.wy-control-group .wy-form-halves input[type=email],.wy-control-group .wy-form-halves input[type=month],.wy-control-group .wy-form-halves input[type=number],.wy-control-group .wy-form-halves input[type=password],.wy-control-group .wy-form-halves input[type=search],.wy-control-group .wy-form-halves input[type=tel],.wy-control-group .wy-form-halves input[type=text],.wy-control-group .wy-form-halves input[type=time],.wy-control-group .wy-form-halves input[type=url],.wy-control-group .wy-form-halves input[type=week],.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds input[type=color],.wy-control-group .wy-form-thirds input[type=date],.wy-control-group .wy-form-thirds input[type=datetime-local],.wy-control-group .wy-form-thirds input[type=datetime],.wy-control-group .wy-form-thirds input[type=email],.wy-control-group .wy-form-thirds input[type=month],.wy-control-group .wy-form-thirds input[type=number],.wy-control-group .wy-form-thirds input[type=password],.wy-control-group .wy-form-thirds input[type=search],.wy-control-group .wy-form-thirds input[type=tel],.wy-control-group .wy-form-thirds input[type=text],.wy-control-group .wy-form-thirds input[type=time],.wy-control-group .wy-form-thirds input[type=url],.wy-control-group .wy-form-thirds input[type=week],.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full{float:left;display:block;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.35765%;width:48.82117%}.wy-control-group .wy-form-halves:last-child,.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(odd){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.35765%;width:31.76157%}.wy-control-group .wy-form-thirds:last-child,.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control,.wy-control-no-input{margin:6px 0 0;font-size:90%}.wy-control-no-input{display:inline-block}.wy-control-group.fluid-input input[type=color],.wy-control-group.fluid-input input[type=date],.wy-control-group.fluid-input input[type=datetime-local],.wy-control-group.fluid-input input[type=datetime],.wy-control-group.fluid-input input[type=email],.wy-control-group.fluid-input input[type=month],.wy-control-group.fluid-input input[type=number],.wy-control-group.fluid-input input[type=password],.wy-control-group.fluid-input input[type=search],.wy-control-group.fluid-input input[type=tel],.wy-control-group.fluid-input input[type=text],.wy-control-group.fluid-input input[type=time],.wy-control-group.fluid-input input[type=url],.wy-control-group.fluid-input input[type=week]{width:100%}.wy-form-message-inline{padding-left:.3em;color:#666;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;*overflow:visible}input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}input[type=datetime-local]{padding:.34375em .625em}input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{padding:0;margin-right:.3125em;*height:13px;*width:13px}input[type=checkbox],input[type=radio],input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}input[type=color]:focus,input[type=date]:focus,input[type=datetime-local]:focus,input[type=datetime]:focus,input[type=email]:focus,input[type=month]:focus,input[type=number]:focus,input[type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=time]:focus,input[type=url]:focus,input[type=week]:focus{outline:0;outline:thin dotted\9;border-color:#333}input.no-focus:focus{border-color:#ccc!important}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:thin dotted #333;outline:1px auto #129fea}input[type=color][disabled],input[type=date][disabled],input[type=datetime-local][disabled],input[type=datetime][disabled],input[type=email][disabled],input[type=month][disabled],input[type=number][disabled],input[type=password][disabled],input[type=search][disabled],input[type=tel][disabled],input[type=text][disabled],input[type=time][disabled],input[type=url][disabled],input[type=week][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,select:focus:invalid,textarea:focus:invalid{color:#e74c3c;border:1px solid #e74c3c}input:focus:invalid:focus,select:focus:invalid:focus,textarea:focus:invalid:focus{border-color:#e74c3c}input[type=checkbox]:focus:invalid:focus,input[type=file]:focus:invalid:focus,input[type=radio]:focus:invalid:focus{outline-color:#e74c3c}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif}select,textarea{padding:.5em .625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}input[readonly],select[disabled],select[readonly],textarea[disabled],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type=checkbox][disabled],input[type=radio][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:1px solid #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{position:relative;display:block;height:24px;margin-top:12px;cursor:pointer}.wy-switch:before{left:0;top:0;width:36px;height:12px;background:#ccc}.wy-switch:after,.wy-switch:before{position:absolute;content:"";display:block;border-radius:4px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch:after{width:18px;height:18px;background:#999;left:-3px;top:-3px}.wy-switch span{position:absolute;left:48px;display:block;font-size:12px;color:#ccc;line-height:1}.wy-switch.active:before{background:#1e8449}.wy-switch.active:after{left:24px;background:#27ae60}.wy-switch.disabled{cursor:not-allowed;opacity:.8}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#e74c3c}.wy-control-group.wy-control-group-error input[type=color],.wy-control-group.wy-control-group-error input[type=date],.wy-control-group.wy-control-group-error input[type=datetime-local],.wy-control-group.wy-control-group-error input[type=datetime],.wy-control-group.wy-control-group-error input[type=email],.wy-control-group.wy-control-group-error input[type=month],.wy-control-group.wy-control-group-error input[type=number],.wy-control-group.wy-control-group-error input[type=password],.wy-control-group.wy-control-group-error input[type=search],.wy-control-group.wy-control-group-error input[type=tel],.wy-control-group.wy-control-group-error input[type=text],.wy-control-group.wy-control-group-error input[type=time],.wy-control-group.wy-control-group-error input[type=url],.wy-control-group.wy-control-group-error input[type=week],.wy-control-group.wy-control-group-error textarea{border:1px solid #e74c3c}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:.5em .625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27ae60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#e74c3c}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#e67e22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980b9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width:480px){.wy-form button[type=submit]{margin:.7em 0 0}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=text],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week],.wy-form label{margin-bottom:.3em;display:block}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0}.wy-form-message,.wy-form-message-inline,.wy-form .wy-help-inline{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width:768px){.tablet-hide{display:none}}@media screen and (max-width:480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.rst-content table.docutils,.rst-content table.field-list,.wy-table{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.rst-content table.docutils caption,.rst-content table.field-list caption,.wy-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.rst-content table.docutils td,.rst-content table.docutils th,.rst-content table.field-list td,.rst-content table.field-list th,.wy-table td,.wy-table th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.rst-content table.docutils td:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list td:first-child,.rst-content table.field-list th:first-child,.wy-table td:first-child,.wy-table th:first-child{border-left-width:0}.rst-content table.docutils thead,.rst-content table.field-list thead,.wy-table thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.rst-content table.docutils thead th,.rst-content table.field-list thead th,.wy-table thead th{font-weight:700;border-bottom:2px solid #e1e4e5}.rst-content table.docutils td,.rst-content table.field-list td,.wy-table td{background-color:transparent;vertical-align:middle}.rst-content table.docutils td p,.rst-content table.field-list td p,.wy-table td p{line-height:18px}.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child,.wy-table td p:last-child{margin-bottom:0}.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min,.wy-table .wy-table-cell-min{width:1%;padding-right:0}.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:grey;font-size:90%}.wy-table-tertiary{color:grey;font-size:80%}.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td,.wy-table-backed,.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td{background-color:#f3f6f6}.rst-content table.docutils,.wy-table-bordered-all{border:1px solid #e1e4e5}.rst-content table.docutils td,.wy-table-bordered-all td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.rst-content table.docutils tbody>tr:last-child td,.wy-table-bordered-all tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0!important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980b9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9b59b6}html{height:100%}body,html{overflow-x:hidden}body{font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;font-weight:400;color:#404040;min-height:100%;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#e67e22!important}a.wy-text-warning:hover{color:#eb9950!important}.wy-text-info{color:#2980b9!important}a.wy-text-info:hover{color:#409ad5!important}.wy-text-success{color:#27ae60!important}a.wy-text-success:hover{color:#36d278!important}.wy-text-danger{color:#e74c3c!important}a.wy-text-danger:hover{color:#ed7669!important}.wy-text-neutral{color:#404040!important}a.wy-text-neutral:hover{color:#595959!important}.rst-content .toctree-wrapper>p.caption,h1,h2,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif}p{line-height:24px;font-size:16px;margin:0 0 24px}h1{font-size:175%}.rst-content .toctree-wrapper>p.caption,h2{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}.rst-content code,.rst-content tt,code{white-space:nowrap;max-width:100%;background:#fff;border:1px solid #e1e4e5;font-size:75%;padding:0 5px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#e74c3c;overflow-x:auto}.rst-content tt.code-large,code.code-large{font-size:90%}.rst-content .section ul,.rst-content .toctree-wrapper ul,.wy-plain-list-disc,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.rst-content .section ul li,.rst-content .toctree-wrapper ul li,.wy-plain-list-disc li,article ul li{list-style:disc;margin-left:24px}.rst-content .section ul li p:last-child,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li p:last-child,.rst-content .toctree-wrapper ul li ul,.wy-plain-list-disc li p:last-child,.wy-plain-list-disc li ul,article ul li p:last-child,article ul li ul{margin-bottom:0}.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,.wy-plain-list-disc li li,article ul li li{list-style:circle}.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,.wy-plain-list-disc li li li,article ul li li li{list-style:square}.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,.wy-plain-list-disc li ol li,article ul li ol li{list-style:decimal}.rst-content .section ol,.rst-content ol.arabic,.wy-plain-list-decimal,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.rst-content .section ol li,.rst-content ol.arabic li,.wy-plain-list-decimal li,article ol li{list-style:decimal;margin-left:24px}.rst-content .section ol li p:last-child,.rst-content .section ol li ul,.rst-content ol.arabic li p:last-child,.rst-content ol.arabic li ul,.wy-plain-list-decimal li p:last-child,.wy-plain-list-decimal li ul,article ol li p:last-child,article ol li ul{margin-bottom:0}.rst-content .section ol li ul li,.rst-content ol.arabic li ul li,.wy-plain-list-decimal li ul li,article ol li ul li{list-style:disc}.wy-breadcrumbs{*zoom:1}.wy-breadcrumbs:after,.wy-breadcrumbs:before{display:table;content:""}.wy-breadcrumbs:after{clear:both}.wy-breadcrumbs li{display:inline-block}.wy-breadcrumbs li.wy-breadcrumbs-aside{float:right}.wy-breadcrumbs li a{display:inline-block;padding:5px}.wy-breadcrumbs li a:first-child{padding-left:0}.rst-content .wy-breadcrumbs li tt,.wy-breadcrumbs li .rst-content tt,.wy-breadcrumbs li code{padding:5px;border:none;background:none}.rst-content .wy-breadcrumbs li tt.literal,.wy-breadcrumbs li .rst-content tt.literal,.wy-breadcrumbs li code.literal{color:#404040}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width:480px){.wy-breadcrumbs-extra,.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}html{font-size:16px}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:after,.wy-menu-horiz:before{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz li,.wy-menu-horiz ul{display:inline-block}.wy-menu-horiz li:hover{background:hsla(0,0%,100%,.1)}.wy-menu-horiz li.divide-left{border-left:1px solid #404040}.wy-menu-horiz li.divide-right{border-right:1px solid #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{color:#55a5d9;height:32px;line-height:32px;padding:0 1.618em;margin:12px 0 0;display:block;font-weight:700;text-transform:uppercase;font-size:85%;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:1px solid #404040}.wy-menu-vertical li.divide-bottom{border-bottom:1px solid #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:grey;border-right:1px solid #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.rst-content .wy-menu-vertical li tt,.wy-menu-vertical li .rst-content tt,.wy-menu-vertical li code{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li span.toctree-expand{display:block;float:left;margin-left:-1.2em;font-size:.8em;line-height:1.6em;color:#4d4d4d}.wy-menu-vertical li.current>a,.wy-menu-vertical li.on a{color:#404040;font-weight:700;position:relative;background:#fcfcfc;border:none;padding:.4045em 1.618em}.wy-menu-vertical li.current>a:hover,.wy-menu-vertical li.on a:hover{background:#fcfcfc}.wy-menu-vertical li.current>a:hover span.toctree-expand,.wy-menu-vertical li.on a:hover span.toctree-expand{color:grey}.wy-menu-vertical li.current>a span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand{display:block;font-size:.8em;line-height:1.6em;color:#333}.wy-menu-vertical li.toctree-l1.current>a{border-bottom:1px solid #c9c9c9;border-top:1px solid #c9c9c9}.wy-menu-vertical .toctree-l1.current .toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .toctree-l11>ul{display:none}.wy-menu-vertical .toctree-l1.current .current.toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .current.toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .current.toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .current.toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .current.toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .current.toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .current.toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .current.toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .current.toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .current.toctree-l11>ul{display:block}.wy-menu-vertical li.toctree-l3,.wy-menu-vertical li.toctree-l4{font-size:.9em}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l4 a,.wy-menu-vertical li.toctree-l5 a,.wy-menu-vertical li.toctree-l6 a,.wy-menu-vertical li.toctree-l7 a,.wy-menu-vertical li.toctree-l8 a,.wy-menu-vertical li.toctree-l9 a,.wy-menu-vertical li.toctree-l10 a{color:#404040}.wy-menu-vertical li.toctree-l2 a:hover span.toctree-expand,.wy-menu-vertical li.toctree-l3 a:hover span.toctree-expand,.wy-menu-vertical li.toctree-l4 a:hover span.toctree-expand,.wy-menu-vertical li.toctree-l5 a:hover span.toctree-expand,.wy-menu-vertical li.toctree-l6 a:hover span.toctree-expand,.wy-menu-vertical li.toctree-l7 a:hover span.toctree-expand,.wy-menu-vertical li.toctree-l8 a:hover span.toctree-expand,.wy-menu-vertical li.toctree-l9 a:hover span.toctree-expand,.wy-menu-vertical li.toctree-l10 a:hover span.toctree-expand{color:grey}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a,.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a,.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a,.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a,.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a,.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a,.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a,.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{display:block}.wy-menu-vertical li.toctree-l2.current>a{padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a,.wy-menu-vertical li.toctree-l3.current>a{padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a,.wy-menu-vertical li.toctree-l4.current>a{padding:.4045em 5.663em}.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a,.wy-menu-vertical li.toctree-l5.current>a{padding:.4045em 7.281em}.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a,.wy-menu-vertical li.toctree-l6.current>a{padding:.4045em 8.899em}.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a,.wy-menu-vertical li.toctree-l7.current>a{padding:.4045em 10.517em}.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a,.wy-menu-vertical li.toctree-l8.current>a{padding:.4045em 12.135em}.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a,.wy-menu-vertical li.toctree-l9.current>a{padding:.4045em 13.753em}.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a,.wy-menu-vertical li.toctree-l10.current>a{padding:.4045em 15.371em}.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{padding:.4045em 16.989em}.wy-menu-vertical li.toctree-l2.current>a,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{background:#c9c9c9}.wy-menu-vertical li.toctree-l2 span.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3.current>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{background:#bdbdbd}.wy-menu-vertical li.toctree-l3 span.toctree-expand{color:#969696}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical li ul li a{margin-bottom:0;color:#d9d9d9;font-weight:400}.wy-menu-vertical a{line-height:18px;padding:.4045em 1.618em;display:block;position:relative;font-size:90%;color:#d9d9d9}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover span.toctree-expand{color:#d9d9d9}.wy-menu-vertical a:active{background-color:#2980b9;cursor:pointer;color:#fff}.wy-menu-vertical a:active span.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:.809em;margin-bottom:.809em;z-index:200;background-color:#2980b9;text-align:center;color:#fcfcfc}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto .809em;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-side-nav-search .wy-dropdown>a,.wy-side-nav-search>a{color:#fcfcfc;font-size:100%;font-weight:700;display:inline-block;padding:4px 6px;margin-bottom:.809em}.wy-side-nav-search .wy-dropdown>a:hover,.wy-side-nav-search>a:hover{background:hsla(0,0%,100%,.1)}.wy-side-nav-search .wy-dropdown>a img.logo,.wy-side-nav-search>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search .wy-dropdown>a.icon img.logo,.wy-side-nav-search>a.icon img.logo{margin-top:.85em}.wy-side-nav-search>div.version{margin-top:-.4045em;margin-bottom:.809em;font-weight:400;color:hsla(0,0%,100%,.3)}.wy-nav .wy-menu-vertical header{color:#2980b9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980b9;color:#fff}[data-menu-wrap]{-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;transition:all .2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:#fcfcfc}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;color:#9b9b9b;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980b9;color:#fff;padding:.4045em .809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:after,.wy-nav-top:before{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:700}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:grey}footer p{margin-bottom:12px}.rst-content footer span.commit tt,footer span.commit .rst-content tt,footer span.commit code{padding:0;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:1em;background:none;border:none;color:grey}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:after,.rst-footer-buttons:before{width:100%;display:table;content:""}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:after,.rst-breadcrumbs-buttons:before{display:table;content:""}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:1px solid #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:1px solid #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:grey;font-size:90%}.genindextable li>ul{margin-left:24px}@media screen and (max-width:768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-menu.wy-menu-vertical,.wy-side-nav-search,.wy-side-scroll{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width:1100px){.wy-nav-content-wrap{background:rgba(0,0,0,.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,.wy-nav-side,footer{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60;*zoom:1}.rst-versions .rst-current-version:after,.rst-versions .rst-current-version:before{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-content .code-block-caption .rst-versions .rst-current-version .headerlink,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-content p.caption .rst-versions .rst-current-version .headerlink,.rst-content table>caption .rst-versions .rst-current-version .headerlink,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .icon,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-versions .rst-current-version .rst-content .code-block-caption .headerlink,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-versions .rst-current-version .rst-content p.caption .headerlink,.rst-versions .rst-current-version .rst-content table>caption .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-versions .rst-current-version .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version span.toctree-expand{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}.rst-content img{max-width:100%;height:auto}.rst-content div.figure{margin-bottom:24px}.rst-content div.figure p.caption{font-style:italic}.rst-content div.figure p:last-child.caption{margin-bottom:0}.rst-content div.figure.align-center{text-align:center}.rst-content .section>a>img,.rst-content .section>img{margin-bottom:24px}.rst-content abbr[title]{text-decoration:none}.rst-content.style-external-links a.reference.external:after{font-family:FontAwesome;content:"\f08e";color:#b3b3b3;vertical-align:super;font-size:60%;margin:0 .2em}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content pre.literal-block{white-space:pre;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;display:block;overflow:auto}.rst-content div[class^=highlight],.rst-content pre.literal-block{border:1px solid #e1e4e5;overflow-x:auto;margin:1px 0 24px}.rst-content div[class^=highlight] div[class^=highlight],.rst-content pre.literal-block div[class^=highlight]{padding:0;border:none;margin:0}.rst-content div[class^=highlight] td.code{width:100%}.rst-content .linenodiv pre{border-right:1px solid #e6e9ea;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;user-select:none;pointer-events:none}.rst-content div[class^=highlight] pre{white-space:pre;margin:0;padding:12px;display:block;overflow:auto}.rst-content div[class^=highlight] pre .hll{display:block;margin:0 -12px;padding:0 12px}.rst-content .linenodiv pre,.rst-content div[class^=highlight] pre,.rst-content pre.literal-block{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:12px;line-height:1.4}.rst-content div.highlight .gp{user-select:none;pointer-events:none}.rst-content .code-block-caption{font-style:italic;font-size:85%;line-height:1;padding:1em 0;text-align:center}@media print{.rst-content .codeblock,.rst-content div[class^=highlight],.rst-content div[class^=highlight] pre{white-space:pre-wrap}}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning{clear:both}.rst-content .admonition-todo .last,.rst-content .admonition-todo>:last-child,.rst-content .admonition .last,.rst-content .admonition>:last-child,.rst-content .attention .last,.rst-content .attention>:last-child,.rst-content .caution .last,.rst-content .caution>:last-child,.rst-content .danger .last,.rst-content .danger>:last-child,.rst-content .error .last,.rst-content .error>:last-child,.rst-content .hint .last,.rst-content .hint>:last-child,.rst-content .important .last,.rst-content .important>:last-child,.rst-content .note .last,.rst-content .note>:last-child,.rst-content .seealso .last,.rst-content .seealso>:last-child,.rst-content .tip .last,.rst-content .tip>:last-child,.rst-content .warning .last,.rst-content .warning>:last-child{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent!important;border-color:rgba(0,0,0,.1)!important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha>li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha>li{list-style:upper-alpha}.rst-content .section ol li>*,.rst-content .section ul li>*{margin-top:12px;margin-bottom:12px}.rst-content .section ol li>:first-child,.rst-content .section ul li>:first-child{margin-top:0}.rst-content .section ol li>p,.rst-content .section ol li>p:last-child,.rst-content .section ul li>p,.rst-content .section ul li>p:last-child{margin-bottom:12px}.rst-content .section ol li>p:only-child,.rst-content .section ol li>p:only-child:last-child,.rst-content .section ul li>p:only-child,.rst-content .section ul li>p:only-child:last-child{margin-bottom:0}.rst-content .section ol li>ol,.rst-content .section ol li>ul,.rst-content .section ul li>ol,.rst-content .section ul li>ul{margin-bottom:12px}.rst-content .section ol.simple li>*,.rst-content .section ol.simple li ol,.rst-content .section ol.simple li ul,.rst-content .section ul.simple li>*,.rst-content .section ul.simple li ol,.rst-content .section ul.simple li ul{margin-top:0;margin-bottom:0}.rst-content .line-block{margin-left:0;margin-bottom:24px;line-height:24px}.rst-content .line-block .line-block{margin-left:24px;margin-bottom:0}.rst-content .topic-title{font-weight:700;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0 0 24px 24px}.rst-content .align-left{float:left;margin:0 24px 24px 0}.rst-content .align-center{margin:auto}.rst-content .align-center:not(table){display:block}.rst-content .code-block-caption .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content table>caption .headerlink{visibility:hidden;font-size:14px}.rst-content .code-block-caption .headerlink:after,.rst-content .toctree-wrapper>p.caption .headerlink:after,.rst-content dl dt .headerlink:after,.rst-content h1 .headerlink:after,.rst-content h2 .headerlink:after,.rst-content h3 .headerlink:after,.rst-content h4 .headerlink:after,.rst-content h5 .headerlink:after,.rst-content h6 .headerlink:after,.rst-content p.caption .headerlink:after,.rst-content table>caption .headerlink:after{content:"\f0c1";font-family:FontAwesome}.rst-content .code-block-caption:hover .headerlink:after,.rst-content .toctree-wrapper>p.caption:hover .headerlink:after,.rst-content dl dt:hover .headerlink:after,.rst-content h1:hover .headerlink:after,.rst-content h2:hover .headerlink:after,.rst-content h3:hover .headerlink:after,.rst-content h4:hover .headerlink:after,.rst-content h5:hover .headerlink:after,.rst-content h6:hover .headerlink:after,.rst-content p.caption:hover .headerlink:after,.rst-content table>caption:hover .headerlink:after{visibility:visible}.rst-content table>caption .headerlink:after{font-size:12px}.rst-content .centered{text-align:center}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:1px solid #e1e4e5}.rst-content .sidebar dl,.rst-content .sidebar p,.rst-content .sidebar ul{font-size:90%}.rst-content .sidebar .last,.rst-content .sidebar>:last-child{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif;font-weight:700;background:#e1e4e5;padding:6px 12px;margin:-24px -24px 24px;font-size:100%}.rst-content .highlighted{background:#f1c40f;box-shadow:0 0 0 2px #f1c40f;display:inline;font-weight:700}.rst-content .citation-reference,.rst-content .footnote-reference{vertical-align:baseline;position:relative;top:-.4em;line-height:0;font-size:90%}.rst-content .hlist{width:100%}html.writer-html4 .rst-content table.docutils.citation,html.writer-html4 .rst-content table.docutils.footnote{background:none;border:none}html.writer-html4 .rst-content table.docutils.citation td,html.writer-html4 .rst-content table.docutils.citation tr,html.writer-html4 .rst-content table.docutils.footnote td,html.writer-html4 .rst-content table.docutils.footnote tr{border:none;background-color:transparent!important;white-space:normal}html.writer-html4 .rst-content table.docutils.citation td.label,html.writer-html4 .rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}html.writer-html5 .rst-content dl dt span.classifier:before{content:" : "}html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{display:grid;grid-template-columns:max-content auto}html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{padding-left:1rem}html.writer-html5 .rst-content dl.field-list>dt:after,html.writer-html5 .rst-content dl.footnote>dt:after{content:":"}html.writer-html5 .rst-content dl.field-list>dd,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dd,html.writer-html5 .rst-content dl.footnote>dt{margin-bottom:0}html.writer-html5 .rst-content dl.footnote{font-size:.9rem}html.writer-html5 .rst-content dl.footnote>dt{margin:0 .5rem .5rem 0;line-height:1.2rem;word-break:break-all;font-weight:400}html.writer-html5 .rst-content dl.footnote>dt>span.brackets{margin-right:.5rem}html.writer-html5 .rst-content dl.footnote>dt>span.brackets:before{content:"["}html.writer-html5 .rst-content dl.footnote>dt>span.brackets:after{content:"]"}html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref{font-style:italic}html.writer-html5 .rst-content dl.footnote>dd{margin:0 0 .5rem;line-height:1.2rem}html.writer-html5 .rst-content dl.footnote>dd p,html.writer-html5 .rst-content dl.option-list kbd{font-size:.9rem}.rst-content table.docutils.footnote,html.writer-html4 .rst-content table.docutils.citation,html.writer-html5 .rst-content dl.footnote{color:grey}.rst-content table.docutils.footnote code,.rst-content table.docutils.footnote tt,html.writer-html4 .rst-content table.docutils.citation code,html.writer-html4 .rst-content table.docutils.citation tt,html.writer-html5 .rst-content dl.footnote code,html.writer-html5 .rst-content dl.footnote tt{color:#555}.rst-content .wy-table-responsive.citation,.rst-content .wy-table-responsive.footnote{margin-bottom:0}.rst-content .wy-table-responsive.citation+:not(.citation),.rst-content .wy-table-responsive.footnote+:not(.footnote){margin-top:24px}.rst-content .wy-table-responsive.citation:last-child,.rst-content .wy-table-responsive.footnote:last-child{margin-bottom:24px}.rst-content table.docutils th{border-color:#e1e4e5}html.writer-html5 .rst-content table.docutils th{border:1px solid #e1e4e5}html.writer-html5 .rst-content table.docutils td>p,html.writer-html5 .rst-content table.docutils th>p{line-height:1rem;margin-bottom:0;font-size:.9rem}.rst-content table.docutils td .last,.rst-content table.docutils td .last>:last-child{margin-bottom:0}.rst-content table.field-list,.rst-content table.field-list td{border:none}.rst-content table.field-list td p{font-size:inherit;line-height:inherit}.rst-content table.field-list td>strong{display:inline-block}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left}.rst-content code,.rst-content tt{color:#000;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;padding:2px 5px}.rst-content code big,.rst-content code em,.rst-content tt big,.rst-content tt em{font-size:100%!important;line-height:normal}.rst-content code.literal,.rst-content tt.literal{color:#e74c3c}.rst-content code.xref,.rst-content tt.xref,a .rst-content code,a .rst-content tt{font-weight:700;color:#404040}.rst-content kbd,.rst-content pre,.rst-content samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace}.rst-content a code,.rst-content a tt{color:#2980b9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:700;margin-bottom:12px}.rst-content dl ol,.rst-content dl p,.rst-content dl table,.rst-content dl ul{margin-bottom:12px}.rst-content dl dd{margin:0 0 12px 24px;line-height:24px}html.writer-html4 .rst-content dl:not(.docutils),html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple){margin-bottom:24px}html.writer-html4 .rst-content dl:not(.docutils)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)>dt{display:table;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980b9;border-top:3px solid #6ab0de;padding:6px;position:relative}html.writer-html4 .rst-content dl:not(.docutils)>dt:before,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)>dt:before{color:#6ab0de}html.writer-html4 .rst-content dl:not(.docutils)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.field-list)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dl:not(.field-list)>dt{margin-bottom:6px;border:none;border-left:3px solid #ccc;background:#f0f0f0;color:#555}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.field-list)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dl:not(.field-list)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils)>dt:first-child,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)>dt:first-child{margin-top:0}html.writer-html4 .rst-content dl:not(.docutils) code,html.writer-html4 .rst-content dl:not(.docutils) tt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) code,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) tt{font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) code.descclassname,html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descclassname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) code.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) tt.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) tt.descname{background-color:transparent;border:none;padding:0;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) tt.descname{font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .optional,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .property,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .property{display:inline-block;padding-right:8px}.rst-content .viewcode-back,.rst-content .viewcode-link{display:inline-block;color:#27ae60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:700}.rst-content code.download,.rst-content tt.download{background:inherit;padding:inherit;font-weight:400;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content code.download span:first-child,.rst-content tt.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{margin-right:4px}.rst-content .guilabel{border:1px solid #7fbbe3;background:#e7f2fa;font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.rst-content .versionmodified{font-style:italic}@media screen and (max-width:480px){.rst-content .sidebar{width:100%}}span[id*=MathJax-Span]{color:#404040}.math{text-align:center}@font-face{font-family:Lato;src:url(fonts/lato-normal.woff2?bd03a2cc277bbbc338d464e679fe9942) format("woff2"),url(fonts/lato-normal.woff?27bd77b9162d388cb8d4c4217c7c5e2a) format("woff");font-weight:400;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold.woff2?cccb897485813c7c256901dbca54ecf2) format("woff2"),url(fonts/lato-bold.woff?d878b6c29b10beca227e9eef4246111b) format("woff");font-weight:700;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold-italic.woff2?0b6bb6725576b072c5d0b02ecdd1900d) format("woff2"),url(fonts/lato-bold-italic.woff?9c7e4e9eb485b4a121c760e61bc3707c) format("woff");font-weight:700;font-style:italic;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-normal-italic.woff2?4eb103b4d12be57cb1d040ed5e162e9d) format("woff2"),url(fonts/lato-normal-italic.woff?f28f2d6482446544ef1ea1ccc6dd5892) format("woff");font-weight:400;font-style:italic;font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:400;src:url(fonts/Roboto-Slab-Regular.woff2?7abf5b8d04d26a2cafea937019bca958) format("woff2"),url(fonts/Roboto-Slab-Regular.woff?c1be9284088d487c5e3ff0a10a92e58c) format("woff");font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:700;src:url(fonts/Roboto-Slab-Bold.woff2?9984f4a9bda09be08e83f2506954adbe) format("woff2"),url(fonts/Roboto-Slab-Bold.woff?bed5564a116b05148e3b3bea6fb1162a) format("woff");font-display:block} \ No newline at end of file + */@font-face{font-family:FontAwesome;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713);src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix&v=4.7.0) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#fontawesomeregular) format("svg");font-weight:400;font-style:normal}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa-pull-left.icon,.fa.fa-pull-left,.rst-content .code-block-caption .fa-pull-left.headerlink,.rst-content .eqno .fa-pull-left.headerlink,.rst-content .fa-pull-left.admonition-title,.rst-content code.download span.fa-pull-left:first-child,.rst-content dl dt .fa-pull-left.headerlink,.rst-content h1 .fa-pull-left.headerlink,.rst-content h2 .fa-pull-left.headerlink,.rst-content h3 .fa-pull-left.headerlink,.rst-content h4 .fa-pull-left.headerlink,.rst-content h5 .fa-pull-left.headerlink,.rst-content h6 .fa-pull-left.headerlink,.rst-content p .fa-pull-left.headerlink,.rst-content table>caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.wy-menu-vertical li.current>a button.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-left.toctree-expand,.wy-menu-vertical li button.fa-pull-left.toctree-expand{margin-right:.3em}.fa-pull-right.icon,.fa.fa-pull-right,.rst-content .code-block-caption .fa-pull-right.headerlink,.rst-content .eqno .fa-pull-right.headerlink,.rst-content .fa-pull-right.admonition-title,.rst-content code.download span.fa-pull-right:first-child,.rst-content dl dt .fa-pull-right.headerlink,.rst-content h1 .fa-pull-right.headerlink,.rst-content h2 .fa-pull-right.headerlink,.rst-content h3 .fa-pull-right.headerlink,.rst-content h4 .fa-pull-right.headerlink,.rst-content h5 .fa-pull-right.headerlink,.rst-content h6 .fa-pull-right.headerlink,.rst-content p .fa-pull-right.headerlink,.rst-content table>caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.wy-menu-vertical li.current>a button.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-right.toctree-expand,.wy-menu-vertical li button.fa-pull-right.toctree-expand{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.pull-left.icon,.rst-content .code-block-caption .pull-left.headerlink,.rst-content .eqno .pull-left.headerlink,.rst-content .pull-left.admonition-title,.rst-content code.download span.pull-left:first-child,.rst-content dl dt .pull-left.headerlink,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content p .pull-left.headerlink,.rst-content table>caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.wy-menu-vertical li.current>a button.pull-left.toctree-expand,.wy-menu-vertical li.on a button.pull-left.toctree-expand,.wy-menu-vertical li button.pull-left.toctree-expand{margin-right:.3em}.fa.pull-right,.pull-right.icon,.rst-content .code-block-caption .pull-right.headerlink,.rst-content .eqno .pull-right.headerlink,.rst-content .pull-right.admonition-title,.rst-content code.download span.pull-right:first-child,.rst-content dl dt .pull-right.headerlink,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content p .pull-right.headerlink,.rst-content table>caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.wy-menu-vertical li.current>a button.pull-right.toctree-expand,.wy-menu-vertical li.on a button.pull-right.toctree-expand,.wy-menu-vertical li button.pull-right.toctree-expand{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);-ms-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scaleY(-1);-ms-transform:scaleY(-1);transform:scaleY(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-close:before,.fa-remove:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-cog:before,.fa-gear:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-repeat:before,.fa-rotate-right:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.rst-content .admonition-title:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-exclamation-triangle:before,.fa-warning:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-cogs:before,.fa-gears:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook-f:before,.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-feed:before,.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-floppy-o:before,.fa-save:before{content:""}.fa-square:before{content:""}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.icon-caret-down:before,.wy-dropdown .caret:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-sort:before,.fa-unsorted:before{content:""}.fa-sort-desc:before,.fa-sort-down:before{content:""}.fa-sort-asc:before,.fa-sort-up:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-gavel:before,.fa-legal:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-bolt:before,.fa-flash:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-clipboard:before,.fa-paste:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-chain-broken:before,.fa-unlink:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:""}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:""}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:""}.fa-eur:before,.fa-euro:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-inr:before,.fa-rupee:before{content:""}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:""}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:""}.fa-krw:before,.fa-won:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-try:before,.fa-turkish-lira:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li button.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-bank:before,.fa-institution:before,.fa-university:before{content:""}.fa-graduation-cap:before,.fa-mortar-board:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper-pp:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:""}.fa-file-archive-o:before,.fa-file-zip-o:before{content:""}.fa-file-audio-o:before,.fa-file-sound-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-rebel:before,.fa-resistance:before{content:""}.fa-empire:before,.fa-ge:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-hacker-news:before,.fa-y-combinator-square:before,.fa-yc-square:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-paper-plane:before,.fa-send:before{content:""}.fa-paper-plane-o:before,.fa-send-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:""}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:""}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:""}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-bed:before,.fa-hotel:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-y-combinator:before,.fa-yc:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery-full:before,.fa-battery:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:""}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:""}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:""}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-paper-o:before,.fa-hand-stop-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:""}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-television:before,.fa-tv:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:""}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:""}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:""}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}.fa-gitlab:before,.icon-gitlab:before{content:""}.fa-wpbeginner:before{content:""}.fa-wpforms:before{content:""}.fa-envira:before{content:""}.fa-universal-access:before{content:""}.fa-wheelchair-alt:before{content:""}.fa-question-circle-o:before{content:""}.fa-blind:before{content:""}.fa-audio-description:before{content:""}.fa-volume-control-phone:before{content:""}.fa-braille:before{content:""}.fa-assistive-listening-systems:before{content:""}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before{content:""}.fa-deaf:before,.fa-deafness:before,.fa-hard-of-hearing:before{content:""}.fa-glide:before{content:""}.fa-glide-g:before{content:""}.fa-sign-language:before,.fa-signing:before{content:""}.fa-low-vision:before{content:""}.fa-viadeo:before{content:""}.fa-viadeo-square:before{content:""}.fa-snapchat:before{content:""}.fa-snapchat-ghost:before{content:""}.fa-snapchat-square:before{content:""}.fa-pied-piper:before{content:""}.fa-first-order:before{content:""}.fa-yoast:before{content:""}.fa-themeisle:before{content:""}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:""}.fa-fa:before,.fa-font-awesome:before{content:""}.fa-handshake-o:before{content:""}.fa-envelope-open:before{content:""}.fa-envelope-open-o:before{content:""}.fa-linode:before{content:""}.fa-address-book:before{content:""}.fa-address-book-o:before{content:""}.fa-address-card:before,.fa-vcard:before{content:""}.fa-address-card-o:before,.fa-vcard-o:before{content:""}.fa-user-circle:before{content:""}.fa-user-circle-o:before{content:""}.fa-user-o:before{content:""}.fa-id-badge:before{content:""}.fa-drivers-license:before,.fa-id-card:before{content:""}.fa-drivers-license-o:before,.fa-id-card-o:before{content:""}.fa-quora:before{content:""}.fa-free-code-camp:before{content:""}.fa-telegram:before{content:""}.fa-thermometer-4:before,.fa-thermometer-full:before,.fa-thermometer:before{content:""}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:""}.fa-thermometer-2:before,.fa-thermometer-half:before{content:""}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:""}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:""}.fa-shower:before{content:""}.fa-bath:before,.fa-bathtub:before,.fa-s15:before{content:""}.fa-podcast:before{content:""}.fa-window-maximize:before{content:""}.fa-window-minimize:before{content:""}.fa-window-restore:before{content:""}.fa-times-rectangle:before,.fa-window-close:before{content:""}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:""}.fa-bandcamp:before{content:""}.fa-grav:before{content:""}.fa-etsy:before{content:""}.fa-imdb:before{content:""}.fa-ravelry:before{content:""}.fa-eercast:before{content:""}.fa-microchip:before{content:""}.fa-snowflake-o:before{content:""}.fa-superpowers:before{content:""}.fa-wpexplorer:before{content:""}.fa-meetup:before{content:""}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{font-family:inherit}.fa:before,.icon:before,.rst-content .admonition-title:before,.rst-content .code-block-caption .headerlink:before,.rst-content .eqno .headerlink:before,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before{font-family:FontAwesome;display:inline-block;font-style:normal;font-weight:400;line-height:1;text-decoration:inherit}.rst-content .code-block-caption a .headerlink,.rst-content .eqno a .headerlink,.rst-content a .admonition-title,.rst-content code.download a span:first-child,.rst-content dl dt a .headerlink,.rst-content h1 a .headerlink,.rst-content h2 a .headerlink,.rst-content h3 a .headerlink,.rst-content h4 a .headerlink,.rst-content h5 a .headerlink,.rst-content h6 a .headerlink,.rst-content p.caption a .headerlink,.rst-content p a .headerlink,.rst-content table>caption a .headerlink,.rst-content tt.download a span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li a button.toctree-expand,a .fa,a .icon,a .rst-content .admonition-title,a .rst-content .code-block-caption .headerlink,a .rst-content .eqno .headerlink,a .rst-content code.download span:first-child,a .rst-content dl dt .headerlink,a .rst-content h1 .headerlink,a .rst-content h2 .headerlink,a .rst-content h3 .headerlink,a .rst-content h4 .headerlink,a .rst-content h5 .headerlink,a .rst-content h6 .headerlink,a .rst-content p.caption .headerlink,a .rst-content p .headerlink,a .rst-content table>caption .headerlink,a .rst-content tt.download span:first-child,a .wy-menu-vertical li button.toctree-expand{display:inline-block;text-decoration:inherit}.btn .fa,.btn .icon,.btn .rst-content .admonition-title,.btn .rst-content .code-block-caption .headerlink,.btn .rst-content .eqno .headerlink,.btn .rst-content code.download span:first-child,.btn .rst-content dl dt .headerlink,.btn .rst-content h1 .headerlink,.btn .rst-content h2 .headerlink,.btn .rst-content h3 .headerlink,.btn .rst-content h4 .headerlink,.btn .rst-content h5 .headerlink,.btn .rst-content h6 .headerlink,.btn .rst-content p .headerlink,.btn .rst-content table>caption .headerlink,.btn .rst-content tt.download span:first-child,.btn .wy-menu-vertical li.current>a button.toctree-expand,.btn .wy-menu-vertical li.on a button.toctree-expand,.btn .wy-menu-vertical li button.toctree-expand,.nav .fa,.nav .icon,.nav .rst-content .admonition-title,.nav .rst-content .code-block-caption .headerlink,.nav .rst-content .eqno .headerlink,.nav .rst-content code.download span:first-child,.nav .rst-content dl dt .headerlink,.nav .rst-content h1 .headerlink,.nav .rst-content h2 .headerlink,.nav .rst-content h3 .headerlink,.nav .rst-content h4 .headerlink,.nav .rst-content h5 .headerlink,.nav .rst-content h6 .headerlink,.nav .rst-content p .headerlink,.nav .rst-content table>caption .headerlink,.nav .rst-content tt.download span:first-child,.nav .wy-menu-vertical li.current>a button.toctree-expand,.nav .wy-menu-vertical li.on a button.toctree-expand,.nav .wy-menu-vertical li button.toctree-expand,.rst-content .btn .admonition-title,.rst-content .code-block-caption .btn .headerlink,.rst-content .code-block-caption .nav .headerlink,.rst-content .eqno .btn .headerlink,.rst-content .eqno .nav .headerlink,.rst-content .nav .admonition-title,.rst-content code.download .btn span:first-child,.rst-content code.download .nav span:first-child,.rst-content dl dt .btn .headerlink,.rst-content dl dt .nav .headerlink,.rst-content h1 .btn .headerlink,.rst-content h1 .nav .headerlink,.rst-content h2 .btn .headerlink,.rst-content h2 .nav .headerlink,.rst-content h3 .btn .headerlink,.rst-content h3 .nav .headerlink,.rst-content h4 .btn .headerlink,.rst-content h4 .nav .headerlink,.rst-content h5 .btn .headerlink,.rst-content h5 .nav .headerlink,.rst-content h6 .btn .headerlink,.rst-content h6 .nav .headerlink,.rst-content p .btn .headerlink,.rst-content p .nav .headerlink,.rst-content table>caption .btn .headerlink,.rst-content table>caption .nav .headerlink,.rst-content tt.download .btn span:first-child,.rst-content tt.download .nav span:first-child,.wy-menu-vertical li .btn button.toctree-expand,.wy-menu-vertical li.current>a .btn button.toctree-expand,.wy-menu-vertical li.current>a .nav button.toctree-expand,.wy-menu-vertical li .nav button.toctree-expand,.wy-menu-vertical li.on a .btn button.toctree-expand,.wy-menu-vertical li.on a .nav button.toctree-expand{display:inline}.btn .fa-large.icon,.btn .fa.fa-large,.btn .rst-content .code-block-caption .fa-large.headerlink,.btn .rst-content .eqno .fa-large.headerlink,.btn .rst-content .fa-large.admonition-title,.btn .rst-content code.download span.fa-large:first-child,.btn .rst-content dl dt .fa-large.headerlink,.btn .rst-content h1 .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.btn .rst-content p .fa-large.headerlink,.btn .rst-content table>caption .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.btn .wy-menu-vertical li button.fa-large.toctree-expand,.nav .fa-large.icon,.nav .fa.fa-large,.nav .rst-content .code-block-caption .fa-large.headerlink,.nav .rst-content .eqno .fa-large.headerlink,.nav .rst-content .fa-large.admonition-title,.nav .rst-content code.download span.fa-large:first-child,.nav .rst-content dl dt .fa-large.headerlink,.nav .rst-content h1 .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.nav .rst-content p .fa-large.headerlink,.nav .rst-content table>caption .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.nav .wy-menu-vertical li button.fa-large.toctree-expand,.rst-content .btn .fa-large.admonition-title,.rst-content .code-block-caption .btn .fa-large.headerlink,.rst-content .code-block-caption .nav .fa-large.headerlink,.rst-content .eqno .btn .fa-large.headerlink,.rst-content .eqno .nav .fa-large.headerlink,.rst-content .nav .fa-large.admonition-title,.rst-content code.download .btn span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.rst-content dl dt .btn .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.rst-content p .btn .fa-large.headerlink,.rst-content p .nav .fa-large.headerlink,.rst-content table>caption .btn .fa-large.headerlink,.rst-content table>caption .nav .fa-large.headerlink,.rst-content tt.download .btn span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.wy-menu-vertical li .btn button.fa-large.toctree-expand,.wy-menu-vertical li .nav button.fa-large.toctree-expand{line-height:.9em}.btn .fa-spin.icon,.btn .fa.fa-spin,.btn .rst-content .code-block-caption .fa-spin.headerlink,.btn .rst-content .eqno .fa-spin.headerlink,.btn .rst-content .fa-spin.admonition-title,.btn .rst-content code.download span.fa-spin:first-child,.btn .rst-content dl dt .fa-spin.headerlink,.btn .rst-content h1 .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.btn .rst-content p .fa-spin.headerlink,.btn .rst-content table>caption .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.btn .wy-menu-vertical li button.fa-spin.toctree-expand,.nav .fa-spin.icon,.nav .fa.fa-spin,.nav .rst-content .code-block-caption .fa-spin.headerlink,.nav .rst-content .eqno .fa-spin.headerlink,.nav .rst-content .fa-spin.admonition-title,.nav .rst-content code.download span.fa-spin:first-child,.nav .rst-content dl dt .fa-spin.headerlink,.nav .rst-content h1 .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.nav .rst-content p .fa-spin.headerlink,.nav .rst-content table>caption .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.nav .wy-menu-vertical li button.fa-spin.toctree-expand,.rst-content .btn .fa-spin.admonition-title,.rst-content .code-block-caption .btn .fa-spin.headerlink,.rst-content .code-block-caption .nav .fa-spin.headerlink,.rst-content .eqno .btn .fa-spin.headerlink,.rst-content .eqno .nav .fa-spin.headerlink,.rst-content .nav .fa-spin.admonition-title,.rst-content code.download .btn span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.rst-content dl dt .btn .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.rst-content p .btn .fa-spin.headerlink,.rst-content p .nav .fa-spin.headerlink,.rst-content table>caption .btn .fa-spin.headerlink,.rst-content table>caption .nav .fa-spin.headerlink,.rst-content tt.download .btn span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.wy-menu-vertical li .btn button.fa-spin.toctree-expand,.wy-menu-vertical li .nav button.fa-spin.toctree-expand{display:inline-block}.btn.fa:before,.btn.icon:before,.rst-content .btn.admonition-title:before,.rst-content .code-block-caption .btn.headerlink:before,.rst-content .eqno .btn.headerlink:before,.rst-content code.download span.btn:first-child:before,.rst-content dl dt .btn.headerlink:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content p .btn.headerlink:before,.rst-content table>caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.wy-menu-vertical li button.btn.toctree-expand:before{opacity:.5;-webkit-transition:opacity .05s ease-in;-moz-transition:opacity .05s ease-in;transition:opacity .05s ease-in}.btn.fa:hover:before,.btn.icon:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content .code-block-caption .btn.headerlink:hover:before,.rst-content .eqno .btn.headerlink:hover:before,.rst-content code.download span.btn:first-child:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content p .btn.headerlink:hover:before,.rst-content table>caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.wy-menu-vertical li button.btn.toctree-expand:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .icon:before,.btn-mini .rst-content .admonition-title:before,.btn-mini .rst-content .code-block-caption .headerlink:before,.btn-mini .rst-content .eqno .headerlink:before,.btn-mini .rst-content code.download span:first-child:before,.btn-mini .rst-content dl dt .headerlink:before,.btn-mini .rst-content h1 .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.btn-mini .rst-content p .headerlink:before,.btn-mini .rst-content table>caption .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.btn-mini .wy-menu-vertical li button.toctree-expand:before,.rst-content .btn-mini .admonition-title:before,.rst-content .code-block-caption .btn-mini .headerlink:before,.rst-content .eqno .btn-mini .headerlink:before,.rst-content code.download .btn-mini span:first-child:before,.rst-content dl dt .btn-mini .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.rst-content p .btn-mini .headerlink:before,.rst-content table>caption .btn-mini .headerlink:before,.rst-content tt.download .btn-mini span:first-child:before,.wy-menu-vertical li .btn-mini button.toctree-expand:before{font-size:14px;vertical-align:-15%}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.wy-alert{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.rst-content .admonition-title,.wy-alert-title{font-weight:700;display:block;color:#fff;background:#6ab0de;padding:6px 12px;margin:-12px -12px 12px}.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.admonition,.rst-content .wy-alert-danger.admonition-todo,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.wy-alert.wy-alert-danger{background:#fdf3f2}.rst-content .danger .admonition-title,.rst-content .danger .wy-alert-title,.rst-content .error .admonition-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.rst-content .wy-alert-danger.admonition .admonition-title,.rst-content .wy-alert-danger.admonition .wy-alert-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.wy-alert.wy-alert-danger .wy-alert-title{background:#f29f97}.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .warning,.rst-content .wy-alert-warning.admonition,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.note,.rst-content .wy-alert-warning.seealso,.rst-content .wy-alert-warning.tip,.wy-alert.wy-alert-warning{background:#ffedcc}.rst-content .admonition-todo .admonition-title,.rst-content .admonition-todo .wy-alert-title,.rst-content .attention .admonition-title,.rst-content .attention .wy-alert-title,.rst-content .caution .admonition-title,.rst-content .caution .wy-alert-title,.rst-content .warning .admonition-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.admonition .admonition-title,.rst-content .wy-alert-warning.admonition .wy-alert-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.wy-alert.wy-alert-warning .wy-alert-title{background:#f0b37e}.rst-content .note,.rst-content .seealso,.rst-content .wy-alert-info.admonition,.rst-content .wy-alert-info.admonition-todo,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.wy-alert.wy-alert-info{background:#e7f2fa}.rst-content .note .admonition-title,.rst-content .note .wy-alert-title,.rst-content .seealso .admonition-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .admonition-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.rst-content .wy-alert-info.admonition .admonition-title,.rst-content .wy-alert-info.admonition .wy-alert-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.wy-alert.wy-alert-info .wy-alert-title{background:#6ab0de}.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.admonition,.rst-content .wy-alert-success.admonition-todo,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.warning,.wy-alert.wy-alert-success{background:#dbfaf4}.rst-content .hint .admonition-title,.rst-content .hint .wy-alert-title,.rst-content .important .admonition-title,.rst-content .important .wy-alert-title,.rst-content .tip .admonition-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .admonition-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.rst-content .wy-alert-success.admonition .admonition-title,.rst-content .wy-alert-success.admonition .wy-alert-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.wy-alert.wy-alert-success .wy-alert-title{background:#1abc9c}.rst-content .wy-alert-neutral.admonition,.rst-content .wy-alert-neutral.admonition-todo,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.wy-alert.wy-alert-neutral{background:#f3f6f6}.rst-content .wy-alert-neutral.admonition-todo .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.rst-content .wy-alert-neutral.admonition .admonition-title,.rst-content .wy-alert-neutral.admonition .wy-alert-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.wy-alert.wy-alert-neutral .wy-alert-title{color:#404040;background:#e1e4e5}.rst-content .wy-alert-neutral.admonition-todo a,.rst-content .wy-alert-neutral.admonition a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.wy-alert.wy-alert-neutral a{color:#2980b9}.rst-content .admonition-todo p:last-child,.rst-content .admonition p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .note p:last-child,.rst-content .seealso p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.wy-alert p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all .3s ease-in;-moz-transition:all .3s ease-in;transition:all .3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27ae60}.wy-tray-container li.wy-tray-item-info{background:#2980b9}.wy-tray-container li.wy-tray-item-warning{background:#e67e22}.wy-tray-container li.wy-tray-item-danger{background:#e74c3c}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width:768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px;color:#fff;border:1px solid rgba(0,0,0,.1);background-color:#27ae60;text-decoration:none;font-weight:400;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 2px -1px hsla(0,0%,100%,.5),inset 0 -2px 0 0 rgba(0,0,0,.1);outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;transition:all .1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:inset 0 -1px 0 0 rgba(0,0,0,.05),inset 0 2px 0 0 rgba(0,0,0,.1);padding:8px 12px 6px}.btn:visited{color:#fff}.btn-disabled,.btn-disabled:active,.btn-disabled:focus,.btn-disabled:hover,.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980b9!important}.btn-info:hover{background-color:#2e8ece!important}.btn-neutral{background-color:#f3f6f6!important;color:#404040!important}.btn-neutral:hover{background-color:#e5ebeb!important;color:#404040}.btn-neutral:visited{color:#404040!important}.btn-success{background-color:#27ae60!important}.btn-success:hover{background-color:#295!important}.btn-danger{background-color:#e74c3c!important}.btn-danger:hover{background-color:#ea6153!important}.btn-warning{background-color:#e67e22!important}.btn-warning:hover{background-color:#e98b39!important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f!important}.btn-link{background-color:transparent!important;color:#2980b9;box-shadow:none;border-color:transparent!important}.btn-link:active,.btn-link:hover{background-color:transparent!important;color:#409ad5!important;box-shadow:none}.btn-link:visited{color:#9b59b6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:after,.wy-btn-group:before{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:1px solid #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980b9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:1px solid #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type=search]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980b9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned .wy-help-inline,.wy-form-aligned input,.wy-form-aligned label,.wy-form-aligned select,.wy-form-aligned textarea{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{margin:0}fieldset,legend{border:0;padding:0}legend{width:100%;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label,legend{display:block}label{margin:0 0 .3125em;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;max-width:1200px;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:after,.wy-control-group:before{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#e74c3c}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full input[type=color],.wy-control-group .wy-form-full input[type=date],.wy-control-group .wy-form-full input[type=datetime-local],.wy-control-group .wy-form-full input[type=datetime],.wy-control-group .wy-form-full input[type=email],.wy-control-group .wy-form-full input[type=month],.wy-control-group .wy-form-full input[type=number],.wy-control-group .wy-form-full input[type=password],.wy-control-group .wy-form-full input[type=search],.wy-control-group .wy-form-full input[type=tel],.wy-control-group .wy-form-full input[type=text],.wy-control-group .wy-form-full input[type=time],.wy-control-group .wy-form-full input[type=url],.wy-control-group .wy-form-full input[type=week],.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves input[type=color],.wy-control-group .wy-form-halves input[type=date],.wy-control-group .wy-form-halves input[type=datetime-local],.wy-control-group .wy-form-halves input[type=datetime],.wy-control-group .wy-form-halves input[type=email],.wy-control-group .wy-form-halves input[type=month],.wy-control-group .wy-form-halves input[type=number],.wy-control-group .wy-form-halves input[type=password],.wy-control-group .wy-form-halves input[type=search],.wy-control-group .wy-form-halves input[type=tel],.wy-control-group .wy-form-halves input[type=text],.wy-control-group .wy-form-halves input[type=time],.wy-control-group .wy-form-halves input[type=url],.wy-control-group .wy-form-halves input[type=week],.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds input[type=color],.wy-control-group .wy-form-thirds input[type=date],.wy-control-group .wy-form-thirds input[type=datetime-local],.wy-control-group .wy-form-thirds input[type=datetime],.wy-control-group .wy-form-thirds input[type=email],.wy-control-group .wy-form-thirds input[type=month],.wy-control-group .wy-form-thirds input[type=number],.wy-control-group .wy-form-thirds input[type=password],.wy-control-group .wy-form-thirds input[type=search],.wy-control-group .wy-form-thirds input[type=tel],.wy-control-group .wy-form-thirds input[type=text],.wy-control-group .wy-form-thirds input[type=time],.wy-control-group .wy-form-thirds input[type=url],.wy-control-group .wy-form-thirds input[type=week],.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full{float:left;display:block;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.35765%;width:48.82117%}.wy-control-group .wy-form-halves:last-child,.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(odd){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.35765%;width:31.76157%}.wy-control-group .wy-form-thirds:last-child,.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control,.wy-control-no-input{margin:6px 0 0;font-size:90%}.wy-control-no-input{display:inline-block}.wy-control-group.fluid-input input[type=color],.wy-control-group.fluid-input input[type=date],.wy-control-group.fluid-input input[type=datetime-local],.wy-control-group.fluid-input input[type=datetime],.wy-control-group.fluid-input input[type=email],.wy-control-group.fluid-input input[type=month],.wy-control-group.fluid-input input[type=number],.wy-control-group.fluid-input input[type=password],.wy-control-group.fluid-input input[type=search],.wy-control-group.fluid-input input[type=tel],.wy-control-group.fluid-input input[type=text],.wy-control-group.fluid-input input[type=time],.wy-control-group.fluid-input input[type=url],.wy-control-group.fluid-input input[type=week]{width:100%}.wy-form-message-inline{padding-left:.3em;color:#666;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;*overflow:visible}input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}input[type=datetime-local]{padding:.34375em .625em}input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{padding:0;margin-right:.3125em;*height:13px;*width:13px}input[type=checkbox],input[type=radio],input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}input[type=color]:focus,input[type=date]:focus,input[type=datetime-local]:focus,input[type=datetime]:focus,input[type=email]:focus,input[type=month]:focus,input[type=number]:focus,input[type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=time]:focus,input[type=url]:focus,input[type=week]:focus{outline:0;outline:thin dotted\9;border-color:#333}input.no-focus:focus{border-color:#ccc!important}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:thin dotted #333;outline:1px auto #129fea}input[type=color][disabled],input[type=date][disabled],input[type=datetime-local][disabled],input[type=datetime][disabled],input[type=email][disabled],input[type=month][disabled],input[type=number][disabled],input[type=password][disabled],input[type=search][disabled],input[type=tel][disabled],input[type=text][disabled],input[type=time][disabled],input[type=url][disabled],input[type=week][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,select:focus:invalid,textarea:focus:invalid{color:#e74c3c;border:1px solid #e74c3c}input:focus:invalid:focus,select:focus:invalid:focus,textarea:focus:invalid:focus{border-color:#e74c3c}input[type=checkbox]:focus:invalid:focus,input[type=file]:focus:invalid:focus,input[type=radio]:focus:invalid:focus{outline-color:#e74c3c}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif}select,textarea{padding:.5em .625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}input[readonly],select[disabled],select[readonly],textarea[disabled],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type=checkbox][disabled],input[type=radio][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:1px solid #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{position:relative;display:block;height:24px;margin-top:12px;cursor:pointer}.wy-switch:before{left:0;top:0;width:36px;height:12px;background:#ccc}.wy-switch:after,.wy-switch:before{position:absolute;content:"";display:block;border-radius:4px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch:after{width:18px;height:18px;background:#999;left:-3px;top:-3px}.wy-switch span{position:absolute;left:48px;display:block;font-size:12px;color:#ccc;line-height:1}.wy-switch.active:before{background:#1e8449}.wy-switch.active:after{left:24px;background:#27ae60}.wy-switch.disabled{cursor:not-allowed;opacity:.8}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#e74c3c}.wy-control-group.wy-control-group-error input[type=color],.wy-control-group.wy-control-group-error input[type=date],.wy-control-group.wy-control-group-error input[type=datetime-local],.wy-control-group.wy-control-group-error input[type=datetime],.wy-control-group.wy-control-group-error input[type=email],.wy-control-group.wy-control-group-error input[type=month],.wy-control-group.wy-control-group-error input[type=number],.wy-control-group.wy-control-group-error input[type=password],.wy-control-group.wy-control-group-error input[type=search],.wy-control-group.wy-control-group-error input[type=tel],.wy-control-group.wy-control-group-error input[type=text],.wy-control-group.wy-control-group-error input[type=time],.wy-control-group.wy-control-group-error input[type=url],.wy-control-group.wy-control-group-error input[type=week],.wy-control-group.wy-control-group-error textarea{border:1px solid #e74c3c}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:.5em .625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27ae60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#e74c3c}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#e67e22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980b9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width:480px){.wy-form button[type=submit]{margin:.7em 0 0}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=text],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week],.wy-form label{margin-bottom:.3em;display:block}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0}.wy-form-message,.wy-form-message-inline,.wy-form .wy-help-inline{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width:768px){.tablet-hide{display:none}}@media screen and (max-width:480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.rst-content table.docutils,.rst-content table.field-list,.wy-table{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.rst-content table.docutils caption,.rst-content table.field-list caption,.wy-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.rst-content table.docutils td,.rst-content table.docutils th,.rst-content table.field-list td,.rst-content table.field-list th,.wy-table td,.wy-table th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.rst-content table.docutils td:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list td:first-child,.rst-content table.field-list th:first-child,.wy-table td:first-child,.wy-table th:first-child{border-left-width:0}.rst-content table.docutils thead,.rst-content table.field-list thead,.wy-table thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.rst-content table.docutils thead th,.rst-content table.field-list thead th,.wy-table thead th{font-weight:700;border-bottom:2px solid #e1e4e5}.rst-content table.docutils td,.rst-content table.field-list td,.wy-table td{background-color:transparent;vertical-align:middle}.rst-content table.docutils td p,.rst-content table.field-list td p,.wy-table td p{line-height:18px}.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child,.wy-table td p:last-child{margin-bottom:0}.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min,.wy-table .wy-table-cell-min{width:1%;padding-right:0}.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:grey;font-size:90%}.wy-table-tertiary{color:grey;font-size:80%}.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td,.wy-table-backed,.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td{background-color:#f3f6f6}.rst-content table.docutils,.wy-table-bordered-all{border:1px solid #e1e4e5}.rst-content table.docutils td,.wy-table-bordered-all td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.rst-content table.docutils tbody>tr:last-child td,.wy-table-bordered-all tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0!important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980b9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9b59b6}html{height:100%}body,html{overflow-x:hidden}body{font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;font-weight:400;color:#404040;min-height:100%;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#e67e22!important}a.wy-text-warning:hover{color:#eb9950!important}.wy-text-info{color:#2980b9!important}a.wy-text-info:hover{color:#409ad5!important}.wy-text-success{color:#27ae60!important}a.wy-text-success:hover{color:#36d278!important}.wy-text-danger{color:#e74c3c!important}a.wy-text-danger:hover{color:#ed7669!important}.wy-text-neutral{color:#404040!important}a.wy-text-neutral:hover{color:#595959!important}.rst-content .toctree-wrapper>p.caption,h1,h2,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif}p{line-height:24px;font-size:16px;margin:0 0 24px}h1{font-size:175%}.rst-content .toctree-wrapper>p.caption,h2{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}.rst-content code,.rst-content tt,code{white-space:nowrap;max-width:100%;background:#fff;border:1px solid #e1e4e5;font-size:75%;padding:0 5px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#e74c3c;overflow-x:auto}.rst-content tt.code-large,code.code-large{font-size:90%}.rst-content .section ul,.rst-content .toctree-wrapper ul,.rst-content section ul,.wy-plain-list-disc,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.rst-content .section ul li,.rst-content .toctree-wrapper ul li,.rst-content section ul li,.wy-plain-list-disc li,article ul li{list-style:disc;margin-left:24px}.rst-content .section ul li p:last-child,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li p:last-child,.rst-content .toctree-wrapper ul li ul,.rst-content section ul li p:last-child,.rst-content section ul li ul,.wy-plain-list-disc li p:last-child,.wy-plain-list-disc li ul,article ul li p:last-child,article ul li ul{margin-bottom:0}.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,.rst-content section ul li li,.wy-plain-list-disc li li,article ul li li{list-style:circle}.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,.rst-content section ul li li li,.wy-plain-list-disc li li li,article ul li li li{list-style:square}.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,.rst-content section ul li ol li,.wy-plain-list-disc li ol li,article ul li ol li{list-style:decimal}.rst-content .section ol,.rst-content .section ol.arabic,.rst-content .toctree-wrapper ol,.rst-content .toctree-wrapper ol.arabic,.rst-content section ol,.rst-content section ol.arabic,.wy-plain-list-decimal,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.rst-content .section ol.arabic li,.rst-content .section ol li,.rst-content .toctree-wrapper ol.arabic li,.rst-content .toctree-wrapper ol li,.rst-content section ol.arabic li,.rst-content section ol li,.wy-plain-list-decimal li,article ol li{list-style:decimal;margin-left:24px}.rst-content .section ol.arabic li ul,.rst-content .section ol li p:last-child,.rst-content .section ol li ul,.rst-content .toctree-wrapper ol.arabic li ul,.rst-content .toctree-wrapper ol li p:last-child,.rst-content .toctree-wrapper ol li ul,.rst-content section ol.arabic li ul,.rst-content section ol li p:last-child,.rst-content section ol li ul,.wy-plain-list-decimal li p:last-child,.wy-plain-list-decimal li ul,article ol li p:last-child,article ol li ul{margin-bottom:0}.rst-content .section ol.arabic li ul li,.rst-content .section ol li ul li,.rst-content .toctree-wrapper ol.arabic li ul li,.rst-content .toctree-wrapper ol li ul li,.rst-content section ol.arabic li ul li,.rst-content section ol li ul li,.wy-plain-list-decimal li ul li,article ol li ul li{list-style:disc}.wy-breadcrumbs{*zoom:1}.wy-breadcrumbs:after,.wy-breadcrumbs:before{display:table;content:""}.wy-breadcrumbs:after{clear:both}.wy-breadcrumbs li{display:inline-block}.wy-breadcrumbs li.wy-breadcrumbs-aside{float:right}.wy-breadcrumbs li a{display:inline-block;padding:5px}.wy-breadcrumbs li a:first-child{padding-left:0}.rst-content .wy-breadcrumbs li tt,.wy-breadcrumbs li .rst-content tt,.wy-breadcrumbs li code{padding:5px;border:none;background:none}.rst-content .wy-breadcrumbs li tt.literal,.wy-breadcrumbs li .rst-content tt.literal,.wy-breadcrumbs li code.literal{color:#404040}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width:480px){.wy-breadcrumbs-extra,.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}html{font-size:16px}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:after,.wy-menu-horiz:before{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz li,.wy-menu-horiz ul{display:inline-block}.wy-menu-horiz li:hover{background:hsla(0,0%,100%,.1)}.wy-menu-horiz li.divide-left{border-left:1px solid #404040}.wy-menu-horiz li.divide-right{border-right:1px solid #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{color:#55a5d9;height:32px;line-height:32px;padding:0 1.618em;margin:12px 0 0;display:block;font-weight:700;text-transform:uppercase;font-size:85%;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:1px solid #404040}.wy-menu-vertical li.divide-bottom{border-bottom:1px solid #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:grey;border-right:1px solid #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.rst-content .wy-menu-vertical li tt,.wy-menu-vertical li .rst-content tt,.wy-menu-vertical li code{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li button.toctree-expand{display:block;float:left;margin-left:-1.2em;line-height:18px;color:#4d4d4d;border:none;background:none;padding:0}.wy-menu-vertical li.current>a,.wy-menu-vertical li.on a{color:#404040;font-weight:700;position:relative;background:#fcfcfc;border:none;padding:.4045em 1.618em}.wy-menu-vertical li.current>a:hover,.wy-menu-vertical li.on a:hover{background:#fcfcfc}.wy-menu-vertical li.current>a:hover button.toctree-expand,.wy-menu-vertical li.on a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand{display:block;line-height:18px;color:#333}.wy-menu-vertical li.toctree-l1.current>a{border-bottom:1px solid #c9c9c9;border-top:1px solid #c9c9c9}.wy-menu-vertical .toctree-l1.current .toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .toctree-l11>ul{display:none}.wy-menu-vertical .toctree-l1.current .current.toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .current.toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .current.toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .current.toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .current.toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .current.toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .current.toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .current.toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .current.toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .current.toctree-l11>ul{display:block}.wy-menu-vertical li.toctree-l3,.wy-menu-vertical li.toctree-l4{font-size:.9em}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l4 a,.wy-menu-vertical li.toctree-l5 a,.wy-menu-vertical li.toctree-l6 a,.wy-menu-vertical li.toctree-l7 a,.wy-menu-vertical li.toctree-l8 a,.wy-menu-vertical li.toctree-l9 a,.wy-menu-vertical li.toctree-l10 a{color:#404040}.wy-menu-vertical li.toctree-l2 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l3 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l4 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l5 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l6 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l7 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l8 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l9 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l10 a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a,.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a,.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a,.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a,.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a,.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a,.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a,.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{display:block}.wy-menu-vertical li.toctree-l2.current>a{padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{padding:.4045em 1.618em .4045em 4.045em}.wy-menu-vertical li.toctree-l3.current>a{padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{padding:.4045em 1.618em .4045em 5.663em}.wy-menu-vertical li.toctree-l4.current>a{padding:.4045em 5.663em}.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a{padding:.4045em 1.618em .4045em 7.281em}.wy-menu-vertical li.toctree-l5.current>a{padding:.4045em 7.281em}.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a{padding:.4045em 1.618em .4045em 8.899em}.wy-menu-vertical li.toctree-l6.current>a{padding:.4045em 8.899em}.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a{padding:.4045em 1.618em .4045em 10.517em}.wy-menu-vertical li.toctree-l7.current>a{padding:.4045em 10.517em}.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a{padding:.4045em 1.618em .4045em 12.135em}.wy-menu-vertical li.toctree-l8.current>a{padding:.4045em 12.135em}.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a{padding:.4045em 1.618em .4045em 13.753em}.wy-menu-vertical li.toctree-l9.current>a{padding:.4045em 13.753em}.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a{padding:.4045em 1.618em .4045em 15.371em}.wy-menu-vertical li.toctree-l10.current>a{padding:.4045em 15.371em}.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{padding:.4045em 1.618em .4045em 16.989em}.wy-menu-vertical li.toctree-l2.current>a,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{background:#c9c9c9}.wy-menu-vertical li.toctree-l2 button.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3.current>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{background:#bdbdbd}.wy-menu-vertical li.toctree-l3 button.toctree-expand{color:#969696}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical li ul li a{margin-bottom:0;color:#d9d9d9;font-weight:400}.wy-menu-vertical a{line-height:18px;padding:.4045em 1.618em;display:block;position:relative;font-size:90%;color:#d9d9d9}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover button.toctree-expand{color:#d9d9d9}.wy-menu-vertical a:active{background-color:#2980b9;cursor:pointer;color:#fff}.wy-menu-vertical a:active button.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:.809em;margin-bottom:.809em;z-index:200;background-color:#2980b9;text-align:center;color:#fcfcfc}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto .809em;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-side-nav-search .wy-dropdown>a,.wy-side-nav-search>a{color:#fcfcfc;font-size:100%;font-weight:700;display:inline-block;padding:4px 6px;margin-bottom:.809em;max-width:100%}.wy-side-nav-search .wy-dropdown>a:hover,.wy-side-nav-search>a:hover{background:hsla(0,0%,100%,.1)}.wy-side-nav-search .wy-dropdown>a img.logo,.wy-side-nav-search>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search .wy-dropdown>a.icon img.logo,.wy-side-nav-search>a.icon img.logo{margin-top:.85em}.wy-side-nav-search>div.version{margin-top:-.4045em;margin-bottom:.809em;font-weight:400;color:hsla(0,0%,100%,.3)}.wy-nav .wy-menu-vertical header{color:#2980b9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980b9;color:#fff}[data-menu-wrap]{-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;transition:all .2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:#fcfcfc}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;color:#9b9b9b;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980b9;color:#fff;padding:.4045em .809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:after,.wy-nav-top:before{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:700}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:grey}footer p{margin-bottom:12px}.rst-content footer span.commit tt,footer span.commit .rst-content tt,footer span.commit code{padding:0;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:1em;background:none;border:none;color:grey}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:after,.rst-footer-buttons:before{width:100%;display:table;content:""}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:after,.rst-breadcrumbs-buttons:before{display:table;content:""}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:1px solid #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:1px solid #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:grey;font-size:90%}.genindextable li>ul{margin-left:24px}@media screen and (max-width:768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-menu.wy-menu-vertical,.wy-side-nav-search,.wy-side-scroll{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width:1100px){.wy-nav-content-wrap{background:rgba(0,0,0,.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,.wy-nav-side,footer{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60;*zoom:1}.rst-versions .rst-current-version:after,.rst-versions .rst-current-version:before{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-content .code-block-caption .rst-versions .rst-current-version .headerlink,.rst-content .eqno .rst-versions .rst-current-version .headerlink,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-content p .rst-versions .rst-current-version .headerlink,.rst-content table>caption .rst-versions .rst-current-version .headerlink,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .icon,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-versions .rst-current-version .rst-content .code-block-caption .headerlink,.rst-versions .rst-current-version .rst-content .eqno .headerlink,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-versions .rst-current-version .rst-content p .headerlink,.rst-versions .rst-current-version .rst-content table>caption .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-versions .rst-current-version .wy-menu-vertical li button.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version button.toctree-expand{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}.rst-content .toctree-wrapper>p.caption,.rst-content h1,.rst-content h2,.rst-content h3,.rst-content h4,.rst-content h5,.rst-content h6{margin-bottom:24px}.rst-content img{max-width:100%;height:auto}.rst-content div.figure,.rst-content figure{margin-bottom:24px}.rst-content div.figure .caption-text,.rst-content figure .caption-text{font-style:italic}.rst-content div.figure p:last-child.caption,.rst-content figure p:last-child.caption{margin-bottom:0}.rst-content div.figure.align-center,.rst-content figure.align-center{text-align:center}.rst-content .section>a>img,.rst-content .section>img,.rst-content section>a>img,.rst-content section>img{margin-bottom:24px}.rst-content abbr[title]{text-decoration:none}.rst-content.style-external-links a.reference.external:after{font-family:FontAwesome;content:"\f08e";color:#b3b3b3;vertical-align:super;font-size:60%;margin:0 .2em}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content pre.literal-block{white-space:pre;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;display:block;overflow:auto}.rst-content div[class^=highlight],.rst-content pre.literal-block{border:1px solid #e1e4e5;overflow-x:auto;margin:1px 0 24px}.rst-content div[class^=highlight] div[class^=highlight],.rst-content pre.literal-block div[class^=highlight]{padding:0;border:none;margin:0}.rst-content div[class^=highlight] td.code{width:100%}.rst-content .linenodiv pre{border-right:1px solid #e6e9ea;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;user-select:none;pointer-events:none}.rst-content div[class^=highlight] pre{white-space:pre;margin:0;padding:12px;display:block;overflow:auto}.rst-content div[class^=highlight] pre .hll{display:block;margin:0 -12px;padding:0 12px}.rst-content .linenodiv pre,.rst-content div[class^=highlight] pre,.rst-content pre.literal-block{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:12px;line-height:1.4}.rst-content div.highlight .gp,.rst-content div.highlight span.linenos{user-select:none;pointer-events:none}.rst-content div.highlight span.linenos{display:inline-block;padding-left:0;padding-right:12px;margin-right:12px;border-right:1px solid #e6e9ea}.rst-content .code-block-caption{font-style:italic;font-size:85%;line-height:1;padding:1em 0;text-align:center}@media print{.rst-content .codeblock,.rst-content div[class^=highlight],.rst-content div[class^=highlight] pre{white-space:pre-wrap}}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning{clear:both}.rst-content .admonition-todo .last,.rst-content .admonition-todo>:last-child,.rst-content .admonition .last,.rst-content .admonition>:last-child,.rst-content .attention .last,.rst-content .attention>:last-child,.rst-content .caution .last,.rst-content .caution>:last-child,.rst-content .danger .last,.rst-content .danger>:last-child,.rst-content .error .last,.rst-content .error>:last-child,.rst-content .hint .last,.rst-content .hint>:last-child,.rst-content .important .last,.rst-content .important>:last-child,.rst-content .note .last,.rst-content .note>:last-child,.rst-content .seealso .last,.rst-content .seealso>:last-child,.rst-content .tip .last,.rst-content .tip>:last-child,.rst-content .warning .last,.rst-content .warning>:last-child{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent!important;border-color:rgba(0,0,0,.1)!important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha>li,.rst-content .toctree-wrapper ol.loweralpha,.rst-content .toctree-wrapper ol.loweralpha>li,.rst-content section ol.loweralpha,.rst-content section ol.loweralpha>li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha>li,.rst-content .toctree-wrapper ol.upperalpha,.rst-content .toctree-wrapper ol.upperalpha>li,.rst-content section ol.upperalpha,.rst-content section ol.upperalpha>li{list-style:upper-alpha}.rst-content .section ol li>*,.rst-content .section ul li>*,.rst-content .toctree-wrapper ol li>*,.rst-content .toctree-wrapper ul li>*,.rst-content section ol li>*,.rst-content section ul li>*{margin-top:12px;margin-bottom:12px}.rst-content .section ol li>:first-child,.rst-content .section ul li>:first-child,.rst-content .toctree-wrapper ol li>:first-child,.rst-content .toctree-wrapper ul li>:first-child,.rst-content section ol li>:first-child,.rst-content section ul li>:first-child{margin-top:0}.rst-content .section ol li>p,.rst-content .section ol li>p:last-child,.rst-content .section ul li>p,.rst-content .section ul li>p:last-child,.rst-content .toctree-wrapper ol li>p,.rst-content .toctree-wrapper ol li>p:last-child,.rst-content .toctree-wrapper ul li>p,.rst-content .toctree-wrapper ul li>p:last-child,.rst-content section ol li>p,.rst-content section ol li>p:last-child,.rst-content section ul li>p,.rst-content section ul li>p:last-child{margin-bottom:12px}.rst-content .section ol li>p:only-child,.rst-content .section ol li>p:only-child:last-child,.rst-content .section ul li>p:only-child,.rst-content .section ul li>p:only-child:last-child,.rst-content .toctree-wrapper ol li>p:only-child,.rst-content .toctree-wrapper ol li>p:only-child:last-child,.rst-content .toctree-wrapper ul li>p:only-child,.rst-content .toctree-wrapper ul li>p:only-child:last-child,.rst-content section ol li>p:only-child,.rst-content section ol li>p:only-child:last-child,.rst-content section ul li>p:only-child,.rst-content section ul li>p:only-child:last-child{margin-bottom:0}.rst-content .section ol li>ol,.rst-content .section ol li>ul,.rst-content .section ul li>ol,.rst-content .section ul li>ul,.rst-content .toctree-wrapper ol li>ol,.rst-content .toctree-wrapper ol li>ul,.rst-content .toctree-wrapper ul li>ol,.rst-content .toctree-wrapper ul li>ul,.rst-content section ol li>ol,.rst-content section ol li>ul,.rst-content section ul li>ol,.rst-content section ul li>ul{margin-bottom:12px}.rst-content .section ol.simple li>*,.rst-content .section ol.simple li ol,.rst-content .section ol.simple li ul,.rst-content .section ul.simple li>*,.rst-content .section ul.simple li ol,.rst-content .section ul.simple li ul,.rst-content .toctree-wrapper ol.simple li>*,.rst-content .toctree-wrapper ol.simple li ol,.rst-content .toctree-wrapper ol.simple li ul,.rst-content .toctree-wrapper ul.simple li>*,.rst-content .toctree-wrapper ul.simple li ol,.rst-content .toctree-wrapper ul.simple li ul,.rst-content section ol.simple li>*,.rst-content section ol.simple li ol,.rst-content section ol.simple li ul,.rst-content section ul.simple li>*,.rst-content section ul.simple li ol,.rst-content section ul.simple li ul{margin-top:0;margin-bottom:0}.rst-content .line-block{margin-left:0;margin-bottom:24px;line-height:24px}.rst-content .line-block .line-block{margin-left:24px;margin-bottom:0}.rst-content .topic-title{font-weight:700;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0 0 24px 24px}.rst-content .align-left{float:left;margin:0 24px 24px 0}.rst-content .align-center{margin:auto}.rst-content .align-center:not(table){display:block}.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink{opacity:0;font-size:14px;font-family:FontAwesome;margin-left:.5em}.rst-content .code-block-caption .headerlink:focus,.rst-content .code-block-caption:hover .headerlink,.rst-content .eqno .headerlink:focus,.rst-content .eqno:hover .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink:focus,.rst-content .toctree-wrapper>p.caption:hover .headerlink,.rst-content dl dt .headerlink:focus,.rst-content dl dt:hover .headerlink,.rst-content h1 .headerlink:focus,.rst-content h1:hover .headerlink,.rst-content h2 .headerlink:focus,.rst-content h2:hover .headerlink,.rst-content h3 .headerlink:focus,.rst-content h3:hover .headerlink,.rst-content h4 .headerlink:focus,.rst-content h4:hover .headerlink,.rst-content h5 .headerlink:focus,.rst-content h5:hover .headerlink,.rst-content h6 .headerlink:focus,.rst-content h6:hover .headerlink,.rst-content p.caption .headerlink:focus,.rst-content p.caption:hover .headerlink,.rst-content p .headerlink:focus,.rst-content p:hover .headerlink,.rst-content table>caption .headerlink:focus,.rst-content table>caption:hover .headerlink{opacity:1}.rst-content .btn:focus{outline:2px solid}.rst-content table>caption .headerlink:after{font-size:12px}.rst-content .centered{text-align:center}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:1px solid #e1e4e5}.rst-content .sidebar dl,.rst-content .sidebar p,.rst-content .sidebar ul{font-size:90%}.rst-content .sidebar .last,.rst-content .sidebar>:last-child{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif;font-weight:700;background:#e1e4e5;padding:6px 12px;margin:-24px -24px 24px;font-size:100%}.rst-content .highlighted{background:#f1c40f;box-shadow:0 0 0 2px #f1c40f;display:inline;font-weight:700}.rst-content .citation-reference,.rst-content .footnote-reference{vertical-align:baseline;position:relative;top:-.4em;line-height:0;font-size:90%}.rst-content .hlist{width:100%}.rst-content dl dt span.classifier:before{content:" : "}.rst-content dl dt span.classifier-delimiter{display:none!important}html.writer-html4 .rst-content table.docutils.citation,html.writer-html4 .rst-content table.docutils.footnote{background:none;border:none}html.writer-html4 .rst-content table.docutils.citation td,html.writer-html4 .rst-content table.docutils.citation tr,html.writer-html4 .rst-content table.docutils.footnote td,html.writer-html4 .rst-content table.docutils.footnote tr{border:none;background-color:transparent!important;white-space:normal}html.writer-html4 .rst-content table.docutils.citation td.label,html.writer-html4 .rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{display:grid;grid-template-columns:max-content auto}html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{padding-left:1rem}html.writer-html5 .rst-content dl.field-list>dt:after,html.writer-html5 .rst-content dl.footnote>dt:after{content:":"}html.writer-html5 .rst-content dl.field-list>dd,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dd,html.writer-html5 .rst-content dl.footnote>dt{margin-bottom:0}html.writer-html5 .rst-content dl.footnote{font-size:.9rem}html.writer-html5 .rst-content dl.footnote>dt{margin:0 .5rem .5rem 0;line-height:1.2rem;word-break:break-all;font-weight:400}html.writer-html5 .rst-content dl.footnote>dt>span.brackets{margin-right:.5rem}html.writer-html5 .rst-content dl.footnote>dt>span.brackets:before{content:"["}html.writer-html5 .rst-content dl.footnote>dt>span.brackets:after{content:"]"}html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref{font-style:italic}html.writer-html5 .rst-content dl.footnote>dd{margin:0 0 .5rem;line-height:1.2rem}html.writer-html5 .rst-content dl.footnote>dd p,html.writer-html5 .rst-content dl.option-list kbd{font-size:.9rem}.rst-content table.docutils.footnote,html.writer-html4 .rst-content table.docutils.citation,html.writer-html5 .rst-content dl.footnote{color:grey}.rst-content table.docutils.footnote code,.rst-content table.docutils.footnote tt,html.writer-html4 .rst-content table.docutils.citation code,html.writer-html4 .rst-content table.docutils.citation tt,html.writer-html5 .rst-content dl.footnote code,html.writer-html5 .rst-content dl.footnote tt{color:#555}.rst-content .wy-table-responsive.citation,.rst-content .wy-table-responsive.footnote{margin-bottom:0}.rst-content .wy-table-responsive.citation+:not(.citation),.rst-content .wy-table-responsive.footnote+:not(.footnote){margin-top:24px}.rst-content .wy-table-responsive.citation:last-child,.rst-content .wy-table-responsive.footnote:last-child{margin-bottom:24px}.rst-content table.docutils th{border-color:#e1e4e5}html.writer-html5 .rst-content table.docutils th{border:1px solid #e1e4e5}html.writer-html5 .rst-content table.docutils td>p,html.writer-html5 .rst-content table.docutils th>p{line-height:1rem;margin-bottom:0;font-size:.9rem}.rst-content table.docutils td .last,.rst-content table.docutils td .last>:last-child{margin-bottom:0}.rst-content table.field-list,.rst-content table.field-list td{border:none}.rst-content table.field-list td p{font-size:inherit;line-height:inherit}.rst-content table.field-list td>strong{display:inline-block}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left}.rst-content code,.rst-content tt{color:#000;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;padding:2px 5px}.rst-content code big,.rst-content code em,.rst-content tt big,.rst-content tt em{font-size:100%!important;line-height:normal}.rst-content code.literal,.rst-content tt.literal{color:#e74c3c;white-space:normal}.rst-content code.xref,.rst-content tt.xref,a .rst-content code,a .rst-content tt{font-weight:700;color:#404040}.rst-content kbd,.rst-content pre,.rst-content samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace}.rst-content a code,.rst-content a tt{color:#2980b9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:700;margin-bottom:12px}.rst-content dl ol,.rst-content dl p,.rst-content dl table,.rst-content dl ul{margin-bottom:12px}.rst-content dl dd{margin:0 0 12px 24px;line-height:24px}html.writer-html4 .rst-content dl:not(.docutils),html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple){margin-bottom:24px}html.writer-html4 .rst-content dl:not(.docutils)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)>dt{display:table;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980b9;border-top:3px solid #6ab0de;padding:6px;position:relative}html.writer-html4 .rst-content dl:not(.docutils)>dt:before,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)>dt:before{color:#6ab0de}html.writer-html4 .rst-content dl:not(.docutils)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.field-list)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dl:not(.field-list)>dt{margin-bottom:6px;border:none;border-left:3px solid #ccc;background:#f0f0f0;color:#555}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.field-list)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dl:not(.field-list)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils)>dt:first-child,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)>dt:first-child{margin-top:0}html.writer-html4 .rst-content dl:not(.docutils) code.descclassname,html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descclassname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) code.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) tt.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) tt.descname{background-color:transparent;border:none;padding:0;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) tt.descname{font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .optional,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .property,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .property{display:inline-block;padding-right:8px;max-width:100%}html.writer-html4 .rst-content dl:not(.docutils) .k,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .k{font-style:italic}html.writer-html4 .rst-content dl:not(.docutils) .descclassname,html.writer-html4 .rst-content dl:not(.docutils) .descname,html.writer-html4 .rst-content dl:not(.docutils) .sig-name,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .sig-name{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#000}.rst-content .viewcode-back,.rst-content .viewcode-link{display:inline-block;color:#27ae60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:700}.rst-content code.download,.rst-content tt.download{background:inherit;padding:inherit;font-weight:400;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content code.download span:first-child,.rst-content tt.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{margin-right:4px}.rst-content .guilabel{border:1px solid #7fbbe3;background:#e7f2fa;font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.rst-content .versionmodified{font-style:italic}@media screen and (max-width:480px){.rst-content .sidebar{width:100%}}span[id*=MathJax-Span]{color:#404040}.math{text-align:center}@font-face{font-family:Lato;src:url(fonts/lato-normal.woff2?bd03a2cc277bbbc338d464e679fe9942) format("woff2"),url(fonts/lato-normal.woff?27bd77b9162d388cb8d4c4217c7c5e2a) format("woff");font-weight:400;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold.woff2?cccb897485813c7c256901dbca54ecf2) format("woff2"),url(fonts/lato-bold.woff?d878b6c29b10beca227e9eef4246111b) format("woff");font-weight:700;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold-italic.woff2?0b6bb6725576b072c5d0b02ecdd1900d) format("woff2"),url(fonts/lato-bold-italic.woff?9c7e4e9eb485b4a121c760e61bc3707c) format("woff");font-weight:700;font-style:italic;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-normal-italic.woff2?4eb103b4d12be57cb1d040ed5e162e9d) format("woff2"),url(fonts/lato-normal-italic.woff?f28f2d6482446544ef1ea1ccc6dd5892) format("woff");font-weight:400;font-style:italic;font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:400;src:url(fonts/Roboto-Slab-Regular.woff2?7abf5b8d04d26a2cafea937019bca958) format("woff2"),url(fonts/Roboto-Slab-Regular.woff?c1be9284088d487c5e3ff0a10a92e58c) format("woff");font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:700;src:url(fonts/Roboto-Slab-Bold.woff2?9984f4a9bda09be08e83f2506954adbe) format("woff2"),url(fonts/Roboto-Slab-Bold.woff?bed5564a116b05148e3b3bea6fb1162a) format("woff");font-display:block} \ No newline at end of file diff --git a/doc/html/apidoc/_static/pygments.css b/doc/html/apidoc/_static/pygments.css index be9feff..582d5c3 100644 --- a/doc/html/apidoc/_static/pygments.css +++ b/doc/html/apidoc/_static/pygments.css @@ -1,8 +1,8 @@ -pre { line-height: 125%; margin: 0; } -td.linenos pre { color: #000000; background-color: #f0f0f0; padding: 0 5px 0 5px; } -span.linenos { color: #000000; background-color: #f0f0f0; padding: 0 5px 0 5px; } -td.linenos pre.special { color: #000000; background-color: #ffffc0; padding: 0 5px 0 5px; } -span.linenos.special { color: #000000; background-color: #ffffc0; padding: 0 5px 0 5px; } +pre { line-height: 125%; } +td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } .highlight .hll { background-color: #ffffcc } .highlight { background: #f8f8f8; } .highlight .c { color: #408080; font-style: italic } /* Comment */ diff --git a/doc/html/apidoc/genindex.html b/doc/html/apidoc/genindex.html index 3109827..931148d 100644 --- a/doc/html/apidoc/genindex.html +++ b/doc/html/apidoc/genindex.html @@ -1,73 +1,35 @@ - - - - - - + + Index — lxml documentation - - - - - - - - - - - - + + - - + - - - - - + - - - +
- -
- - -
- - - - - - - - + \ No newline at end of file diff --git a/doc/html/apidoc/index.html b/doc/html/apidoc/index.html index 46aedd2..d11697a 100644 --- a/doc/html/apidoc/index.html +++ b/doc/html/apidoc/index.html @@ -1,74 +1,37 @@ - - - - - - - lxml API Reference — lxml documentation - - - - - + - - - - - - + + lxml API Reference — lxml documentation + + - - + - - - - - + - - - +
- -
- - -
+
-
-
- -
- - - - - - - - + \ No newline at end of file diff --git a/doc/html/apidoc/lxml.ElementInclude.html b/doc/html/apidoc/lxml.ElementInclude.html index 807898b..0f240ba 100644 --- a/doc/html/apidoc/lxml.ElementInclude.html +++ b/doc/html/apidoc/lxml.ElementInclude.html @@ -1,75 +1,38 @@ - - - - - - - lxml.ElementInclude module — lxml documentation - - - - - + - - - - - - + + lxml.ElementInclude module — lxml documentation + + - - + - - - - - + - - - +
- -
- - -
-
- - - - - - - - - - - + \ No newline at end of file diff --git a/doc/html/apidoc/lxml._elementpath.html b/doc/html/apidoc/lxml._elementpath.html index 302a6f3..7de80e0 100644 --- a/doc/html/apidoc/lxml._elementpath.html +++ b/doc/html/apidoc/lxml._elementpath.html @@ -1,75 +1,38 @@ - - - - - - - lxml._elementpath module — lxml documentation - - - - - + - - - - - - + + lxml._elementpath module — lxml documentation + + - - + - - - - - + - - - +
- -
- - -
- - - - - - - - - - - - + \ No newline at end of file diff --git a/doc/html/apidoc/lxml.builder.html b/doc/html/apidoc/lxml.builder.html index 5892110..e88089c 100644 --- a/doc/html/apidoc/lxml.builder.html +++ b/doc/html/apidoc/lxml.builder.html @@ -1,75 +1,38 @@ - - - - - - - lxml.builder module — lxml documentation - - - - - + - - - - - - + + lxml.builder module — lxml documentation + + - - + - - - - - + - - - +
- -
- - -
- - - - - - - - - - - - + \ No newline at end of file diff --git a/doc/html/apidoc/lxml.cssselect.html b/doc/html/apidoc/lxml.cssselect.html index 43d4229..03ba2ae 100644 --- a/doc/html/apidoc/lxml.cssselect.html +++ b/doc/html/apidoc/lxml.cssselect.html @@ -1,75 +1,38 @@ - - - - - - - lxml.cssselect module — lxml documentation - - - - - + - - - - - - + + lxml.cssselect module — lxml documentation + + - - + - - - - - + - - - +
- -
- - -
- - - - - - - - + \ No newline at end of file diff --git a/doc/html/apidoc/lxml.doctestcompare.html b/doc/html/apidoc/lxml.doctestcompare.html index c25a0b9..45dffe1 100644 --- a/doc/html/apidoc/lxml.doctestcompare.html +++ b/doc/html/apidoc/lxml.doctestcompare.html @@ -1,75 +1,38 @@ - - - - - - - lxml.doctestcompare module — lxml documentation - - - - - + - - - - - - + + lxml.doctestcompare module — lxml documentation + + - - + - - - - - + - - - +
- -
- - -
- - - - - - - - - - - - + \ No newline at end of file diff --git a/doc/html/apidoc/lxml.etree.html b/doc/html/apidoc/lxml.etree.html index 6307879..c0b6ccf 100644 --- a/doc/html/apidoc/lxml.etree.html +++ b/doc/html/apidoc/lxml.etree.html @@ -1,75 +1,38 @@ - - - - - - - lxml.etree module — lxml documentation - - - - - + - - - - - - + + lxml.etree module — lxml documentation + + - - + - - - - - + - - - +
- -
- - -
- - - - - - - - - - - - + \ No newline at end of file diff --git a/doc/html/apidoc/lxml.html b/doc/html/apidoc/lxml.html index 0cabb88..f9144de 100644 --- a/doc/html/apidoc/lxml.html +++ b/doc/html/apidoc/lxml.html @@ -1,75 +1,38 @@ - - - - - - - lxml package — lxml documentation - - - - - + - - - - - - + + lxml package — lxml documentation + + - - + - - - - - + - - - +
- -
- - -
-
-

Module contents¶

+ +
+

Module contents

-
-lxml.get_include()[source]¶
+
+lxml.get_include()[source]

Returns a list of header include paths (for lxml itself, libxml2 and libxslt) needed to compile C code against lxml if it was built with statically linked libraries.

-
- + + - - - - - - - - - - - - + \ No newline at end of file diff --git a/doc/html/apidoc/lxml.html.ElementSoup.html b/doc/html/apidoc/lxml.html.ElementSoup.html index dbb1d44..7775ab6 100644 --- a/doc/html/apidoc/lxml.html.ElementSoup.html +++ b/doc/html/apidoc/lxml.html.ElementSoup.html @@ -1,75 +1,38 @@ - - - - - - - lxml.html.ElementSoup module — lxml documentation - - - - - + - - - - - - + + lxml.html.ElementSoup module — lxml documentation + + - - + - - - - - + - - - +
- -
- - -
- - - - - - - - + \ No newline at end of file diff --git a/doc/html/apidoc/lxml.html._diffcommand.html b/doc/html/apidoc/lxml.html._diffcommand.html index d055676..e0c05be 100644 --- a/doc/html/apidoc/lxml.html._diffcommand.html +++ b/doc/html/apidoc/lxml.html._diffcommand.html @@ -1,75 +1,38 @@ - - - - - - - lxml.html._diffcommand module — lxml documentation - - - - - + - - - - - - + + lxml.html._diffcommand module — lxml documentation + + - - + - - - - - + - - - +
- -
- - -
- - - - - - - - - - - - + \ No newline at end of file diff --git a/doc/html/apidoc/lxml.html._setmixin.html b/doc/html/apidoc/lxml.html._setmixin.html index 460ab1b..8d4a798 100644 --- a/doc/html/apidoc/lxml.html._setmixin.html +++ b/doc/html/apidoc/lxml.html._setmixin.html @@ -1,75 +1,38 @@ - - - - - - - lxml.html._setmixin module — lxml documentation - - - - - + - - - - - - + + lxml.html._setmixin module — lxml documentation + + - - + - - - - - + - - - +
- -
- - -
- - - - - - - - - - - - + \ No newline at end of file diff --git a/doc/html/apidoc/lxml.html.builder.html b/doc/html/apidoc/lxml.html.builder.html index 44c9a8d..0b504dd 100644 --- a/doc/html/apidoc/lxml.html.builder.html +++ b/doc/html/apidoc/lxml.html.builder.html @@ -1,75 +1,38 @@ - - - - - - - lxml.html.builder module — lxml documentation - - - - - + - - - - - - + + lxml.html.builder module — lxml documentation + + - - + - - - - - + - - - +
- -
- - -
- - - - - - - - - - - - + \ No newline at end of file diff --git a/doc/html/apidoc/lxml.html.clean.html b/doc/html/apidoc/lxml.html.clean.html index b1fe54b..989e272 100644 --- a/doc/html/apidoc/lxml.html.clean.html +++ b/doc/html/apidoc/lxml.html.clean.html @@ -1,75 +1,38 @@ - - - - - - - lxml.html.clean module — lxml documentation - - - - - + - - - - - - + + lxml.html.clean module — lxml documentation + + - - + - - - - - + - - - +
- -
- - -
- - - - - - - - - - - - + \ No newline at end of file diff --git a/doc/html/apidoc/lxml.html.defs.html b/doc/html/apidoc/lxml.html.defs.html index a71c10e..8bb0078 100644 --- a/doc/html/apidoc/lxml.html.defs.html +++ b/doc/html/apidoc/lxml.html.defs.html @@ -1,75 +1,38 @@ - - - - - - - lxml.html.defs module — lxml documentation - - - - - + - - - - - - + + lxml.html.defs module — lxml documentation + + - - + - - - - - + - - - +
- -
- - -
- - - - - - - - - - - - + \ No newline at end of file diff --git a/doc/html/apidoc/lxml.html.diff.html b/doc/html/apidoc/lxml.html.diff.html index b4202d0..47da606 100644 --- a/doc/html/apidoc/lxml.html.diff.html +++ b/doc/html/apidoc/lxml.html.diff.html @@ -1,75 +1,38 @@ - - - - - - - lxml.html.diff module — lxml documentation - - - - - + - - - - - - + + lxml.html.diff module — lxml documentation + + - - + - - - - - + - - - +
- -
- - -
- - - - - - - - - - - - + \ No newline at end of file diff --git a/doc/html/apidoc/lxml.html.formfill.html b/doc/html/apidoc/lxml.html.formfill.html index 96d1810..01e8a8a 100644 --- a/doc/html/apidoc/lxml.html.formfill.html +++ b/doc/html/apidoc/lxml.html.formfill.html @@ -1,75 +1,38 @@ - - - - - - - lxml.html.formfill module — lxml documentation - - - - - + - - - - - - + + lxml.html.formfill module — lxml documentation + + - - + - - - - - + - - - +
- -
- - -
- - - - - - - - - - - - + \ No newline at end of file diff --git a/doc/html/apidoc/lxml.html.html b/doc/html/apidoc/lxml.html.html index 58733c0..e95b568 100644 --- a/doc/html/apidoc/lxml.html.html +++ b/doc/html/apidoc/lxml.html.html @@ -1,75 +1,38 @@ - - - - - - - lxml.html package — lxml documentation - - - - - - - - - - + - + + lxml.html package — lxml documentation + + - - + - - - - - + - - - +
- -
- - -
-
-add(value)[source]¶
+
+add(value)[source]

Add a class.

This has no effect if the class is already present.

-
-discard(value)[source]¶
+
+discard(value)[source]

Remove a class if it is currently present.

If the class is not present, do nothing.

-
-remove(value)[source]¶
+
+remove(value)[source]

Remove a class; it must currently be present.

If the class is not present, raise a KeyError.

-
-toggle(value)[source]¶
+
+toggle(value)[source]

Add a class name if it isn’t there yet, or remove it if it exists.

Returns true if the class was added (and is now enabled) and false if it was removed (and is now disabled).

-
-update(values)[source]¶
+
+update(values)[source]

Add all names from ‘values’.

-
-_abc_impl = <_abc_data object>¶
+
+_abc_impl = <_abc._abc_data object>
-
-class lxml.html.FieldsDict(inputs)[source]¶
+
+class lxml.html.FieldsDict(inputs)[source]

Bases: collections.abc.MutableMapping

-
-keys() → a set-like object providing a view on D’s keys[source]¶
+
+keys() a set-like object providing a view on D's keys[source]
-
-_abc_impl = <_abc_data object>¶
+
+_abc_impl = <_abc._abc_data object>
-
-class lxml.html.FormElement[source]¶
+
+class lxml.html.FormElement[source]

Bases: lxml.html.HtmlElement

Represents a <form> element.

-
-_name()[source]¶
+
+_name()[source]
-
-form_values()[source]¶
+
+form_values()[source]

Return a list of tuples of the field values for the form. This is suitable to be passed to urllib.urlencode().

-
-
-property action¶
+
+
+property action

Get/set the form’s action attribute.

-
-
-property fields¶
+
+
+property fields

Dictionary-like object that represents all the fields in this form. You can set values in this dictionary to effect the form.

-
-
-property inputs¶
+
+
+property inputs

Returns an accessor for all the input elements in the form.

See InputGetter for more information about the object.

-
-
-property method¶
+
+
+property method

Get/set the form’s method. Always returns a capitalized string, and defaults to 'GET'

@@ -380,26 +292,26 @@ string, and defaults to -
-class lxml.html.HTMLParser(**kwargs)[source]¶
+
+class lxml.html.HTMLParser(**kwargs)[source]

Bases: lxml.etree.HTMLParser

An HTML parser that is configured to return lxml.html Element objects.

-
-class lxml.html.HtmlComment[source]¶
+
+class lxml.html.HtmlComment[source]

Bases: lxml.etree.CommentBase, lxml.html.HtmlMixin

-
-class lxml.html.HtmlElement[source]¶
+
+class lxml.html.HtmlElement[source]

Bases: lxml.etree.ElementBase, lxml.html.HtmlMixin

-
-cssselect(expr, translator='html')¶
+
+cssselect(expr, translator='html')

Run the CSS expression on this element and its children, returning a list of the results.

Equivalent to lxml.cssselect.CSSSelect(expr, translator=’html’)(self) @@ -408,8 +320,8 @@ speedup.

-
-set(self, key, value=None)¶
+
+set(self, key, value=None)

Sets an element attribute. If no value is provided, or if the value is None, creates a ‘boolean’ attribute without value, e.g. “<form novalidate></form>” for form.set('novalidate').

@@ -418,8 +330,8 @@ for form.set('noval
-
-class lxml.html.HtmlElementClassLookup(classes=None, mixins=None)[source]¶
+
+class lxml.html.HtmlElementClassLookup(classes=None, mixins=None)[source]

Bases: lxml.etree.CustomElementClassLookup

A lookup scheme for HTML Element classes.

To create a lookup instance with different Element classes, pass a tag @@ -428,30 +340,30 @@ a tag name mapping of Mixin classes in the -

-lookup(self, type, doc, namespace, name)[source]¶
+
+lookup(self, type, doc, namespace, name)[source]
-
-_default_element_classes = {'form': <class 'lxml.html.FormElement'>, 'input': <class 'lxml.html.InputElement'>, 'label': <class 'lxml.html.LabelElement'>, 'select': <class 'lxml.html.SelectElement'>, 'textarea': <class 'lxml.html.TextareaElement'>}¶
+
+_default_element_classes = {'form': <class 'lxml.html.FormElement'>, 'input': <class 'lxml.html.InputElement'>, 'label': <class 'lxml.html.LabelElement'>, 'select': <class 'lxml.html.SelectElement'>, 'textarea': <class 'lxml.html.TextareaElement'>}
-
-class lxml.html.HtmlEntity[source]¶
+
+class lxml.html.HtmlEntity[source]

Bases: lxml.etree.EntityBase, lxml.html.HtmlMixin

-
-class lxml.html.HtmlMixin[source]¶
+
+class lxml.html.HtmlMixin[source]

Bases: object

-
-cssselect(expr, translator='html')[source]¶
+
+cssselect(expr, translator='html')[source]

Run the CSS expression on this element and its children, returning a list of the results.

Equivalent to lxml.cssselect.CSSSelect(expr, translator=’html’)(self) @@ -460,8 +372,8 @@ speedup.

-
-drop_tag()[source]¶
+
+drop_tag()[source]

Remove the tag, but not its children or text. The children and text are merged into the parent.

Example:

@@ -474,28 +386,28 @@ are merged into the parent.

-
-drop_tree()[source]¶
+
+drop_tree()[source]

Removes this element from the tree, including its children and text. The tail text is joined to the previous element or parent.

-
-find_class(class_name)[source]¶
+
+find_class(class_name)[source]

Find any elements with the given class name.

- +

Find any links like <a rel="{rel}">...</a>; returns a list of elements.

-
-get_element_by_id(id, *default)[source]¶
+
+get_element_by_id(id, *default)[source]

Get the first element in a document with the given id. If none is found, return the default argument if provided or raise KeyError otherwise.

@@ -506,8 +418,8 @@ the same.

- +

Yield (element, attribute, link, pos), where attribute may be None (indicating the link is in the text). pos is the position where the link occurs; often 0, but sometimes something else in @@ -523,8 +435,8 @@ links reported later on.

- +

Make all links in the document absolute, given the base_url for the document (the full URL where the document came from), or if no base_url is given, then the .base_url @@ -538,8 +450,8 @@ are ignored. If set to ‘discard’, failing URLs will be removed.

-
-resolve_base_href(handle_failures=None)[source]¶
+
+resolve_base_href(handle_failures=None)[source]

Find any <base href> tag in the document, and apply its values to all links found in the document. Also remove the tag once it has been applied.

@@ -549,8 +461,8 @@ are ignored. If set to ‘discard’, failing URLs will be removed.

- +

Rewrite all the links in the document. For each link link_repl_func(link) will be called, and the return value will replace the old link.

@@ -565,70 +477,70 @@ tag text will be removed completely.

-
-set(self, key, value=None)[source]¶
+
+set(self, key, value=None)[source]

Sets an element attribute. If no value is provided, or if the value is None, creates a ‘boolean’ attribute without value, e.g. “<form novalidate></form>” for form.set('novalidate').

-
-text_content()[source]¶
+
+text_content()[source]

Return the text content of the tag (and the text in any children).

-
-
-property base_url¶
+
+
+property base_url

Returns the base URL, given when the page was parsed.

Use with urlparse.urljoin(el.base_url, href) to get absolute URLs.

-
-
-property body¶
+
+
+property body

Return the <body> element. Can be called from a child element to get the document’s head.

-
-
-property classes¶
+
+
+property classes

A set-like wrapper around the ‘class’ attribute.

-
-
-property forms¶
+
+
+property forms

Return a list of all the forms

-
-
-property head¶
+
+
+property head

Returns the <head> element. Can be called from a child element to get the document’s head.

-
-
-property label¶
+
+
+property label

Get or set any <label> element associated with this element.

-
-class lxml.html.HtmlProcessingInstruction[source]¶
+
+class lxml.html.HtmlProcessingInstruction[source]

Bases: lxml.etree.PIBase, lxml.html.HtmlMixin

-
-class lxml.html.InputElement[source]¶
+
+class lxml.html.InputElement[source]

Bases: lxml.html.InputMixin, lxml.html.HtmlElement

Represents an <input> element.

You can get the type with .type (which is lower-cased and @@ -637,29 +549,29 @@ defaults to 'text'<

Checkboxes and radios have the attribute input.checkable == True (for all others it is false) and a boolean attribute .checked.

-
-
-property checkable¶
+
+
+property checkable

Boolean: can this element be checked?

-
-
-property checked¶
+
+
+property checked

Boolean attribute to get/set the presence of the checked attribute.

You can only use this on checkable input types.

-
-
-property type¶
+
+
+property type

Return the type of this element (using the type attribute).

-
-
-property value¶
+
+
+property value

Get/set the value of this element, using the value attribute.

Also, if this is a checkbox and it has no value, this defaults to 'on'. If it is a checkbox or radio that is not @@ -669,8 +581,8 @@ checked, this returns None.

-
-class lxml.html.InputGetter(form)[source]¶
+
+class lxml.html.InputGetter(form)[source]

Bases: object

An accessor that represents all the input fields in a form.

You can get fields by name from this, with @@ -683,8 +595,8 @@ in this way.

won’t return the same thing as if you get all the names, as checkboxes and radio elements are returned individually.

-
-items()[source]¶
+
+items()[source]

Returns all fields with their names, similar to dict.items().

Returns
@@ -694,8 +606,8 @@ checkboxes and radio elements are returned individually.

-
-keys()[source]¶
+
+keys()[source]

Returns all unique field names, in document order.

Returns
@@ -707,28 +619,28 @@ checkboxes and radio elements are returned individually.

-
-class lxml.html.InputMixin[source]¶
+
+class lxml.html.InputMixin[source]

Bases: object

Mix-in for all input elements (input, select, and textarea)

-
-
-property name¶
+
+
+property name

Get/set the name of the element

-
-class lxml.html.LabelElement[source]¶
+
+class lxml.html.LabelElement[source]

Bases: lxml.html.HtmlElement

Represents a <label> element.

Label elements are linked to other elements with their for attribute. You can access this element with label.for_element.

-
-
-property for_element¶
+
+
+property for_element

Get/set the element this label points to. Return None if it can’t be found.

@@ -736,64 +648,64 @@ can’t be found.

-
-class lxml.html.MultipleSelectOptions(select)[source]¶
+
+class lxml.html.MultipleSelectOptions(select)[source]

Bases: lxml.html._setmixin.SetMixin

Represents all the selected options in a <select multiple> element.

You can add to this set-like option to select an option, or remove to unselect the option.

-
-add(item)[source]¶
+
+add(item)[source]

Add an element.

-
-remove(item)[source]¶
+
+remove(item)[source]

Remove an element. If not a member, raise a KeyError.

-
-_abc_impl = <_abc_data object>¶
+
+_abc_impl = <_abc._abc_data object>
-
-
-property options¶
+
+
+property options

Iterator of all the <option> elements.

-
-class lxml.html.RadioGroup(iterable=(), /)[source]¶
+
+class lxml.html.RadioGroup(iterable=(), /)[source]

Bases: list

This object represents several <input type=radio> elements that have the same name.

You can use this like a list, but also use the property .value to check/uncheck inputs. Also you can use .value_options to get the possible values.

-
-
-property value¶
+
+
+property value

Get/set the value, which checks the radio with that value (and unchecks any other value).

-
-
-property value_options¶
+
+
+property value_options

Returns a list of all the possible values.

-
-class lxml.html.SelectElement[source]¶
+
+class lxml.html.SelectElement[source]

Bases: lxml.html.InputMixin, lxml.html.HtmlElement

<select> element. You can get the name with .name.

.value will be the value of the selected option, unless this @@ -802,23 +714,23 @@ it will be a set-like object. In either case .multiple shows if this is a multi-select.

-
-
-property multiple¶
+
+
+property multiple

Boolean attribute: is there a multiple attribute on this element.

-
-
-property value¶
+
+
+property value

Get/set the value of this select (the selected option).

If this is a multi-select, this is a set-like object that represents all the selected options.

-
-
-property value_options¶
+
+
+property value_options

All the possible values this select can have (the value attribute of all the <option> elements.

@@ -826,22 +738,22 @@ attribute of all the -
-class lxml.html.TextareaElement[source]¶
+
+class lxml.html.TextareaElement[source]

Bases: lxml.html.InputMixin, lxml.html.HtmlElement

<textarea> element. You can get the name with .name and get/set the value with .value

-
-
-property value¶
+
+
+property value

Get/set the value (which is the contents of this element)

-
-class lxml.html.XHTMLParser(**kwargs)[source]¶
+
+class lxml.html.XHTMLParser(**kwargs)[source]

Bases: lxml.etree.XMLParser

An XML parser that is configured to return lxml.html Element objects.

@@ -860,8 +772,8 @@ parser like this:

-
-class lxml.html._MethodFunc(name, copy=False, source_class=<class 'lxml.html.HtmlMixin'>)[source]¶
+
+class lxml.html._MethodFunc(name, copy=False, source_class=<class 'lxml.html.HtmlMixin'>)[source]

Bases: object

An object that represents a method on an element as a function; the function takes either an element or an HTML string. It @@ -871,96 +783,96 @@ of the resulting document.

-
-lxml.html.Element(*args, **kw)[source]¶
+
+lxml.html.Element(*args, **kw)[source]

Create a new HTML Element.

This can also be used for XHTML documents.

-
-lxml.html.__bytes_replace_meta_content_type(repl, string, count=0)¶
+
+lxml.html.__bytes_replace_meta_content_type(repl, string, count=0)

Return the string obtained by replacing the leftmost non-overlapping occurrences of pattern in string by the replacement repl.

-
-lxml.html.__fix_docstring(s)[source]¶
+
+lxml.html.__fix_docstring(s)[source]
-
-lxml.html.__str_replace_meta_content_type(repl, string, count=0)¶
+
+lxml.html.__str_replace_meta_content_type(repl, string, count=0)

Return the string obtained by replacing the leftmost non-overlapping occurrences of pattern in string by the replacement repl.

-
-lxml.html._contains_block_level_tag(el)[source]¶
+
+lxml.html._contains_block_level_tag(el)[source]
-
-lxml.html._element_name(el)[source]¶
+
+lxml.html._element_name(el)[source]
-
-lxml.html._iter_css_imports(string, pos=0, endpos=9223372036854775807)¶
+
+lxml.html._iter_css_imports(string, pos=0, endpos=9223372036854775807)

Return an iterator over all non-overlapping matches for the RE pattern in string.

For each match, the iterator returns a match object.

-
-lxml.html._iter_css_urls(string, pos=0, endpos=9223372036854775807)¶
+
+lxml.html._iter_css_urls(string, pos=0, endpos=9223372036854775807)

Return an iterator over all non-overlapping matches for the RE pattern in string.

For each match, the iterator returns a match object.

-
-lxml.html._looks_like_full_html_bytes(string, pos=0, endpos=9223372036854775807)¶
+
+lxml.html._looks_like_full_html_bytes(string, pos=0, endpos=9223372036854775807)

Matches zero or more characters at the beginning of the string.

-
-lxml.html._looks_like_full_html_unicode(string, pos=0, endpos=9223372036854775807)¶
+
+lxml.html._looks_like_full_html_unicode(string, pos=0, endpos=9223372036854775807)

Matches zero or more characters at the beginning of the string.

-
-lxml.html._nons(tag)[source]¶
+
+lxml.html._nons(tag)[source]
-
-lxml.html._parse_meta_refresh_url(string, pos=0, endpos=9223372036854775807)¶
+
+lxml.html._parse_meta_refresh_url(string, pos=0, endpos=9223372036854775807)

Scan through string looking for a match, and return a corresponding match object instance.

Return None if no position in the string matches.

-
-lxml.html._transform_result(typ, result)[source]¶
+
+lxml.html._transform_result(typ, result)[source]

Convert the result back into the input type.

-
-lxml.html._unquote_match(s, pos)[source]¶
+
+lxml.html._unquote_match(s, pos)[source]
-
-lxml.html.document_fromstring(html, parser=None, ensure_head_body=False, **kw)[source]¶
+
+lxml.html.document_fromstring(html, parser=None, ensure_head_body=False, **kw)[source]
-
-lxml.html.fragment_fromstring(html, create_parent=False, base_url=None, parser=None, **kw)[source]¶
+
+lxml.html.fragment_fromstring(html, create_parent=False, base_url=None, parser=None, **kw)[source]

Parses a single HTML element; it is an error if there is more than one element, or if anything but whitespace precedes or follows the element.

@@ -973,8 +885,8 @@ as result of the parsing.

-
-lxml.html.fragments_fromstring(html, no_leading_text=False, base_url=None, parser=None, **kw)[source]¶
+
+lxml.html.fragments_fromstring(html, no_leading_text=False, base_url=None, parser=None, **kw)[source]

Parses several HTML elements, returning a list of elements.

The first item in the list may be a string. If no_leading_text is true, then it will be an error if there is @@ -984,8 +896,8 @@ leading text, and it will always be a list of only elements.

-
-lxml.html.fromstring(html, base_url=None, parser=None, **kw)[source]¶
+
+lxml.html.fromstring(html, base_url=None, parser=None, **kw)[source]

Parse the html, returning a single element/document.

This tries to minimally parse the chunk of text, without knowing if it is a fragment or a document.

@@ -993,28 +905,28 @@ is a fragment or a document.

-
-lxml.html.html_to_xhtml(html)[source]¶
+
+lxml.html.html_to_xhtml(html)[source]

Convert all tags in an HTML tree to XHTML by moving them to the XHTML namespace.

-
-lxml.html.open_http_urllib(method, url, values)[source]¶
+
+lxml.html.open_http_urllib(method, url, values)[source]
-
-lxml.html.open_in_browser(doc, encoding=None)[source]¶
+
+lxml.html.open_in_browser(doc, encoding=None)[source]

Open the HTML document in a web browser, saving it to a temporary file to open it. Note that this does not delete the file after use. This is mainly meant for debugging.

-
-lxml.html.parse(filename_or_url, parser=None, base_url=None, **kw)[source]¶
+
+lxml.html.parse(filename_or_url, parser=None, base_url=None, **kw)[source]

Parse a filename, URL, or file-like object into an HTML document tree. Note: this returns a tree, not an element. Use parse(...).getroot() to get the document root.

@@ -1023,8 +935,8 @@ is most useful when parsing from a file-like object.

-
-lxml.html.submit_form(form, extra_values=None, open_http=None)[source]¶
+
+lxml.html.submit_form(form, extra_values=None, open_http=None)[source]

Helper function to submit a form. Returns a file-like object, as from urllib.urlopen(). This object also has a .geturl() function, which shows the URL if there were any redirects.

@@ -1048,8 +960,8 @@ form data.

-
-lxml.html.tostring(doc, pretty_print=False, include_meta_content_type=False, encoding=None, method='html', with_tail=True, doctype=None)[source]¶
+
+lxml.html.tostring(doc, pretty_print=False, include_meta_content_type=False, encoding=None, method='html', with_tail=True, doctype=None)[source]

Return an HTML string representation of the document.

Note: if include_meta_content_type is true this will create a <meta http-equiv="Content-Type" ...> tag in the head; @@ -1108,69 +1020,44 @@ when serialising an ElementTree instance.

-
-lxml.html.xhtml_to_html(xhtml)[source]¶
+
+lxml.html.xhtml_to_html(xhtml)[source]

Convert all tags in an XHTML tree to HTML by removing their XHTML namespace.

- - + + - - - - - - - - - - - - + \ No newline at end of file diff --git a/doc/html/apidoc/lxml.html.html5parser.html b/doc/html/apidoc/lxml.html.html5parser.html index 53791f9..a5a1264 100644 --- a/doc/html/apidoc/lxml.html.html5parser.html +++ b/doc/html/apidoc/lxml.html.html5parser.html @@ -1,75 +1,38 @@ - - - - - - - lxml.html.html5parser module — lxml documentation - - - - - + - - - - - - + + lxml.html.html5parser module — lxml documentation + + - - + - - - - - + - - - +
- -
- - -
- - - - - - - - + \ No newline at end of file diff --git a/doc/html/apidoc/lxml.html.soupparser.html b/doc/html/apidoc/lxml.html.soupparser.html index 3a45aaa..de0f5f2 100644 --- a/doc/html/apidoc/lxml.html.soupparser.html +++ b/doc/html/apidoc/lxml.html.soupparser.html @@ -1,75 +1,38 @@ - - - - - - - lxml.html.soupparser module — lxml documentation - - - - - + - - - - - - + + lxml.html.soupparser module — lxml documentation + + - - + - - - - - + - - - +
- -
- - -
- - - - - - - - + \ No newline at end of file diff --git a/doc/html/apidoc/lxml.isoschematron.html b/doc/html/apidoc/lxml.isoschematron.html index ff2a05b..4526a55 100644 --- a/doc/html/apidoc/lxml.isoschematron.html +++ b/doc/html/apidoc/lxml.isoschematron.html @@ -1,75 +1,38 @@ - - - - - - - lxml.isoschematron package — lxml documentation - - - - - + - - - - - - + + lxml.isoschematron package — lxml documentation + + - - + - - - - - + - - - +
- -
- - -
-
-lxml.isoschematron._stylesheet_param_dict(paramsDict, kwargsDict)[source]¶
+
+lxml.isoschematron._stylesheet_param_dict(paramsDict, kwargsDict)[source]

Return a copy of paramsDict, updated with kwargsDict entries, wrapped as stylesheet arguments. kwargsDict entries with a value of None are ignored.

-
-lxml.isoschematron.stylesheet_params(**kwargs)[source]¶
+
+lxml.isoschematron.stylesheet_params(**kwargs)[source]

Convert keyword args to a dictionary of stylesheet parameters. XSL stylesheet parameters must be XPath expressions, i.e.:

    @@ -382,63 +294,38 @@ If arg is None raise TypeError. Else convert arg to string.

- - + + - - - - - - - - - - - - + \ No newline at end of file diff --git a/doc/html/apidoc/lxml.objectify.html b/doc/html/apidoc/lxml.objectify.html index 7c95731..a42f7bc 100644 --- a/doc/html/apidoc/lxml.objectify.html +++ b/doc/html/apidoc/lxml.objectify.html @@ -1,75 +1,38 @@ - - - - - - - lxml.objectify module — lxml documentation - - - - - + - - - - - - + + lxml.objectify module — lxml documentation + + - - + - - - - - + - - - +
- -
- - -
- - - - - - - - - - - - + \ No newline at end of file diff --git a/doc/html/apidoc/lxml.sax.html b/doc/html/apidoc/lxml.sax.html index 8fb4163..5e31cce 100644 --- a/doc/html/apidoc/lxml.sax.html +++ b/doc/html/apidoc/lxml.sax.html @@ -1,74 +1,37 @@ - - - - - - - lxml.sax module — lxml documentation - - - - - + - - - - - - + + lxml.sax module — lxml documentation + + - - + - - - - - + - - - +
- -
- - -
- - - - - - - - - - - - + \ No newline at end of file diff --git a/doc/html/apidoc/py-modindex.html b/doc/html/apidoc/py-modindex.html index 75cf09a..a8050a9 100644 --- a/doc/html/apidoc/py-modindex.html +++ b/doc/html/apidoc/py-modindex.html @@ -1,39 +1,20 @@ - - - - - - + + Python Module Index — lxml documentation - - - - - - - - - - - - + + - - + - - - - - + @@ -41,36 +22,17 @@ - - - +
- -
- - -
- - - - - - - - + \ No newline at end of file diff --git a/doc/html/apidoc/search.html b/doc/html/apidoc/search.html index c119ba2..d5cf86a 100644 --- a/doc/html/apidoc/search.html +++ b/doc/html/apidoc/search.html @@ -1,75 +1,38 @@ - - - - - - + + Search — lxml documentation - - - - - - - - - - - - + + - - + - - - - - - + + + - - - +
- -
- - -
- - - - - - - - - - + diff --git a/doc/html/build.html b/doc/html/build.html index 9130ad3..3652aac 100644 --- a/doc/html/build.html +++ b/doc/html/build.html @@ -2,7 +2,7 @@ - + How to build lxml from source
-

How to build lxml from source

+

How to build lxml from source

To build lxml from source, you need libxml2 and libxslt properly installed, including the header files. These are likely shipped in @@ -317,7 +317,7 @@ installed using dpkg -i

diff --git a/doc/html/capi.html b/doc/html/capi.html index 405df7e..95ffc01 100644 --- a/doc/html/capi.html +++ b/doc/html/capi.html @@ -2,7 +2,7 @@ - + The public C-API of lxml.etree
-

The public C-API of lxml.etree

+

The public C-API of lxml.etree

As of version 1.1, lxml.etree provides a public C-API. This allows external C extensions to efficiently access public functions and classes of lxml, without going through the Python API.

The API is described in the file etreepublic.pxd, which is directly -c-importable by extension modules implemented in Pyrex or Cython.

+c-importable by extension modules implemented in Cython.

Contents

    @@ -57,8 +57,8 @@ of the C function adoptExternalDocument().

Writing external modules in Cython

-

This is the easiest way of extending lxml at the C level. A Cython -(or Pyrex) module should start like this:

+

This is the easiest way of extending lxml at the C level. A Cython +module should start like this:

 # My Cython extension
 
@@ -102,29 +102,29 @@ etree.set_element_class_lookup(
 

If you really feel like it, you can also interface with lxml.etree straight from C code. All you have to do is include the header file for the public API, import the lxml.etree module and then call the import function:

-
/* My C extension */
+
/* My C extension */
 
-/* common includes */
-#include "Python.h"
-#include "stdio.h"
-#include "string.h"
-#include "stdarg.h"
-#include "libxml/xmlversion.h"
-#include "libxml/encoding.h"
-#include "libxml/hash.h"
-#include "libxml/tree.h"
-#include "libxml/xmlIO.h"
-#include "libxml/xmlsave.h"
-#include "libxml/globals.h"
-#include "libxml/xmlstring.h"
+/* common includes */
+#include "Python.h"
+#include "stdio.h"
+#include "string.h"
+#include "stdarg.h"
+#include "libxml/xmlversion.h"
+#include "libxml/encoding.h"
+#include "libxml/hash.h"
+#include "libxml/tree.h"
+#include "libxml/xmlIO.h"
+#include "libxml/xmlsave.h"
+#include "libxml/globals.h"
+#include "libxml/xmlstring.h"
 
-/* lxml.etree specific includes */
-#include "lxml-version.h"
-#include "etree_defs.h"
-#include "etree.h"
+/* lxml.etree specific includes */
+#include "lxml-version.h"
+#include "etree_defs.h"
+#include "etree.h"
 
-/* setup code */
-import_lxml__etree()
+/* setup code */
+import_lxml__etree()
 

Note that including etree.h does not automatically include the header files it requires. Note also that the above list of common @@ -133,7 +133,7 @@ includes may not be sufficient.

diff --git a/doc/html/changes-4.6.3.html b/doc/html/changes-4.6.3.html deleted file mode 100644 index 0ce06bb..0000000 --- a/doc/html/changes-4.6.3.html +++ /dev/null @@ -1,3712 +0,0 @@ - - - - - - -lxml changelog - - - -
-

lxml changelog

- -
-

4.6.3 (2021-03-21)

-
-

Bugs fixed

-
    -
  • A vulnerability (CVE-2021-28957) was discovered in the HTML Cleaner by Kevin Chung, -which allowed JavaScript to pass through. The cleaner now removes the HTML5 -formaction attribute.
  • -
-
-
-
-

4.6.2 (2020-11-26)

-
-

Bugs fixed

-
    -
  • A vulnerability (CVE-2020-27783) was discovered in the HTML Cleaner by Yaniv Nizry, -which allowed JavaScript to pass through. The cleaner now removes more sneaky -"style" content.
  • -
-
-
-
-

4.6.1 (2020-10-18)

-
-

Bugs fixed

-
    -
  • A vulnerability was discovered in the HTML Cleaner by Yaniv Nizry, which allowed -JavaScript to pass through. The cleaner now removes more sneaky "style" content.
  • -
-
-
-
-

4.6.0 (2020-10-17)

-
-

Features added

-
    -
  • GH#310: lxml.html.InputGetter supports __len__() to count the number of input fields. -Patch by Aidan Woolley.
  • -
  • lxml.html.InputGetter has a new .items() method to ease processing all input fields.
  • -
  • lxml.html.InputGetter.keys() now returns the field names in document order.
  • -
  • GH-309: The API documentation is now generated using sphinx-apidoc. -Patch by Chris Mayo.
  • -
-
-
-

Bugs fixed

-
    -
  • LP#1869455: C14N 2.0 serialisation failed for unprefixed attributes -when a default namespace was defined.
  • -
  • TreeBuilder.close() raised AssertionError in some error cases where it -should have raised XMLSyntaxError. It now raises a combined exception to -keep up backwards compatibility, while switching to XMLSyntaxError as an -interface.
  • -
-
-
-
-

4.5.2 (2020-07-09)

-
-

Bugs fixed

-
    -
  • Cleaner() now validates that only known configuration options can be set.
  • -
  • LP#1882606: Cleaner.clean_html() discarded comments and PIs regardless of the -corresponding configuration option, if remove_unknown_tags was set.
  • -
  • LP#1880251: Instead of globally overwriting the document loader in libxml2, lxml now -sets it per parser run, which improves the interoperability with other users of libxml2 -such as libxmlsec.
  • -
  • LP#1881960: Fix build in CPython 3.10 by using Cython 0.29.21.
  • -
  • The setup options "--with-xml2-config" and "--with-xslt-config" were accidentally renamed -to "--xml2-config" and "--xslt-config" in 4.5.1 and are now available again.
  • -
-
-
-
-

4.5.1 (2020-05-19)

-
-

Bugs fixed

-
    -
  • LP#1570388: Fix failures when serialising documents larger than 2GB in some cases.
  • -
  • LP#1865141, GH#298: QName values were not accepted by the el.iter() method. -Patch by xmo-odoo.
  • -
  • LP#1863413, GH#297: The build failed to detect libraries on Linux that are only -configured via pkg-config. -Patch by Hugh McMaster.
  • -
-
-
-
-

4.5.0 (2020-01-29)

-
-

Features added

-
    -
  • A new function indent() was added to insert tail whitespace for pretty-printing -an XML tree.
  • -
-
-
-

Bugs fixed

-
    -
  • LP#1857794: Tail text of nodes that get removed from a document using item -deletion disappeared silently instead of sticking with the node that was removed.
  • -
-
-
-

Other changes

-
    -
  • MacOS builds are 64-bit-only by default. -Set CFLAGS and LDFLAGS explicitly to override it.
  • -
  • Linux/MacOS Binary wheels now use libxml2 2.9.10 and libxslt 1.1.34.
  • -
  • LP#1840234: The package version number is now available as lxml.__version__.
  • -
-
-
-
-

4.4.3 (2020-01-28)

-
-

Bugs fixed

-
    -
  • LP#1844674: itertext() was missing tail text of comments and PIs since 4.4.0.
  • -
-
-
-
-

4.4.2 (2019-11-25)

-
-

Bugs fixed

-
    -
  • LP#1835708: ElementInclude incorrectly rejected repeated non-recursive -includes as recursive. -Patch by Rainer Hausdorf.
  • -
-
-
-
-

4.4.1 (2019-08-11)

-
-

Bugs fixed

-
    -
  • LP#1838252: The order of an OrderedDict was lost in 4.4.0 when passing it as -attrib mapping during element creation.
  • -
  • LP#1838521: The package metadata now lists the supported Python versions.
  • -
-
-
-
-

4.4.0 (2019-07-27)

-
-

Features added

-
    -
  • Element.clear() accepts a new keyword argument keep_tail=True to clear -everything but the tail text. This is helpful in some document-style use cases -and for clearing the current element in iterparse() and pull parsing.
  • -
  • When creating attributes or namespaces from a dict in Python 3.6+, lxml now -preserves the original insertion order of that dict, instead of always sorting -the items by name. A similar change was made for ElementTree in CPython 3.8. -See https://bugs.python.org/issue34160
  • -
  • Integer elements in lxml.objectify implement the __index__() special method.
  • -
  • GH#269: Read-only elements in XSLT were missing the nsmap property. -Original patch by Jan Pazdziora.
  • -
  • ElementInclude can now restrict the maximum inclusion depth via a max_depth -argument to prevent content explosion. It is limited to 6 by default.
  • -
  • The target object of the XMLParser can have start_ns() and end_ns() -callback methods to listen to namespace declarations.
  • -
  • The TreeBuilder has new arguments comment_factory and pi_factory to -pass factories for creating comments and processing instructions, as well as -flag arguments insert_comments and insert_pis to discard them from the -tree when set to false.
  • -
  • A C14N 2.0 implementation was added as -etree.canonicalize(), a corresponding C14NWriterTarget class, and -a c14n2 serialisation method.
  • -
-
-
-

Bugs fixed

-
    -
  • When writing to file paths that contain the URL escape character '%', the file -path could wrongly be mangled by URL unescaping and thus write to a different -file or directory. Code that writes to file paths that are provided by untrusted -sources, but that must work with previous versions of lxml, should best either -reject paths that contain '%' characters, or otherwise make sure that the path -does not contain maliciously injected '%XX' URL hex escapes for paths like '../'.
  • -
  • Assigning to Element child slices with negative step could insert the slice at -the wrong position, starting too far on the left.
  • -
  • Assigning to Element child slices with overly large step size could take very -long, regardless of the length of the actual slice.
  • -
  • Assigning to Element child slices of the wrong size could sometimes fail to -raise a ValueError (like a list assignment would) and instead assign outside -of the original slice bounds or leave parts of it unreplaced.
  • -
  • The comment and pi events in iterwalk() were never triggered, and -instead, comments and processing instructions in the tree were reported as -start elements. Also, when walking an ElementTree (as opposed to its root -element), comments and PIs outside of the root element are now reported.
  • -
  • LP#1827833: The RelaxNG compact syntax support was broken with recent versions -of rnc2rng.
  • -
  • LP#1758553: The HTML elements source and track were added to the list -of empty tags in lxml.html.defs.
  • -
  • Registering a prefix other than "xml" for the XML namespace is now rejected.
  • -
  • Failing to write XSLT output to a file could raise a misleading exception. -It now raises IOError.
  • -
-
-
-

Other changes

-
    -
  • Support for Python 3.4 was removed.
  • -
  • When using Element.find*() with prefix-namespace mappings, the empty string -is now accepted to define a default namespace, in addition to the previously -supported None prefix. Empty strings are more convenient since they keep -all prefix keys in a namespace dict strings, which simplifies sorting etc.
  • -
  • The ElementTree.write_c14n() method has been deprecated in favour of the -long preferred ElementTree.write(f, method="c14n"). It will be removed -in a future release.
  • -
-
-
-
-

4.3.5 (2019-07-27)

-
    -
  • Rebuilt with Cython 0.29.13 to support Python 3.8.
  • -
-
-
-

4.3.4 (2019-06-10)

-
    -
  • Rebuilt with Cython 0.29.10 to support Python 3.8.
  • -
-
-
-

4.3.3 (2019-03-26)

-
-

Bugs fixed

-
    -
  • Fix leak of output buffer and unclosed files in _XSLTResultTree.write_output().
  • -
-
-
-
-

4.3.2 (2019-02-29)

-
-

Bugs fixed

-
    -
  • Crash in 4.3.1 when appending a child subtree with certain text nodes.
  • -
-
-
-

Other changes

-
    -
  • Built with Cython 0.29.6.
  • -
-
-
-
-

4.3.1 (2019-02-08)

-
-

Bugs fixed

-
    -
  • LP#1814522: Crash when appending a child subtree that contains unsubstituted -entity references.
  • -
-
-
-

Other changes

-
    -
  • Built with Cython 0.29.5.
  • -
-
-
-
-

4.3.0 (2019-01-04)

-
-

Features added

-
    -
  • The module lxml.sax is compiled using Cython in order to speed it up.
  • -
  • GH#267: lxml.sax.ElementTreeProducer now preserves the namespace prefixes. -If two prefixes point to the same URI, the first prefix in alphabetical order -is used. Patch by Lennart Regebro.
  • -
  • Updated ISO-Schematron implementation to 2013 version (now MIT licensed) -and the corresponding schema to the 2016 version (with optional "properties").
  • -
-
-
-

Other changes

-
    -
  • GH#270, GH#271: Support for Python 2.6 and 3.3 was removed. -Patch by hugovk.
  • -
  • The minimum dependency versions were raised to libxml2 2.9.2 and libxslt 1.1.27, -which were released in 2014 and 2012 respectively.
  • -
  • Built with Cython 0.29.2.
  • -
-
-
-
-

4.2.6 (2019-01-02)

-
-

Bugs fixed

-
    -
  • LP#1799755: Fix a DeprecationWarning in Py3.7+.
  • -
  • Import warnings in Python 3.6+ were resolved.
  • -
-
-
-
-

4.2.5 (2018-09-09)

-
-

Bugs fixed

-
    -
  • Javascript URLs that used URL escaping were not removed by the HTML cleaner. -Security problem found by Omar Eissa. (CVE-2018-19787)
  • -
-
-
-
-

4.2.4 (2018-08-03)

-
-

Features added

-
    -
  • GH#259: Allow using pkg-config for build configuration. -Patch by Patrick Griffis.
  • -
-
-
-

Bugs fixed

-
    -
  • LP#1773749, GH#268: Crash when moving an element to another document with -Element.insert(). -Patch by Alexander Weggerle.
  • -
-
-
-
-

4.2.3 (2018-06-27)

-
-

Bugs fixed

-
    -
  • Reverted GH#265: lxml links against zlib as a shared library again.
  • -
-
-
-
-

4.2.2 (2018-06-22)

-
-

Bugs fixed

-
    -
  • GH#266: Fix sporadic crash during GC when parse-time schema validation is used -and the parser participates in a reference cycle. -Original patch by Julien Greard.
  • -
  • GH#265: lxml no longer links against zlib as a shared library, only on static builds. -Patch by Nehal J Wani.
  • -
-
-
-
-

4.2.1 (2018-03-21)

-
-

Bugs fixed

-
    -
  • LP#1755825: iterwalk() failed to return the 'start' event for the initial -element if a tag selector is used.
  • -
  • LP#1756314: Failure to import 4.2.0 into PyPy due to a missing library symbol.
  • -
  • LP#1727864, GH#258: Add "-isysroot" linker option on MacOS as needed by XCode 9.
  • -
-
-
-
-

4.2.0 (2018-03-13)

-
-

Features added

-
    -
  • GH#255: SelectElement.value returns more standard-compliant and -browser-like defaults for non-multi-selects. If no option is selected, the -value of the first option is returned (instead of None). If multiple options -are selected, the value of the last one is returned (instead of that of the -first one). If no options are present (not standard-compliant) -SelectElement.value still returns None.
  • -
  • GH#261: The HTMLParser() now supports the huge_tree option. -Patch by stranac.
  • -
-
-
-

Bugs fixed

-
    -
  • LP#1551797: Some XSLT messages were not captured by the transform error log.
  • -
  • LP#1737825: Crash at shutdown after an interrupted iterparse run with XMLSchema -validation.
  • -
-
-
-

Other changes

-
-
-
-

4.1.1 (2017-11-04)

-
    -
  • Rebuild with Cython 0.27.3 to improve support for Py3.7.
  • -
-
-
-

4.1.0 (2017-10-13)

-
-

Features added

-
    -
  • ElementPath supports text predicates for current node, like "[.='text']".
  • -
  • ElementPath allows spaces in predicates.
  • -
  • Custom Element classes and XPath functions can now be registered with a -decorator rather than explicit dict assignments.
  • -
  • Static Linux wheels are now built with link time optimisation (LTO) enabled. -This should have a beneficial impact on the overall performance by providing -a tighter compiler integration between lxml and libxml2/libxslt.
  • -
-
-
-

Bugs fixed

-
    -
  • LP#1722776: Requesting non-Element objects like comments from a document with -PythonElementClassLookup could fail with a TypeError.
  • -
-
-
-
-

4.0.0 (2017-09-17)

-
-

Features added

-
    -
  • The ElementPath implementation is now compiled using Cython, -which speeds up the .find*() methods quite significantly.
  • -
  • The modules lxml.builder, lxml.html.diff and lxml.html.clean -are also compiled using Cython in order to speed them up.
  • -
  • xmlfile() supports async coroutines using async with and await.
  • -
  • iterwalk() has a new method skip_subtree() that prevents walking into -the descendants of the current element.
  • -
  • RelaxNG.from_rnc_string() accepts a base_url argument to -allow relative resource lookups.
  • -
  • The XSLT result object has a new method .write_output(file) that serialises -output data into a file according to the <xsl:output> configuration.
  • -
-
-
-

Bugs fixed

-
    -
  • GH#251: HTML comments were handled incorrectly by the soupparser. -Patch by mozbugbox.

    -
  • -
  • LP#1654544: The html5parser no longer passes the useChardet option -if the input is a Unicode string, unless explicitly requested. When parsing -files, the default is to enable it when a URL or file path is passed (because -the file is then opened in binary mode), and to disable it when reading from -a file(-like) object.

    -

    Note: This is a backwards incompatible change of the default configuration. -If your code parses byte strings/streams and depends on character detection, -please pass the option guess_charset=True explicitly, which already worked -in older lxml versions.

    -
  • -
  • LP#1703810: etree.fromstring() failed to parse UTF-32 data with BOM.

    -
  • -
  • LP#1526522: Some RelaxNG errors were not reported in the error log.

    -
  • -
  • LP#1567526: Empty and plain text input raised a TypeError in soupparser.

    -
  • -
  • LP#1710429: Uninitialised variable usage in HTML diff.

    -
  • -
  • LP#1415643: The closing tags context manager in xmlfile() could continue -to output end tags even after writing failed with an exception.

    -
  • -
  • LP#1465357: xmlfile.write() now accepts and ignores None as input argument.

    -
  • -
  • Compilation under Py3.7-pre failed due to a modified function signature.

    -
  • -
-
-
-

Other changes

-
    -
  • The main module source files were renamed from lxml.*.pyx to plain -*.pyx (e.g. etree.pyx) to simplify their handling in the build -process. Care was taken to keep the old header files as fallbacks for -code that compiles against the public C-API of lxml, but it might still -be worth validating that third-party code does not notice this change.
  • -
-
-
-
-

3.8.0 (2017-06-03)

-
-

Features added

-
    -
  • ElementTree.write() has a new option doctype that writes out a -doctype string before the serialisation, in the same way as tostring().
  • -
  • GH#220: xmlfile allows switching output methods at an element level. -Patch by Burak Arslan.
  • -
  • LP#1595781, GH#240: added a PyCapsule Python API and C-level API for -passing externally generated libxml2 documents into lxml.
  • -
  • GH#244: error log entries have a new property path with an XPath -expression (if known, None otherwise) that points to the tree element -responsible for the error. Patch by Bob Kline.
  • -
  • The namespace prefix mapping that can be used in ElementPath now injects -a default namespace when passing a None prefix.
  • -
-
-
-

Bugs fixed

-
    -
  • GH#238: Character escapes were not hex-encoded in the xmlfile serialiser. -Patch by matejcik.
  • -
  • GH#229: fix for externally created XML documents. Patch by Theodore Dubois.
  • -
  • LP#1665241, GH#228: Form data handling in lxml.html no longer strips the -option values specified in form attributes but only the text values. -Patch by Ashish Kulkarni.
  • -
  • LP#1551797: revert previous fix for XSLT error logging as it breaks -multi-threaded XSLT processing.
  • -
  • LP#1673355, GH#233: fromstring() html5parser failed to parse byte strings.
  • -
-
-
-

Other changes

-
    -
  • The previously undocumented docstring option in ElementTree.write() -produces a deprecation warning and will eventually be removed.
  • -
-
-
-
-

3.7.4 (2017-??-??)

-
-

Bugs fixed

-
    -
  • LP#1551797: revert previous fix for XSLT error logging as it breaks -multi-threaded XSLT processing.
  • -
  • LP#1673355, GH#233: fromstring() html5parser failed to parse byte strings.
  • -
-
-
-
-

3.7.3 (2017-02-18)

-
-

Bugs fixed

-
    -
  • GH#218 was ineffective in Python 3.
  • -
  • GH#222: lxml.html.submit_form() failed in Python 3. -Patch by Jakub Wilk.
  • -
-
-
-
-

3.7.2 (2017-01-08)

-
    -
  • GH#220: xmlfile allows switching output methods at an element level. -Patch by Burak Arslan.
  • -
-
-

Bugs fixed

-
    -
  • Work around installation problems in recent Python 2.7 versions -due to FTP download failures.
  • -
  • GH#219: xmlfile.element() was not properly quoting attribute values. -Patch by Burak Arslan.
  • -
  • GH#218: xmlfile.element() was not properly escaping text content of -script/style tags. Patch by Burak Arslan.
  • -
-
-
-
-

3.7.1 (2016-12-23)

-
    -
  • No source changes, issued only to solve problems with the -binary packages released for 3.7.0.
  • -
-
-
-

3.7.0 (2016-12-10)

-
-

Features added

-
    -
  • GH#217: XMLSyntaxError now behaves more like its SyntaxError -baseclass. Patch by Philipp A.
  • -
  • GH#216: HTMLParser() now supports the same collect_ids parameter -as XMLParser(). Patch by Burak Arslan.
  • -
  • GH#210: Allow specifying a serialisation method in xmlfile.write(). -Patch by Burak Arslan.
  • -
  • GH#203: New option default_doctype in HTMLParser that allows -disabling the automatic doctype creation. Patch by Shadab Zafar.
  • -
  • GH#201: Calling the method .set('attrname') without value argument -(or None) on HTML elements creates an attribute without value that -serialises like <div attrname></div>. Patch by Daniel Holth.
  • -
  • GH#197: Ignore form input fields in form_values() when they are -marked as disabled in HTML. Patch by Kristian Klemon.
  • -
-
-
-

Bugs fixed

-
    -
  • GH#206: File name and line number were missing from XSLT error messages. -Patch by Marcus Brinkmann.
  • -
-
-
-

Other changes

-
    -
  • Log entries no longer allow anything but plain string objects as message text -and file name.
  • -
  • zlib is included in the list of statically built libraries.
  • -
-
-
-
-

3.6.4 (2016-08-20)

- -
-
-

3.6.3 (2016-08-18)

-
    -
  • LP#1614603: change linker flags to build multi-linux wheels
  • -
-
-
-

3.6.2 (2016-08-18)

-
    -
  • LP#1614603: release without source changes to provide cleanly built Linux wheels
  • -
-
-
-

3.6.1 (2016-07-24)

-
-

Features added

-
    -
  • GH#180: Separate option inline_style for Cleaner that only removes style -attributes instead of all styles. Patch by Christian Pedersen.
  • -
  • GH#196: Windows build support for Python 3.5. Contribution by Maximilian Hils.
  • -
-
-
-

Bugs fixed

-
    -
  • GH#199: Exclude file fields from FormElement.form_values (as browsers do). -Patch by Tomas Divis.
  • -
  • GH#198, LP#1568167: Try to provide base URL from Resolver.resolve_string(). -Patch by Michael van Tellingen.
  • -
  • GH#191: More accurate float serialisation in objectify.FloatElement. -Patch by Holger Joukl.
  • -
  • LP#1551797: Repair XSLT error logging. Patch by Marcus Brinkmann.
  • -
-
-
-
-

3.6.0 (2016-03-17)

-
-

Features added

-
    -
  • GH#187: Now supports (only) version 5.x and later of PyPy. -Patch by Armin Rigo.
  • -
  • GH#181: Direct support for .rnc files in RelaxNG() if rnc2rng -is installed. Patch by Dirkjan Ochtman.
  • -
-
-
-

Bugs fixed

-
    -
  • GH#189: Static builds honour FTP proxy configurations when downloading -the external libs. Patch by Youhei Sakurai.
  • -
  • GH#186: Soupparser failed to process entities in Python 3.x. -Patch by Duncan Morris.
  • -
  • GH#185: Rare encoding related TypeError on import was fixed. -Patch by Petr Demin.
  • -
-
-
-
-

3.5.0 (2015-11-13)

-
-

Bugs fixed

-
    -
  • Unicode string results failed XPath queries in PyPy.
  • -
  • LP#1497051: HTML target parser failed to terminate on exceptions -and continued parsing instead.
  • -
  • Deprecated API usage in doctestcompare.
  • -
-
-
-
-

3.5.0b1 (2015-09-18)

-
-

Features added

-
    -
  • cleanup_namespaces() accepts a new argument keep_ns_prefixes -that does not remove definitions of the provided prefix-namespace -mapping from the tree.
  • -
  • cleanup_namespaces() accepts a new argument top_nsmap that -moves definitions of the provided prefix-namespace mapping to the -top of the tree.
  • -
  • LP#1490451: Element objects gained a cssselect() method as -known from lxml.html. Patch by Simon Sapin.
  • -
  • API functions and methods behave and look more like Python functions, -which allows introspection on them etc. One side effect to be aware of -is that the functions now bind as methods when assigned to a class -variable. A quick fix is to wrap them in staticmethod() (as for -normal Python functions).
  • -
  • ISO-Schematron support gained an option error_finder that allows -passing a filter function for picking validation errors from reports.
  • -
  • LP#1243600: Elements in lxml.html gained a classes property -that provides a set-like interface to the class attribute. -Original patch by masklinn.
  • -
  • LP#1341964: The soupparser now handles DOCTYPE declarations, comments -and processing instructions outside of the root element. -Patch by Olli Pottonen.
  • -
  • LP#1421512: The docinfo of a tree was made editable to allow -setting and removing the public ID and system ID of the DOCTYPE. -Patch by Olli Pottonen.
  • -
  • LP#1442427: More work-arounds for quirks and bugs in pypy and pypy3.
  • -
  • lxml.html.soupparser now uses BeautifulSoup version 4 instead -of version 3 if available.
  • -
-
-
-

Bugs fixed

-
    -
  • Memory errors that occur during tree adaptations (e.g. moving subtrees -to foreign documents) could leave the tree in a crash prone state.
  • -
  • Calling process_children() in an XSLT extension element without -an output_parent argument failed with a TypeError. -Fix by Jens Tröger.
  • -
  • GH#162: Image data in HTML data URLs is considered safe and -no longer removed by lxml.html.clean JavaScript cleaner.
  • -
  • GH#166: Static build could link libraries in wrong order.
  • -
  • GH#172: Rely a bit more on libxml2 for encoding detection rather than -rolling our own in some cases. Patch by Olli Pottonen.
  • -
  • GH#159: Validity checks for names and string content were tightened -to detect the use of illegal characters early. Patch by Olli Pottonen.
  • -
  • LP#1421921: Comments/PIs before the DOCTYPE declaration were not -serialised. Patch by Olli Pottonen.
  • -
  • LP#659367: Some HTML DOCTYPE declarations were not serialised. -Patch by Olli Pottonen.
  • -
  • LP#1238503: lxml.doctestcompare is now consistent with stdlib's doctest -in how it uses + and - to refer to unexpected and missing output.
  • -
  • Empty prefixes are explicitly rejected when a namespace mapping is used -with ElementPath to avoid hiding bugs in user code.
  • -
  • Several problems with PyPy were fixed by switching to Cython 0.23.
  • -
-
-
-
-

3.4.4 (2015-04-25)

-
-

Bugs fixed

-
    -
  • An ElementTree compatibility test added in lxml 3.4.3 that failed in -Python 3.4+ was removed again.
  • -
-
-
-
-

3.4.3 (2015-04-15)

-
-

Bugs fixed

-
    -
  • Expression cache in ElementPath was ignored. Fix by Changaco.
  • -
  • LP#1426868: Passing a default namespace and a prefixed namespace mapping -as nsmap into xmlfile.element() raised a TypeError.
  • -
  • LP#1421927: DOCTYPE system URLs were incorrectly quoted when containing -double quotes. Patch by Olli Pottonen.
  • -
  • LP#1419354: meta-redirect URLs were incorrectly processed by -iterlinks() if preceded by whitespace.
  • -
-
-
-
-

3.4.2 (2015-02-07)

-
-

Bugs fixed

-
    -
  • LP#1415907: Crash when creating an XMLSchema from a non-root element -of an XML document.
  • -
  • LP#1369362: HTML cleaning failed when hitting processing instructions -with pseudo-attributes.
  • -
  • CDATA() wrapped content was rejected for tail text.
  • -
  • CDATA sections were not serialised as tail text of the top-level element.
  • -
-
-
-
-

3.4.1 (2014-11-20)

-
-

Features added

-
    -
  • New htmlfile HTML generator to accompany the incremental xmlfile -serialisation API. Patch by Burak Arslan.
  • -
-
-
-

Bugs fixed

-
    -
  • lxml.sax.ElementTreeContentHandler did not initialise its superclass.
  • -
-
-
-
-

3.4.0 (2014-09-10)

-
-

Features added

-
    -
  • xmlfile(buffered=False) disables output buffering and flushes the -content after each API operation (starting/ending element blocks or writes). -A new method xf.flush() can alternatively be used to explicitly flush -the output.
  • -
  • lxml.html.document_fromstring has a new option ensure_head_body=True -which will add an empty head and/or body element to the result document if -missing.
  • -
  • lxml.html.iterlinks now returns links inside meta refresh tags.
  • -
  • New XMLParser option collect_ids=False to disable ID hash table -creation. This can substantially speed up parsing of documents with many -different IDs that are not used.
  • -
  • The parser uses per-document hash tables for XML IDs. This reduces the -load of the global parser dict and speeds up parsing for documents with -many different IDs.
  • -
  • ElementTree.getelementpath(element) returns a structural ElementPath -expression for the given element, which can be used for lookups later.
  • -
  • xmlfile() accepts a new argument close=True to close file(-like) -objects after writing to them. Before, xmlfile() only closed the file -if it had opened it internally.
  • -
  • Allow "bytearray" type for ASCII text input.
  • -
-
-
-

Bugs fixed

-
-
-

Other changes

-
    -
  • LP#400588: decoding errors have become hard errors even in recovery mode. -Previously, they could lead to an internal tree representation in a mixed -encoding state, which lead to very late errors or even silently incorrect -behaviour during tree traversal or serialisation.
  • -
  • Requires Python 2.6, 2.7, 3.2 or later. No longer supports -Python 2.4, 2.5 and 3.1, use lxml 3.3.x for those.
  • -
  • Requires libxml2 2.7.0 or later and libxslt 1.1.23 or later, -use lxml 3.3.x with older versions.
  • -
-
-
-
-

3.3.6 (2014-08-28)

-
-

Bugs fixed

-
    -
  • Prevent tree cycle creation when adding Elements as siblings.
  • -
  • LP#1361948: crash when deallocating Element siblings without parent.
  • -
  • LP#1354652: crash when traversing internally loaded documents in XSLT -extension functions.
  • -
-
-
-
-

3.3.5 (2014-04-18)

-
-

Bugs fixed

-
    -
  • HTML cleaning could fail to strip javascript links that mix control -characters into the link scheme.
  • -
-
-
-
-

3.3.4 (2014-04-03)

-
-

Features added

-
    -
  • Source line numbers above 65535 are available on Elements when -using libxml2 2.9 or later.
  • -
-
-
-

Bugs fixed

-
    -
  • lxml.html.fragment_fromstring() failed for bytes input in Py3.
  • -
-
-
-

Other changes

-
-
-
-

3.3.3 (2014-03-04)

-
-

Bugs fixed

-
    -
  • LP#1287118: Crash when using Element subtypes with __slots__.
  • -
-
-
-

Other changes

-
    -
  • The internal classes _LogEntry and _Attrib can no longer be -subclassed from Python code.
  • -
-
-
-
-

3.3.2 (2014-02-26)

-
-

Bugs fixed

-
    -
  • The properties resolvers and version, as well as the methods -set_element_class_lookup() and makeelement(), were lost from -iterparse objects in 3.3.0.
  • -
  • LP#1222132: instances of XMLSchema, Schematron and RelaxNG -did not clear their local error_log before running a validation.
  • -
  • LP#1238500: lxml.doctestcompare mixed up "expected" and "actual" in -attribute values.
  • -
  • Some file I/O tests were failing in MS-Windows due to non-portable temp -file usage. Initial patch by Gabi Davar.
  • -
  • LP#910014: duplicate IDs in a document were not reported by DTD validation.
  • -
  • LP#1185332: tostring(method="html") did not use HTML serialisation -semantics for trailing tail text. Initial patch by Sylvain Viollon.
  • -
  • LP#1281139: .attrib value of Comments lost its mutation methods -in 3.3.0. Even though it is empty and immutable, it should still -provide the same interface as that returned for Elements.
  • -
-
-
-
-

3.3.1 (2014-02-12)

-
-

Features added

-
-
-

Bugs fixed

-
    -
  • LP#1014290: HTML documents parsed with parser.feed() failed to find -elements during tag iteration.
  • -
  • LP#1273709: Building in PyPy failed due to missing support for -PyUnicode_Compare() and PyByteArray_*() in PyPy's C-API.
  • -
  • LP#1274413: Compilation in MSVC failed due to missing "stdint.h" standard -header file.
  • -
  • LP#1274118: iterparse() failed to parse BOM prefixed files.
  • -
-
-
-

Other changes

-
-
-
-

3.3.0 (2014-01-26)

-
-

Features added

-
-
-

Bugs fixed

-
    -
  • The heuristic that distinguishes file paths from URLs was tightened -to produce less false negatives.
  • -
-
-
-

Other changes

-
-
-
-

3.3.0beta5 (2014-01-18)

-
-

Features added

-
    -
  • The PEP 393 unicode parsing support gained a fallback for wchar strings -which might still be somewhat common on Windows systems.
  • -
-
-
-

Bugs fixed

-
    -
  • Several error handling problems were fixed throughout the code base that -could previously lead to exceptions being silently swallowed or not -properly reported.
  • -
  • The C-API function appendChild() is now deprecated as it does not -propagate exceptions (its return type is void). The new function -appendChildToElement() was added as a safe replacement.
  • -
  • Passing a string into fromstringlist() raises an exception instead of -parsing the string character by character.
  • -
-
-
-

Other changes

-
    -
  • Document cleanup code was simplified using the new GC features in -Cython 0.20.
  • -
-
-
-
-

3.3.0beta4 (2014-01-12)

-
-

Features added

-
-
-

Bugs fixed

-
    -
  • The (empty) value returned by the attrib property of Entity and Comment -objects was mutable.
  • -
  • Element class lookup wasn't available for the new pull parsers or when using -a custom parser target.
  • -
  • Setting Element attributes on instantiation with both the attrib argument -and keyword arguments could modify the mapping passed as attrib.
  • -
  • LP#1266171: DTDs instantiated from internal/external subsets (i.e. through -the docinfo property) lost their attribute declarations.
  • -
-
-
-

Other changes

-
    -
  • Built with Cython 0.20pre (gitrev 012ae82eb) to prepare support for -Python 3.4.
  • -
-
-
-
-

3.3.0beta3 (2014-01-02)

-
-

Features added

-
    -
  • Unicode string parsing was optimised for Python 3.3 (PEP 393).
  • -
-
-
-

Bugs fixed

-
    -
  • HTML parsing of Unicode strings could misdecode the input on some platforms.
  • -
  • Crash in xmlfile() when closing open elements out of order in an error case.
  • -
-
-
-

Other changes

-
-
-
-

3.3.0beta2 (2013-12-20)

-
-

Features added

-
    -
  • iterparse() supports the recover option.
  • -
-
-
-

Bugs fixed

-
    -
  • Crash in iterparse() for HTML parsing.
  • -
  • Crash in target parsing with attributes.
  • -
-
-
-

Other changes

-
    -
  • The safety check in the read-only tree implementation (e.g. used by -PythonElementClassLookup) raises a more appropriate ReferenceError -for illegal access after tree disposal instead of an AssertionError. -This should only impact test code that specifically checks the original -behaviour.
  • -
-
-
-
-

3.3.0beta1 (2013-12-12)

-
-

Features added

-
    -
  • New option handle_failures in make_links_absolute() and -resolve_base_href() (lxml.html) that enables ignoring or -discarding links that fail to parse as URLs.
  • -
  • New parser classes XMLPullParser and HTMLPullParser for -incremental parsing, as implemented for ElementTree in Python 3.4.
  • -
  • iterparse() enables recovery mode by default for HTML parsing -(html=True).
  • -
-
-
-

Bugs fixed

-
    -
  • LP#1255132: crash when trying to run validation over non-Element (e.g. -comment or PI).
  • -
  • Error messages in the log and in exception messages that originated -from libxml2 could accidentally be picked up from preceding warnings -instead of the actual error.
  • -
  • The ElementMaker in lxml.objectify did not accept a dict as -argument for adding attributes to the element it's building. This -works as in lxml.builder now.
  • -
  • LP#1228881: repr(XSLTAccessControl) failed in Python 3.
  • -
  • Raise ValueError when trying to append an Element to itself or -to one of its own descendants, instead of running into an infinite -loop.
  • -
  • LP#1206077: htmldiff discarded whitespace from the output.
  • -
  • Compressed plain-text serialisation to file-like objects was broken.
  • -
  • lxml.html.formfill: Fix textarea form filling. -The textarea used to be cleared before the new content was set, -which removed the name attribute.
  • -
-
-
-

Other changes

-
    -
  • Some basic API classes use freelists internally for faster -instantiation. This can speed up some iterparse() scenarios, -for example.
  • -
  • iterparse() was rewritten to use the new *PullParser -classes internally instead of being a parser itself.
  • -
-
-
-
-

3.2.5 (2014-01-02)

-
-

Features added

-
-
-

Bugs fixed

-
    -
  • Crash in xmlfile() when closing open elements out of order in an error case.
  • -
  • Crash in target parsing with attributes.
  • -
  • LP#1255132: crash when trying to run validation over non-Element (e.g. -comment or PI).
  • -
-
-
-

Other changes

-
-
-
-

3.2.4 (2013-11-07)

-
-

Features added

-
-
-

Bugs fixed

-
    -
  • Memory leak when creating an XPath evaluator in a thread.
  • -
  • LP#1228881: repr(XSLTAccessControl) failed in Python 3.
  • -
  • Raise ValueError when trying to append an Element to itself or -to one of its own descendants.
  • -
  • LP#1206077: htmldiff discarded whitespace from the output.
  • -
  • Compressed plain-text serialisation to file-like objects was broken.
  • -
-
-
-

Other changes

-
-
-
-

3.2.3 (2013-07-28)

-
-

Bugs fixed

-
    -
  • Fix support for Python 2.4 which was lost in 3.2.2.
  • -
-
-
-
-

3.2.2 (2013-07-28)

-
-

Features added

-
-
-

Bugs fixed

-
    -
  • LP#1185701: spurious XMLSyntaxError after finishing iterparse().
  • -
  • Crash in lxml.objectify during xsi annotation.
  • -
-
-
-

Other changes

-
    -
  • Return values of user provided element class lookup methods are now -validated against the type of the XML node they represent to prevent -API class mismatches.
  • -
-
-
-
-

3.2.1 (2013-05-11)

-
-

Features added

-
    -
  • The methods apply_templates() and process_children() of XSLT -extension elements have gained two new boolean options elements_only -and remove_blank_text that discard either all strings or whitespace-only -strings from the result list.
  • -
-
-
-

Bugs fixed

-
    -
  • When moving Elements to another tree, the namespace cleanup mechanism -no longer drops namespace prefixes from attributes for which it finds -a default namespace declaration, to prevent them from appearing as -unnamespaced attributes after serialisation.
  • -
  • Returning non-type objects from a custom class lookup method could lead -to a crash.
  • -
  • Instantiating and using subtypes of Comments and ProcessingInstructions -crashed.
  • -
-
-
-

Other changes

-
-
-
-

3.2.0 (2013-04-28)

-
-

Features added

-
-
-

Bugs fixed

-
    -
  • LP#690319: Leading whitespace could change the behaviour of the string -parsing functions in lxml.html.
  • -
  • LP#599318: The string parsing functions in lxml.html are more robust -in the face of uncommon HTML content like framesets or missing body tags. -Patch by Stefan Seelmann.
  • -
  • LP#712941: I/O errors while trying to access files with paths that contain -non-ASCII characters could raise UnicodeDecodeError instead of properly -reporting the IOError.
  • -
  • LP#673205: Parsing from in-memory strings disabled network access in the -default parser and made subsequent attempts to parse from a URL fail.
  • -
  • LP#971754: lxml.html.clean appends 'nofollow' to 'rel' attributes instead -of overwriting the current value.
  • -
  • LP#715687: lxml.html.clean no longer discards scripts that are explicitly -allowed by the user provided whitelist. Patch by Christine Koppelt.
  • -
-
-
-

Other changes

-
-
-
-

3.1.2 (2013-04-12)

-
-

Features added

-
-
-

Bugs fixed

-
    -
  • LP#1136509: Passing attributes through the namespace-unaware API of -the sax bridge (i.e. the handler.startElement() method) failed -with a TypeError. Patch by Mike Bayer.
  • -
  • LP#1123074: Fix serialisation error in XSLT output when converting -the result tree to a Unicode string.
  • -
  • GH#105: Replace illegal usage of xmlBufLength() in libxml2 2.9.0 -by properly exported API function xmlBufUse().
  • -
-
-
-

Other changes

-
-
-
-

3.1.1 (2013-03-29)

-
-

Features added

-
-
-

Bugs fixed

-
    -
  • LP#1160386: Write access to lxml.html.FormElement.fields raised -an AttributeError in Py3.
  • -
  • Illegal memory access during cleanup in incremental xmlfile writer.
  • -
-
-
-

Other changes

-
    -
  • The externally useless class lxml.etree._BaseParser was removed -from the module dict.
  • -
-
-
-
-

3.1.0 (2013-02-10)

-
-

Features added

-
    -
  • GH#89: lxml.html.clean allows overriding the set of attributes that it -considers 'safe'. Patch by Francis Devereux.
  • -
-
-
-

Bugs fixed

-
    -
  • LP#1104370: copy.copy(el.attrib) raised an exception. It now returns -a copy of the attributes as a plain Python dict.
  • -
  • GH#95: When used with namespace prefixes, the el.find*() methods -always used the first namespace mapping that was provided for each -path expression instead of using the one that was actually passed -in for the current run.
  • -
  • LP#1092521, GH#91: Fix undefined C symbol in Python runtimes compiled -without threading support. Patch by Ulrich Seidl.
  • -
-
-
-

Other changes

-
-
-
-

3.1beta1 (2012-12-21)

-
-

Features added

-
    -
  • New build-time option --with-unicode-strings for Python 2 that -makes the API always return Unicode strings for names and text -instead of byte strings for plain ASCII content.
  • -
  • New incremental XML file writing API etree.xmlfile().
  • -
  • E factory in lxml.objectify is callable to simplify the creation of -tags with non-identifier names without having to resort to getattr().
  • -
-
-
-

Bugs fixed

-
    -
  • When starting from a non-namespaced element in lxml.objectify, searching -for a child without explicitly specifying a namespace incorrectly found -namespaced elements with the requested local name, instead of restricting -the search to non-namespaced children.
  • -
  • GH#85: Deprecation warnings were fixed for Python 3.x.
  • -
  • GH#33: lxml.html.fromstring() failed to accept bytes input in Py3.
  • -
  • LP#1080792: Static build of libxml2 2.9.0 failed due to missing file.
  • -
-
-
-

Other changes

-
    -
  • The externally useless class _ObjectifyElementMakerCaller was -removed from the module API of lxml.objectify.
  • -
  • LP#1075622: lxml.builder is faster for adding text to elements with -many children. Patch by Anders Hammarquist.
  • -
-
-
-
-

3.0.2 (2012-12-14)

-
-

Features added

-
-
-

Bugs fixed

-
    -
  • Fix crash during interpreter shutdown by switching to Cython 0.17.3 for building.
  • -
-
-
-

Other changes

-
-
-
-

3.0.1 (2012-10-14)

-
-

Features added

-
-
-

Bugs fixed

-
    -
  • LP#1065924: Element proxies could disappear during garbage collection -in PyPy without proper cleanup.
  • -
  • GH#71: Failure to work with libxml2 2.6.x.
  • -
  • LP#1065139: static MacOS-X build failed in Py3.
  • -
-
-
-

Other changes

-
-
-
-

3.0 (2012-10-08)

-
-

Features added

-
-
-

Bugs fixed

-
    -
  • End-of-file handling was incorrect in iterparse() when reading from -a low-level C file stream and failed in libxml2 2.9.0 due to its -improved consistency checks.
  • -
-
-
-

Other changes

-
    -
  • The build no longer uses Cython by default unless the generated C files -are missing. To use Cython, pass the option "--with-cython". To ignore -the fatal build error when Cython is required but not available (e.g. to -run special setup.py commands that do not actually run a build), pass -"--without-cython".
  • -
-
-
-
-

3.0beta1 (2012-09-26)

-
-

Features added

-
    -
  • Python level access to (optional) libxml2 memory debugging features -to simplify debugging of memory leaks etc.
  • -
-
-
-

Bugs fixed

-
    -
  • Fix a memory leak in XPath by switching to Cython 0.17.1.
  • -
  • Some tests were adapted to work with PyPy.
  • -
-
-
-

Other changes

-
    -
  • The code was adapted to work with the upcoming libxml2 2.9.0 release.
  • -
-
-
-
-

3.0alpha2 (2012-08-23)

-
-

Features added

-
    -
  • The .iter() method of elements now accepts tag arguments like -"{*}name" to search for elements with a given local name in any -namespace. With this addition, all combinations of wildcards now work -as expected: -"{ns}name", "{}name", "{*}name", "{ns}*", "{}*" -and "{*}*". Note that "name" is equivalent to "{}name", -but "*" is "{*}*". -The same change applies to the .getiterator(), .itersiblings(), -.iterancestors(), .iterdescendants(), .iterchildren() -and .itertext() methods;the strip_attributes(), -strip_elements() and strip_tags() functions as well as the -iterparse() class. Patch by Simon Sapin.
  • -
  • C14N allows specifying the inclusive prefixes to be promoted -to top-level during exclusive serialisation.
  • -
-
-
-

Bugs fixed

-
    -
  • Passing long Unicode strings into the feed() parser interface -failed to read the entire string.
  • -
-
-
-

Other changes

-
-
-
-

3.0alpha1 (2012-07-31)

-
-

Features added

-
    -
  • Initial support for building in PyPy (through cpyext).
  • -
  • DTD objects gained an API that allows read access to their -declarations.
  • -
  • xpathgrep.py gained support for parsing line-by-line (e.g. -from grep output) and for surrounding the output with a new root -tag.
  • -
  • E-factory in lxml.builder accepts subtypes of known data -types (such as string subtypes) when building elements around them.
  • -
  • Tree iteration and iterparse() with a selective tag -argument supports passing a set of tags. Tree nodes will be -returned by the iterators if they match any of the tags.
  • -
-
-
-

Bugs fixed

-
    -
  • The .find*() methods in lxml.objectify no longer use XPath -internally, which makes them faster in many cases (especially when -short circuiting after a single or couple of elements) and fixes -some behavioural differences compared to lxml.etree. Note that -this means that they no longer support arbitrary XPath expressions -but only the subset that the ElementPath language supports. -The previous implementation was also redundant with the normal -XPath support, which can be used as a replacement.
  • -
  • el.find('*') could accidentally return a comment or processing -instruction that happened to be in the wrong spot. (Same for the -other .find*() methods.)
  • -
  • The error logging is less intrusive and avoids a global setup where -possible.
  • -
  • Fixed undefined names in html5lib parser.
  • -
  • xpathgrep.py did not work in Python 3.
  • -
  • Element.attrib.update() did not accept an attrib of -another Element as parameter.
  • -
  • For subtypes of ElementBase that make the .text or .tail -properties immutable (as in objectify, for example), inserting text -when creating Elements through the E-Factory feature of the class -constructor would fail with an exception, stating that the text -cannot be modified.
  • -
-
-
-

Other changes

-
    -
  • The code base was overhauled to properly use 'const' where the API -of libxml2 and libxslt requests it. This also has an impact on the -public C-API of lxml itself, as defined in etreepublic.pxd, as -well as the provided declarations in the lxml/includes/ directory. -Code that uses these declarations may have to be adapted. On the -plus side, this fixes several C compiler warnings, also for user -code, thus making it easier to spot real problems again.
  • -
  • The functionality of "lxml.cssselect" was moved into a separate PyPI -package called "cssselect". To continue using it, you must install -that package separately. The "lxml.cssselect" module is still -available and provides the same interface, provided the "cssselect" -package can be imported at runtime.
  • -
  • Element attributes passed in as an attrib dict or as keyword -arguments are now sorted by (namespaced) name before being created -to make their order predictable for serialisation and iteration. -Note that adding or deleting attributes afterwards does not take -that order into account, i.e. setting a new attribute appends it -after the existing ones.
  • -
  • Several classes that are for internal use only were removed -from the lxml.etree module dict: -_InputDocument, _ResolverRegistry, _ResolverContext, _BaseContext, -_ExsltRegExp, _IterparseContext, _TempStore, _ExceptionContext, -__ContentOnlyElement, _AttribIterator, _NamespaceRegistry, -_ClassNamespaceRegistry, _FunctionNamespaceRegistry, -_XPathFunctionNamespaceRegistry, _ParserDictionaryContext, -_FileReaderContext, _ParserContext, _PythonSaxParserTarget, -_TargetParserContext, _ReadOnlyProxy, _ReadOnlyPIProxy, -_ReadOnlyEntityProxy, _ReadOnlyElementProxy, _OpaqueNodeWrapper, -_OpaqueDocumentWrapper, _ModifyContentOnlyProxy, -_ModifyContentOnlyPIProxy, _ModifyContentOnlyEntityProxy, -_AppendOnlyElementProxy, _SaxParserContext, _FilelikeWriter, -_ParserSchemaValidationContext, _XPathContext, -_XSLTResolverContext, _XSLTContext, _XSLTQuotedStringParam
  • -
  • Several internal classes can no longer be inherited from: -_InputDocument, _ResolverRegistry, _ExsltRegExp, _ElementUnicodeResult, -_IterparseContext, _TempStore, _AttribIterator, _ClassNamespaceRegistry, -_XPathFunctionNamespaceRegistry, _ParserDictionaryContext, -_FileReaderContext, _PythonSaxParserTarget, _TargetParserContext, -_ReadOnlyPIProxy, _ReadOnlyEntityProxy, _OpaqueDocumentWrapper, -_ModifyContentOnlyPIProxy, _ModifyContentOnlyEntityProxy, -_AppendOnlyElementProxy, _FilelikeWriter, _ParserSchemaValidationContext, -_XPathContext, _XSLTResolverContext, _XSLTContext, _XSLTQuotedStringParam, -_XSLTResultTree, _XSLTProcessingInstruction
  • -
-
-
-
-

2.3.6 (2012-09-28)

-
-

Features added

-
-
-

Bugs fixed

-
    -
  • Passing long Unicode strings into the feed() parser interface -failed to read the entire string.
  • -
-
-
-

Other changes

-
-
-
-

2.3.5 (2012-07-31)

-
-

Features added

-
-
-

Bugs fixed

-
    -
  • Crash when merging text nodes in element.remove().
  • -
  • Crash in sax/target parser when reporting empty doctype.
  • -
-
-
-

Other changes

-
-
-
-

2.3.4 (2012-03-26)

-
-

Features added

-
-
-

Bugs fixed

-
    -
  • Crash when building an nsmap (Element property) with empty -namespace URIs.
  • -
  • Crash due to race condition when errors (or user messages) occur -during threaded XSLT processing.
  • -
  • XSLT stylesheet compilation could ignore compilation errors.
  • -
-
-
-

Other changes

-
-
-
-

2.3.3 (2012-01-04)

-
-

Features added

-
    -
  • lxml.html.tostring() gained new serialisation options -with_tail and doctype.
  • -
-
-
-

Bugs fixed

-
    -
  • Fixed a crash when using iterparse() for HTML parsing and -requesting start events.
  • -
  • Fixed parsing of more selectors in cssselect. Whitespace before -pseudo-elements and pseudo-classes is significant as it is a -descendant combinator. -"E :pseudo" should parse the same as "E *:pseudo", not "E:pseudo". -Patch by Simon Sapin.
  • -
  • lxml.html.diff no longer raises an exception when hitting -'img' tags without 'src' attribute.
  • -
-
-
-

Other changes

-
-
-
-

2.3.2 (2011-11-11)

-
-

Features added

-
    -
  • lxml.objectify.deannotate() has a new boolean option -cleanup_namespaces to remove the objectify namespace -declarations (and generally clean up the namespace declarations) -after removing the type annotations.
  • -
  • lxml.objectify gained its own SubElement() function as a -copy of etree.SubElement to avoid an otherwise redundant import -of lxml.etree on the user side.
  • -
-
-
-

Bugs fixed

-
    -
  • Fixed the "descendant" bug in cssselect a second time (after a first -fix in lxml 2.3.1). The previous change resulted in a serious -performance regression for the XPath based evaluation of the -translated expression. Note that this breaks the usage of some of -the generated XPath expressions as XSLT location paths that -previously worked in 2.3.1.
  • -
  • Fixed parsing of some selectors in cssselect. Whitespace after combinators -">", "+" and "~" is now correctly ignored. Previously it was parsed as -a descendant combinator. For example, "div> .foo" was parsed the same as -"div>* .foo" instead of "div>.foo". Patch by Simon Sapin.
  • -
-
-
-

Other changes

-
-
-
-

2.3.1 (2011-09-25)

-
-

Features added

-
    -
  • New option kill_tags in lxml.html.clean to remove specific -tags and their content (i.e. their whole subtree).
  • -
  • pi.get() and pi.attrib on processing instructions to parse -pseudo-attributes from the text content of processing instructions.
  • -
  • lxml.get_include() returns a list of include paths that can be -used to compile external C code against lxml.etree. This is -specifically required for statically linked lxml builds when code -needs to compile against the exact same header file versions as lxml -itself.
  • -
  • Resolver.resolve_file() takes an additional option -close_file that configures if the file(-like) object will be -closed after reading or not. By default, the file will be closed, -as the user is not expected to keep a reference to it.
  • -
-
-
-

Bugs fixed

-
    -
  • HTML cleaning didn't remove 'data:' links.
  • -
  • The html5lib parser integration now uses the 'official' -implementation in html5lib itself, which makes it work with newer -releases of the library.
  • -
  • In lxml.sax, endElementNS() could incorrectly reject a plain -tag name when the corresponding start event inferred the same plain -tag name to be in the default namespace.
  • -
  • When an open file-like object is passed into parse() or -iterparse(), the parser will no longer close it after use. This -reverts a change in lxml 2.3 where all files would be closed. It is -the users responsibility to properly close the file(-like) object, -also in error cases.
  • -
  • Assertion error in lxml.html.cleaner when discarding top-level elements.
  • -
  • In lxml.cssselect, use the xpath 'A//B' (short for -'A/descendant-or-self::node()/B') instead of 'A/descendant::B' for -the css descendant selector ('A B'). This makes a few edge cases -like "div *:last-child" consistent with the selector behavior in -WebKit and Firefox, and makes more css expressions valid location -paths (for use in xsl:template match).
  • -
  • In lxml.html, non-selected <option> tags no longer show up in the -collected form values.
  • -
  • Adding/removing <option> values to/from a multiple select form -field properly selects them and unselects them.
  • -
-
-
-

Other changes

-
    -
  • Static builds can specify the download directory with the ---download-dir option.
  • -
-
-
-
-

2.3 (2011-02-06)

-
-

Features added

-
    -
  • When looking for children, lxml.objectify takes '{}tag' as -meaning an empty namespace, as opposed to the parent namespace.
  • -
-
-
-

Bugs fixed

-
    -
  • When finished reading from a file-like object, the parser -immediately calls its .close() method.
  • -
  • When finished parsing, iterparse() immediately closes the input -file.
  • -
  • Work-around for libxml2 bug that can leave the HTML parser in a -non-functional state after parsing a severely broken document (fixed -in libxml2 2.7.8).
  • -
  • marque tag in HTML cleanup code is correctly named marquee.
  • -
-
-
-

Other changes

-
    -
  • Some public functions in the Cython-level C-API have more explicit -return types.
  • -
-
-
-
-

2.3beta1 (2010-09-06)

-
-

Features added

-
-
-

Bugs fixed

-
    -
  • Crash in newer libxml2 versions when moving elements between -documents that had attributes on replaced XInclude nodes.
  • -
  • XMLID() function was missing the optional parser and -base_url parameters.
  • -
  • Searching for wildcard tags in iterparse() was broken in Py3.
  • -
  • lxml.html.open_in_browser() didn't work in Python 3 due to the -use of os.tempnam. It now takes an optional 'encoding' parameter.
  • -
-
-
-

Other changes

-
-
-
-

2.3alpha2 (2010-07-24)

-
-

Features added

-
-
-

Bugs fixed

-
    -
  • Crash in XSLT when generating text-only result documents with a -stylesheet created in a different thread.
  • -
-
-
-

Other changes

-
    -
  • repr() of Element objects shows the hex ID with leading 0x -(following ElementTree 1.3).
  • -
-
-
-
-

2.3alpha1 (2010-06-19)

-
-

Features added

-
    -
  • Keyword argument namespaces in lxml.cssselect.CSSSelector() -to pass a prefix-to-namespace mapping for the selector.
  • -
  • New function lxml.etree.register_namespace(prefix, uri) that -globally registers a namespace prefix for a namespace that newly -created Elements in that namespace will use automatically. Follows -ElementTree 1.3.
  • -
  • Support 'unicode' string name as encoding parameter in -tostring(), following ElementTree 1.3.
  • -
  • Support 'c14n' serialisation method in ElementTree.write() and -tostring(), following ElementTree 1.3.
  • -
  • The ElementPath expression syntax (el.find*()) was extended to -match the upcoming ElementTree 1.3 that will ship in the standard -library of Python 3.2/2.7. This includes extended support for -predicates as well as namespace prefixes (as known from XPath).
  • -
  • During regular XPath evaluation, various ESXLT functions are -available within their namespace when using libxslt 1.1.26 or later.
  • -
  • Support passing a readily configured logger instance into -PyErrorLog, instead of a logger name.
  • -
  • On serialisation, the new doctype parameter can be used to -override the DOCTYPE (internal subset) of the document.
  • -
  • New parameter output_parent to XSLTExtension.apply_templates() -to append the resulting content directly to an output element.
  • -
  • XSLTExtension.process_children() to process the content of the -XSLT extension element itself.
  • -
  • ISO-Schematron support based on the de-facto Schematron reference -'skeleton implementation'.
  • -
  • XSLT objects now take XPath object as __call__ stylesheet -parameters.
  • -
  • Enable path caching in ElementPath (el.find*()) to avoid parsing -overhead.
  • -
  • Setting the value of a namespaced attribute always uses a prefixed -namespace instead of the default namespace even if both declare the -same namespace URI. This avoids serialisation problems when an -attribute from a default namespace is set on an element from a -different namespace.
  • -
  • XSLT extension elements: support for XSLT context nodes other than -elements: document root, comments, processing instructions.
  • -
  • Support for strings (in addition to Elements) in node-sets returned -by extension functions.
  • -
  • Forms that lack an action attribute default to the base URL of -the document on submit.
  • -
  • XPath attribute result strings have an attrname property.
  • -
  • Namespace URIs get validated against RFC 3986 at the API level -(required by the XML namespace specification).
  • -
  • Target parsers show their target object in the .target property -(compatible with ElementTree).
  • -
-
-
-

Bugs fixed

-
    -
  • API is hardened against invalid proxy instances to prevent crashes -due to incorrectly instantiated Element instances.
  • -
  • Prevent crash when instantiating CommentBase and friends.
  • -
  • Export ElementTree compatible XML parser class as -XMLTreeBuilder, as it is called in ET 1.2.
  • -
  • ObjectifiedDataElements in lxml.objectify were not hashable. They -now use the hash value of the underlying Python value (string, -number, etc.) to which they compare equal.
  • -
  • Parsing broken fragments in lxml.html could fail if the fragment -contained an orphaned closing '</div>' tag.
  • -
  • Using XSLT extension elements around the root of the output document -crashed.
  • -
  • lxml.cssselect did not distinguish between x[attr="val"] and -x [attr="val"] (with a space). The latter now matches the -attribute independent of the element.
  • -
  • Rewriting multiple links inside of HTML text content could end up -replacing unrelated content as replacements could impact the -reported position of subsequent matches. Modifications are now -simplified by letting the iterlinks() generator in lxml.html -return links in reversed order if they appear inside the same text -node. Thus, replacements and link-internal modifications no longer -change the position of links reported afterwards.
  • -
  • The .value attribute of textarea elements in lxml.html did -not represent the complete raw value (including child tags etc.). It -now serialises the complete content on read and replaces the -complete content by a string on write.
  • -
  • Target parser didn't call .close() on the target object if -parsing failed. Now it is guaranteed that .close() will be -called after parsing, regardless of the outcome.
  • -
-
-
-

Other changes

-
    -
  • Official support for Python 3.1.2 and later.
  • -
  • Static MS Windows builds can now download their dependencies -themselves.
  • -
  • Element.attrib no longer uses a cyclic reference back to its -Element object. It therefore no longer requires the garbage -collector to clean up.
  • -
  • Static builds include libiconv, in addition to libxml2 and libxslt.
  • -
-
-
-
-

2.2.8 (2010-09-02)

-
-

Bugs fixed

-
    -
  • Crash in newer libxml2 versions when moving elements between -documents that had attributes on replaced XInclude nodes.
  • -
  • Import fix for urljoin in Python 3.1+.
  • -
-
-
-
-

2.2.7 (2010-07-24)

-
-

Bugs fixed

-
    -
  • Crash in XSLT when generating text-only result documents with a -stylesheet created in a different thread.
  • -
-
-
-
-

2.2.6 (2010-03-02)

-
-

Bugs fixed

-
    -
  • Fixed several Python 3 regressions by building with Cython 0.11.3.
  • -
-
-
-
-

2.2.5 (2010-02-28)

-
-

Features added

-
    -
  • Support for running XSLT extension elements on the input root node -(e.g. in a template matching on "/").
  • -
-
-
-

Bugs fixed

-
    -
  • Crash in XPath evaluation when reading smart strings from a document -other than the original context document.
  • -
  • Support recent versions of html5lib by not requiring its -XHTMLParser in htmlparser.py anymore.
  • -
  • Manually instantiating the custom element classes in -lxml.objectify could crash.
  • -
  • Invalid XML text characters were not rejected by the API when they -appeared in unicode strings directly after non-ASCII characters.
  • -
  • lxml.html.open_http_urllib() did not work in Python 3.
  • -
  • The functions strip_tags() and strip_elements() in -lxml.etree did not remove all occurrences of a tag in all cases.
  • -
  • Crash in XSLT extension elements when the XSLT context node is not -an element.
  • -
-
-
-
-

2.2.4 (2009-11-11)

-
-

Bugs fixed

-
    -
  • Static build of libxml2/libxslt was broken.
  • -
-
-
-
-

2.2.3 (2009-10-30)

-
-

Features added

-
-
-

Bugs fixed

-
    -
  • The resolve_entities option did not work in the incremental feed -parser.
  • -
  • Looking up and deleting attributes without a namespace could hit a -namespaced attribute of the same name instead.
  • -
  • Late errors during calls to SubElement() (e.g. attribute related -ones) could leave a partially initialised element in the tree.
  • -
  • Modifying trees that contain parsed entity references could result -in an infinite loop.
  • -
  • ObjectifiedElement.__setattr__ created an empty-string child element when the -attribute value was rejected as a non-unicode/non-ascii string
  • -
  • Syntax errors in lxml.cssselect could result in misleading error -messages.
  • -
  • Invalid syntax in CSS expressions could lead to an infinite loop in -the parser of lxml.cssselect.
  • -
  • CSS special character escapes were not properly handled in -lxml.cssselect.
  • -
  • CSS Unicode escapes were not properly decoded in lxml.cssselect.
  • -
  • Select options in HTML forms that had no explicit value -attribute were not handled correctly. The HTML standard dictates -that their value is defined by their text content. This is now -supported by lxml.html.
  • -
  • XPath raised a TypeError when finding CDATA sections. This is now -fully supported.
  • -
  • Calling help(lxml.objectify) didn't work at the prompt.
  • -
  • The ElementMaker in lxml.objectify no longer defines the default -namespaces when annotation is disabled.
  • -
  • Feed parser failed to honour the 'recover' option on parse errors.
  • -
  • Diverting the error logging to Python's logging system was broken.
  • -
-
-
-

Other changes

-
-
-
-

2.2.2 (2009-06-21)

-
-

Features added

-
    -
  • New helper functions strip_attributes(), strip_elements(), -strip_tags() in lxml.etree to remove attributes/subtrees/tags -from a subtree.
  • -
-
-
-

Bugs fixed

-
    -
  • Namespace cleanup on subtree insertions could result in missing -namespace declarations (and potentially crashes) if the element -defining a namespace was deleted and the namespace was not used by -the top element of the inserted subtree but only in deeper subtrees.
  • -
  • Raising an exception from a parser target callback didn't always -terminate the parser.
  • -
  • Only {true, false, 1, 0} are accepted as the lexical representation for -BoolElement ({True, False, T, F, t, f} not any more), restoring lxml <= 2.0 -behaviour.
  • -
-
-
-

Other changes

-
-
-
-

2.2.1 (2009-06-02)

-
-

Features added

-
    -
  • Injecting default attributes into a document during XML Schema -validation (also at parse time).
  • -
  • Pass huge_tree parser option to disable parser security -restrictions imposed by libxml2 2.7.
  • -
-
-
-

Bugs fixed

-
    -
  • The script for statically building libxml2 and libxslt didn't work -in Py3.
  • -
  • XMLSchema() also passes invalid schema documents on to libxml2 -for parsing (which could lead to a crash before release 2.6.24).
  • -
-
-
-

Other changes

-
-
-
-

2.2 (2009-03-21)

-
-

Features added

-
    -
  • Support for standalone flag in XML declaration through -tree.docinfo.standalone and by passing standalone=True/False -on serialisation.
  • -
-
-
-

Bugs fixed

-
    -
  • Crash when parsing an XML Schema with external imports from a -filename.
  • -
-
-
-
-

2.2beta4 (2009-02-27)

-
-

Features added

-
    -
  • Support strings and instantiable Element classes as child arguments -to the constructor of custom Element classes.
  • -
  • GZip compression support for serialisation to files and file-like -objects.
  • -
-
-
-

Bugs fixed

-
    -
  • Deep-copying an ElementTree copied neither its sibling PIs and -comments nor its internal/external DTD subsets.
  • -
  • Soupparser failed on broken attributes without values.
  • -
  • Crash in XSLT when overwriting an already defined attribute using -xsl:attribute.
  • -
  • Crash bug in exception handling code under Python 3. This was due -to a problem in Cython, not lxml itself.
  • -
  • lxml.html.FormElement._name() failed for non top-level forms.
  • -
  • TAG special attribute in constructor of custom Element classes -was evaluated incorrectly.
  • -
-
-
-

Other changes

-
    -
  • Official support for Python 3.0.1.
  • -
  • Element.findtext() now returns an empty string instead of None -for Elements without text content.
  • -
-
-
-
-

2.2beta3 (2009-02-17)

-
-

Features added

-
    -
  • XSLT.strparam() class method to wrap quoted string parameters -that require escaping.
  • -
-
-
-

Bugs fixed

-
    -
  • Memory leak in XPath evaluators.
  • -
  • Crash when parsing indented XML in one thread and merging it with -other documents parsed in another thread.
  • -
  • Setting the base attribute in lxml.objectify from a unicode -string failed.
  • -
  • Fixes following changes in Python 3.0.1.
  • -
  • Minor fixes for Python 3.
  • -
-
-
-

Other changes

-
    -
  • The global error log (which is copied into the exception log) is now -local to a thread, which fixes some race conditions.
  • -
  • More robust error handling on serialisation.
  • -
-
-
-
-

2.2beta2 (2009-01-25)

-
-

Bugs fixed

-
    -
  • Potential memory leak on exception handling. This was due to a -problem in Cython, not lxml itself.
  • -
  • iter_links (and related link-rewriting functions) in -lxml.html would interpret CSS like url("link") incorrectly -(treating the quotation marks as part of the link).
  • -
  • Failing import on systems that have an io module.
  • -
-
-
-
-

2.1.5 (2009-01-06)

-
-

Bugs fixed

-
    -
  • Potential memory leak on exception handling. This was due to a -problem in Cython, not lxml itself.
  • -
  • Failing import on systems that have an io module.
  • -
-
-
-
-

2.2beta1 (2008-12-12)

-
-

Features added

-
    -
  • Allow lxml.html.diff.htmldiff to accept Element objects, not -just HTML strings.
  • -
-
-
-

Bugs fixed

-
    -
  • Crash when using an XPath evaluator in multiple threads.
  • -
  • Fixed missing whitespace before Link:... in lxml.html.diff.
  • -
-
-
-

Other changes

-
    -
  • Export lxml.html.parse.
  • -
-
-
-
-

2.1.4 (2008-12-12)

-
-

Bugs fixed

-
    -
  • Crash when using an XPath evaluator in multiple threads.
  • -
-
-
-
-

2.0.11 (2008-12-12)

-
-

Bugs fixed

-
    -
  • Crash when using an XPath evaluator in multiple threads.
  • -
-
-
-
-

2.2alpha1 (2008-11-23)

-
-

Features added

-
    -
  • Support for XSLT result tree fragments in XPath/XSLT extension -functions.
  • -
  • QName objects have new properties namespace and localname.
  • -
  • New options for exclusive C14N and C14N without comments.
  • -
  • Instantiating a custom Element classes creates a new Element.
  • -
-
-
-

Bugs fixed

-
    -
  • XSLT didn't inherit the parse options of the input document.
  • -
  • 0-bytes could slip through the API when used inside of Unicode -strings.
  • -
  • With lxml.html.clean.autolink, links with balanced parenthesis, -that end in a parenthesis, will be linked in their entirety (typical -with Wikipedia links).
  • -
-
-
-

Other changes

-
-
-
-

2.1.3 (2008-11-17)

-
-

Features added

-
-
-

Bugs fixed

-
    -
  • Ref-count leaks when lxml enters a try-except statement while an -outside exception lives in sys.exc_*(). This was due to a problem in -Cython, not lxml itself.
  • -
  • Parser Unicode decoding errors could get swallowed by other -exceptions.
  • -
  • Name/import errors in some Python modules.
  • -
  • Internal DTD subsets that did not specify a system or public ID were -not serialised and did not appear in the docinfo property of -ElementTrees.
  • -
  • Fix a pre-Py3k warning when parsing from a gzip file in Py2.6.
  • -
  • Test suite fixes for libxml2 2.7.
  • -
  • Resolver.resolve_string() did not work for non-ASCII byte strings.
  • -
  • Resolver.resolve_file() was broken.
  • -
  • Overriding the parser encoding didn't work for many encodings.
  • -
-
-
-

Other changes

-
-
-
-

2.0.10 (2008-11-17)

-
-

Bugs fixed

-
    -
  • Ref-count leaks when lxml enters a try-except statement while an -outside exception lives in sys.exc_*(). This was due to a problem in -Cython, not lxml itself.
  • -
-
-
-
-

2.1.2 (2008-09-05)

-
-

Features added

-
    -
  • lxml.etree now tries to find the absolute path name of files when -parsing from a file-like object. This helps custom resolvers when -resolving relative URLs, as lixbml2 can prepend them with the path -of the source document.
  • -
-
-
-

Bugs fixed

-
    -
  • Memory problem when passing documents between threads.
  • -
  • Target parser did not honour the recover option and raised an -exception instead of calling .close() on the target.
  • -
-
-
-

Other changes

-
-
-
-

2.0.9 (2008-09-05)

-
-

Bugs fixed

-
    -
  • Memory problem when passing documents between threads.
  • -
  • Target parser did not honour the recover option and raised an -exception instead of calling .close() on the target.
  • -
-
-
-
-

2.1.1 (2008-07-24)

-
-

Features added

-
-
-

Bugs fixed

-
    -
  • Crash when parsing XSLT stylesheets in a thread and using them in -another.
  • -
  • Encoding problem when including text with ElementInclude under -Python 3.
  • -
-
-
-

Other changes

-
-
-
-

2.0.8 (2008-07-24)

-
-

Features added

-
    -
  • lxml.html.rewrite_links() strips links to work around documents -with whitespace in URL attributes.
  • -
-
-
-

Bugs fixed

-
    -
  • Crash when parsing XSLT stylesheets in a thread and using them in -another.
  • -
  • CSS selector parser dropped remaining expression after a function -with parameters.
  • -
-
-
-

Other changes

-
-
-
-

2.1 (2008-07-09)

-
-

Features added

-
    -
  • Smart strings can be switched off in XPath (smart_strings -keyword option).
  • -
  • lxml.html.rewrite_links() strips links to work around documents -with whitespace in URL attributes.
  • -
-
-
-

Bugs fixed

-
    -
  • Custom resolvers were not used for XMLSchema includes/imports and -XInclude processing.
  • -
  • CSS selector parser dropped remaining expression after a function -with parameters.
  • -
-
-
-

Other changes

-
    -
  • objectify.enableRecursiveStr() was removed, use -objectify.enable_recursive_str() instead
  • -
  • Speed-up when running XSLTs on documents from other threads
  • -
-
-
-
-

2.0.7 (2008-06-20)

-
-

Features added

-
    -
  • Pickling ElementTree objects in lxml.objectify.
  • -
-
-
-

Bugs fixed

-
    -
  • Descending dot-separated classes in CSS selectors were not resolved -correctly.
  • -
  • ElementTree.parse() didn't handle target parser result.
  • -
  • Potential threading problem in XInclude.
  • -
  • Crash in Element class lookup classes when the __init__() method of -the super class is not called from Python subclasses.
  • -
-
-
-

Other changes

-
    -
  • Non-ASCII characters in attribute values are no longer escaped on -serialisation.
  • -
-
-
-
-

2.1beta3 (2008-06-19)

-
-

Features added

-
    -
  • Major overhaul of tools/xpathgrep.py script.
  • -
  • Pickling ElementTree objects in lxml.objectify.
  • -
  • Support for parsing from file-like objects that return unicode -strings.
  • -
  • New function etree.cleanup_namespaces(el) that removes unused -namespace declarations from a (sub)tree (experimental).
  • -
  • XSLT results support the buffer protocol in Python 3.
  • -
  • Polymorphic functions in lxml.html that accept either a tree or -a parsable string will return either a UTF-8 encoded byte string, a -unicode string or a tree, based on the type of the input. -Previously, the result was always a byte string or a tree.
  • -
  • Support for Python 2.6 and 3.0 beta.
  • -
  • File name handling now uses a heuristic to convert between byte -strings (usually filenames) and unicode strings (usually URLs).
  • -
  • Parsing from a plain file object frees the GIL under Python 2.x.
  • -
  • Running iterparse() on a plain file (or filename) frees the GIL -on reading under Python 2.x.
  • -
  • Conversion functions html_to_xhtml() and xhtml_to_html() in -lxml.html (experimental).
  • -
  • Most features in lxml.html work for XHTML namespaced tag names -(experimental).
  • -
-
-
-

Bugs fixed

-
    -
  • ElementTree.parse() didn't handle target parser result.
  • -
  • Crash in Element class lookup classes when the __init__() method of -the super class is not called from Python subclasses.
  • -
  • A number of problems related to unicode/byte string conversion of -filenames and error messages were fixed.
  • -
  • Building on MacOS-X now passes the "flat_namespace" option to the C -compiler, which reportedly prevents build quirks and crashes on this -platform.
  • -
  • Windows build was broken.
  • -
  • Rare crash when serialising to a file object with certain encodings.
  • -
-
-
-

Other changes

-
    -
  • Non-ASCII characters in attribute values are no longer escaped on -serialisation.
  • -
  • Passing non-ASCII byte strings or invalid unicode strings as .tag, -namespaces, etc. will result in a ValueError instead of an -AssertionError (just like the tag well-formedness check).
  • -
  • Up to several times faster attribute access (i.e. tree traversal) in -lxml.objectify.
  • -
-
-
-
-

2.0.6 (2008-05-31)

-
-

Features added

-
-
-

Bugs fixed

-
    -
  • Incorrect evaluation of el.find("tag[child]").
  • -
  • Windows build was broken.
  • -
  • Moving a subtree from a document created in one thread into a -document of another thread could crash when the rest of the source -document is deleted while the subtree is still in use.
  • -
  • Rare crash when serialising to a file object with certain encodings.
  • -
-
-
-

Other changes

-
    -
  • lxml should now build without problems on MacOS-X.
  • -
-
-
-
-

2.1beta2 (2008-05-02)

-
-

Features added

-
    -
  • All parse functions in lxml.html take a parser keyword argument.
  • -
  • lxml.html has a new parser class XHTMLParser and a module -attribute xhtml_parser that provide XML parsers that are -pre-configured for the lxml.html package.
  • -
-
-
-

Bugs fixed

-
    -
  • Moving a subtree from a document created in one thread into a -document of another thread could crash when the rest of the source -document is deleted while the subtree is still in use.
  • -
  • Passing an nsmap when creating an Element will no longer strip -redundantly defined namespace URIs. This prevented the definition -of more than one prefix for a namespace on the same Element.
  • -
-
-
-

Other changes

-
    -
  • If the default namespace is redundantly defined with a prefix on the -same Element, the prefix will now be preferred for subelements and -attributes. This allows users to work around a problem in libxml2 -where attributes from the default namespace could serialise without -a prefix even when they appear on an Element with a different -namespace (i.e. they would end up in the wrong namespace).
  • -
-
-
-
-

2.0.5 (2008-05-01)

-
-

Features added

-
-
-

Bugs fixed

-
    -
  • Resolving to a filename in custom resolvers didn't work.
  • -
  • lxml did not honour libxslt's second error state "STOPPED", which -let some XSLT errors pass silently.
  • -
  • Memory leak in Schematron with libxml2 >= 2.6.31.
  • -
-
-
-

Other changes

-
-
-
-

2.1beta1 (2008-04-15)

-
-

Features added

-
    -
  • Error logging in Schematron (requires libxml2 2.6.32 or later).
  • -
  • Parser option strip_cdata for normalising or keeping CDATA -sections. Defaults to True as before, thus replacing CDATA -sections by their text content.
  • -
  • CDATA() factory to wrap string content as CDATA section.
  • -
-
-
-

Bugs fixed

-
    -
  • Resolving to a filename in custom resolvers didn't work.
  • -
  • lxml did not honour libxslt's second error state "STOPPED", which -let some XSLT errors pass silently.
  • -
  • Memory leak in Schematron with libxml2 >= 2.6.31.
  • -
  • lxml.etree accepted non well-formed namespace prefix names.
  • -
-
-
-

Other changes

-
    -
  • Major cleanup in internal moveNodeToDocument() function, which -takes care of namespace cleanup when moving elements between -different namespace contexts.
  • -
  • New Elements created through the makeelement() method of an HTML -parser or through lxml.html now end up in a new HTML document -(doctype HTML 4.01 Transitional) instead of a generic XML document. -This mostly impacts the serialisation and the availability of a DTD -context.
  • -
-
-
-
-

2.0.4 (2008-04-13)

-
-

Features added

-
-
-

Bugs fixed

-
    -
  • Hanging thread in conjunction with GTK threading.
  • -
  • Crash bug in iterparse when moving elements into other documents.
  • -
  • HTML elements' .cssselect() method was broken.
  • -
  • ElementTree.find*() didn't accept QName objects.
  • -
-
-
-

Other changes

-
-
-
-

2.1alpha1 (2008-03-27)

-
-

Features added

-
    -
  • New event types 'comment' and 'pi' in iterparse().
  • -
  • XSLTAccessControl instances have a property options that -returns a dict of access configuration options.
  • -
  • Constant instances DENY_ALL and DENY_WRITE on -XSLTAccessControl class.
  • -
  • Extension elements for XSLT (experimental!)
  • -
  • Element.base property returns the xml:base or HTML base URL of -an Element.
  • -
  • docinfo.URL property is writable.
  • -
-
-
-

Bugs fixed

-
    -
  • Default encoding for plain text serialisation was different from -that of XML serialisation (UTF-8 instead of ASCII).
  • -
-
-
-

Other changes

-
    -
  • Minor API speed-ups.
  • -
  • The benchmark suite now uses tail text in the trees, which makes the -absolute numbers incomparable to previous results.
  • -
  • Generating the HTML documentation now requires Pygments, which is -used to enable syntax highlighting for the doctest examples.
  • -
-

Most long-time deprecated functions and methods were removed:

-
    -
  • etree.clearErrorLog(), use etree.clear_error_log()

    -
  • -
  • etree.useGlobalPythonLog(), use -etree.use_global_python_log()

    -
  • -
  • etree.ElementClassLookup.setFallback(), use -etree.ElementClassLookup.set_fallback()

    -
  • -
  • etree.getDefaultParser(), use etree.get_default_parser()

    -
  • -
  • etree.setDefaultParser(), use etree.set_default_parser()

    -
  • -
  • etree.setElementClassLookup(), use -etree.set_element_class_lookup()

    -

    Note that parser.setElementClassLookup() has not been removed -yet, although parser.set_element_class_lookup() should be used -instead.

    -
  • -
  • xpath_evaluator.registerNamespace(), use -xpath_evaluator.register_namespace()

    -
  • -
  • xpath_evaluator.registerNamespaces(), use -xpath_evaluator.register_namespaces()

    -
  • -
  • objectify.setPytypeAttributeTag, use -objectify.set_pytype_attribute_tag

    -
  • -
  • objectify.setDefaultParser(), use -objectify.set_default_parser()

    -
  • -
-
-
-
-

2.0.3 (2008-03-26)

-
-

Features added

-
    -
  • soupparser.parse() allows passing keyword arguments on to -BeautifulSoup.
  • -
  • fromstring() method in lxml.html.soupparser.
  • -
-
-
-

Bugs fixed

-
    -
  • lxml.html.diff didn't treat empty tags properly (e.g., -<br>).
  • -
  • Handle entity replacements correctly in target parser.
  • -
  • Crash when using iterparse() with XML Schema validation.
  • -
  • The BeautifulSoup parser (soupparser.py) did not replace entities, -which made them turn up in text content.
  • -
  • Attribute assignment of custom PyTypes in objectify could fail to -correctly serialise the value to a string.
  • -
-
-
-

Other changes

-
    -
  • lxml.html.ElementSoup was replaced by a new module -lxml.html.soupparser with a more consistent API. The old module -remains for compatibility with ElementTree's own ElementSoup module.
  • -
  • Setting the XSLT_CONFIG and XML2_CONFIG environment variables at -build time will let setup.py pick up the xml2-config and -xslt-config scripts from the supplied path name.
  • -
  • Passing --with-xml2-config=/path/to/xml2-config to setup.py will -override the xml2-config script that is used to determine the C -compiler options. The same applies for the --with-xslt-config -option.
  • -
-
-
-
-

2.0.2 (2008-02-22)

-
-

Features added

-
    -
  • Support passing base_url to file parser functions to override -the filename of the file(-like) object.
  • -
-
-
-

Bugs fixed

-
    -
  • The prefix for objectify's pytype namespace was missing from the set -of default prefixes.
  • -
  • Memory leak in Schematron (fixed only for libxml2 2.6.31+).
  • -
  • Error type names in RelaxNG were reported incorrectly.
  • -
  • Slice deletion bug fixed in objectify.
  • -
-
-
-

Other changes

-
    -
  • Enabled doctests for some Python modules (especially lxml.html).
  • -
  • Add a method argument to lxml.html.tostring() -(method="xml" for XHTML output).
  • -
  • Make it clearer that methods like lxml.html.fromstring() take a -base_url argument.
  • -
-
-
-
-

2.0.1 (2008-02-13)

-
-

Features added

-
    -
  • Child iteration in lxml.pyclasslookup.
  • -
  • Loads of new docstrings reflect the signature of functions and -methods to make them visible in API docs and help()
  • -
-
-
-

Bugs fixed

-
    -
  • The module lxml.html.builder was duplicated as -lxml.htmlbuilder
  • -
  • Form elements would return None for form.fields.keys() if there -was an unnamed input field. Now unnamed input fields are completely -ignored.
  • -
  • Setting an element slice in objectify could insert slice-overlapping -elements at the wrong position.
  • -
-
-
-

Other changes

-
    -
  • The generated API documentation was cleaned up and disburdened from -non-public classes etc.
  • -
  • The previously public module lxml.html.setmixin was renamed to -lxml.html._setmixin as it is not an official part of lxml. If -you want to use it, feel free to copy it over to your own source -base.
  • -
  • Passing --with-xslt-config=/path/to/xslt-config to setup.py will -override the xslt-config script that is used to determine the C -compiler options.
  • -
-
-
-
-

2.0 (2008-02-01)

-
-

Features added

-
    -
  • Passing the unicode type as encoding to tostring() will -serialise to unicode. The tounicode() function is now -deprecated.
  • -
  • XMLSchema() and RelaxNG() can parse from StringIO.
  • -
  • makeparser() function in lxml.objectify to create a new -parser with the usual objectify setup.
  • -
  • Plain ASCII XPath string results are no longer forced into unicode -objects as in 2.0beta1, but are returned as plain strings as before.
  • -
  • All XPath string results are 'smart' objects that have a -getparent() method to retrieve their parent Element.
  • -
  • with_tail option in serialiser functions.
  • -
  • More accurate exception messages in validator creation.
  • -
  • Parse-time XML schema validation (schema parser keyword).
  • -
  • XPath string results of the text() function and attribute -selection make their Element container accessible through a -getparent() method. As a side-effect, they are now always -unicode objects (even ASCII strings).
  • -
  • XSLT objects are usable in any thread - at the cost of a deep -copy if they were not created in that thread.
  • -
  • Invalid entity names and character references will be rejected by -the Entity() factory.
  • -
  • entity.text returns the textual representation of the entity, -e.g. &amp;.
  • -
  • New properties position and code on ParseError exception (as -in ET 1.3)
  • -
  • Rich comparison of element.attrib proxies.
  • -
  • ElementTree compatible TreeBuilder class.
  • -
  • Use default prefixes for some common XML namespaces.
  • -
  • lxml.html.clean.Cleaner now allows for a host_whitelist, and -two overridable methods: allow_embedded_url(el, url) and the -more general allow_element(el).
  • -
  • Extended slicing of Elements as in element[1:-1:2], both in -etree and in objectify
  • -
  • Resolvers can now provide a base_url keyword argument when -resolving a document as string data.
  • -
  • When using lxml.doctestcompare you can give the doctest option -NOPARSE_MARKUP (like # doctest: +NOPARSE_MARKUP) to suppress -the special checking for one test.
  • -
  • Separate feed_error_log property for the feed parser interface. -The normal parser interface and iterparse continue to use -error_log.
  • -
  • The normal parsers and the feed parser interface are now separated -and can be used concurrently on the same parser instance.
  • -
  • fromstringlist() and tostringlist() functions as in -ElementTree 1.3
  • -
  • iterparse() accepts an html boolean keyword argument for -parsing with the HTML parser (note that this interface may be -subject to change)
  • -
  • Parsers accept an encoding keyword argument that overrides the encoding -of the parsed documents.
  • -
  • New C-API function hasChild() to test for children
  • -
  • annotate() function in objectify can annotate with Python types and XSI -types in one step. Accompanied by xsiannotate() and pyannotate().
  • -
  • ET.write(), tostring() and tounicode() now accept a keyword -argument method that can be one of 'xml' (or None), 'html' or 'text' to -serialise as XML, HTML or plain text content.
  • -
  • iterfind() method on Elements returns an iterator equivalent to -findall()
  • -
  • itertext() method on Elements
  • -
  • Setting a QName object as value of the .text property or as an attribute -will resolve its prefix in the respective context
  • -
  • ElementTree-like parser target interface as described in -http://effbot.org/elementtree/elementtree-xmlparser.htm
  • -
  • ElementTree-like feed parser interface on XMLParser and HTMLParser -(feed() and close() methods)
  • -
  • Reimplemented objectify.E for better performance and improved -integration with objectify. Provides extended type support based on -registered PyTypes.
  • -
  • XSLT objects now support deep copying
  • -
  • New makeSubElement() C-API function that allows creating a new -subelement straight with text, tail and attributes.
  • -
  • XPath extension functions can now access the current context node -(context.context_node) and use a context dictionary -(context.eval_context) from the context provided in their first -parameter
  • -
  • HTML tag soup parser based on BeautifulSoup in lxml.html.ElementSoup
  • -
  • New module lxml.doctestcompare by Ian Bicking for writing simplified -doctests based on XML/HTML output. Use by importing lxml.usedoctest or -lxml.html.usedoctest from within a doctest.
  • -
  • New module lxml.cssselect by Ian Bicking for selecting Elements with CSS -selectors.
  • -
  • New package lxml.html written by Ian Bicking for advanced HTML -treatment.
  • -
  • Namespace class setup is now local to the ElementNamespaceClassLookup -instance and no longer global.
  • -
  • Schematron validation (incomplete in libxml2)
  • -
  • Additional stringify argument to objectify.PyType() takes a -conversion function to strings to support setting text values from arbitrary -types.
  • -
  • Entity support through an Entity factory and element classes. XML -parsers now have a resolve_entities keyword argument that can be set to -False to keep entities in the document.
  • -
  • column field on error log entries to accompany the line field
  • -
  • Error specific messages in XPath parsing and evaluation -NOTE: for evaluation errors, you will now get an XPathEvalError instead of -an XPathSyntaxError. To catch both, you can except on XPathError
  • -
  • The regular expression functions in XPath now support passing a node-set -instead of a string
  • -
  • Extended type annotation in objectify: new xsiannotate() function
  • -
  • EXSLT RegExp support in standard XPath (not only XSLT)
  • -
-
-
-

Bugs fixed

-
    -
  • Missing import in lxml.html.clean.
  • -
  • Some Python 2.4-isms prevented lxml from building/running under -Python 2.3.
  • -
  • XPath on ElementTrees could crash when selecting the virtual root -node of the ElementTree.
  • -
  • Compilation --without-threading was buggy in alpha5/6.
  • -
  • Memory leak in the parse() function.
  • -
  • Minor bugs in XSLT error message formatting.
  • -
  • Result document memory leak in target parser.
  • -
  • Target parser failed to report comments.
  • -
  • In the lxml.html iter_links method, links in <object> -tags weren't recognized. (Note: plugin-specific link parameters -still aren't recognized.) Also, the <embed> tag, though not -standard, is now included in lxml.html.defs.special_inline_tags.
  • -
  • Using custom resolvers on XSLT stylesheets parsed from a string -could request ill-formed URLs.
  • -
  • With lxml.doctestcompare if you do <tag xmlns="..."> in your -output, it will then be namespace-neutral (before the ellipsis was -treated as a real namespace).
  • -
  • AttributeError in feed parser on parse errors
  • -
  • XML feed parser setup problem
  • -
  • Type annotation for unicode strings in DataElement()
  • -
  • lxml failed to serialise namespace declarations of elements other than the -root node of a tree
  • -
  • Race condition in XSLT where the resolver context leaked between concurrent -XSLT calls
  • -
  • lxml.etree did not check tag/attribute names
  • -
  • The XML parser did not report undefined entities as error
  • -
  • The text in exceptions raised by XML parsers, validators and XPath -evaluators now reports the first error that occurred instead of the last
  • -
  • Passing '' as XPath namespace prefix did not raise an error
  • -
  • Thread safety in XPath evaluators
  • -
-
-
-

Other changes

-
    -
  • Exceptions carry only the part of the error log that is related to -the operation that caused the error.
  • -
  • XMLSchema() and RelaxNG() now enforce passing the source -file/filename through the file keyword argument.
  • -
  • The test suite now skips most doctests under Python 2.3.
  • -
  • make clean no longer removes the .c files (use make -realclean instead)
  • -
  • Minor performance tweaks for Element instantiation and subelement -creation
  • -
  • Various places in the XPath, XSLT and iteration APIs now require -keyword-only arguments.
  • -
  • The argument order in element.itersiblings() was changed to -match the order used in all other iteration methods. The second -argument ('preceding') is now a keyword-only argument.
  • -
  • The getiterator() method on Elements and ElementTrees was -reverted to return an iterator as it did in lxml 1.x. The ET API -specification allows it to return either a sequence or an iterator, -and it traditionally returned a sequence in ET and an iterator in -lxml. However, it is now deprecated in favour of the iter() -method, which should be used in new code wherever possible.
  • -
  • The 'pretty printed' serialisation of ElementTree objects now -inserts newlines at the root level between processing instructions, -comments and the root tag.
  • -
  • A 'pretty printed' serialisation is now terminated with a newline.
  • -
  • Second argument to lxml.etree.Extension() helper is no longer -required, third argument is now a keyword-only argument ns.
  • -
  • lxml.html.tostring takes an encoding argument.
  • -
  • The module source files were renamed to "lxml.*.pyx", such as -"lxml.etree.pyx". This was changed for consistency with the way -Pyrex commonly handles package imports. The main effect is that -classes now know about their fully qualified class name, including -the package name of their module.
  • -
  • Keyword-only arguments in some API functions, especially in the -parsers and serialisers.
  • -
  • Tag name validation in lxml.etree (and lxml.html) now distinguishes -between HTML tags and XML tags based on the parser that was used to -parse or create them. HTML tags no longer reject any non-ASCII -characters in tag names but only spaces and the special characters -<>&/"'.
  • -
  • lxml.etree now emits a warning if you use XPath with libxml2 2.6.27 -(which can crash on certain XPath errors)
  • -
  • Type annotation in objectify now preserves the already annotated type by -default to prevent losing type information that is already there.
  • -
  • element.getiterator() returns a list, use element.iter() to retrieve -an iterator (ElementTree 1.3 compatible behaviour)
  • -
  • objectify.PyType for None is now called "NoneType"
  • -
  • el.getiterator() renamed to el.iter(), following ElementTree 1.3 - -original name is still available as alias
  • -
  • In the public C-API, findOrBuildNodeNs() was replaced by the more -generic findOrBuildNodeNsPrefix
  • -
  • Major refactoring in XPath/XSLT extension function code
  • -
  • Network access in parsers disabled by default
  • -
-
-
-
-

1.3.6 (2007-10-29)

-
-

Bugs fixed

-
    -
  • Backported decref crash fix from 2.0
  • -
  • Well hidden free-while-in-use crash bug in ObjectPath
  • -
-
-
-

Other changes

-
    -
  • The test suites now run gc.collect() in the tearDown() -methods. While this makes them take a lot longer to run, it also -makes it easier to link a specific test to garbage collection -problems that would otherwise appear in later tests.
  • -
-
-
-
-

1.3.5 (2007-10-22)

-
-

Features added

-
-
-

Bugs fixed

-
    -
  • lxml.etree could crash when adding more than 10000 namespaces to a -document
  • -
  • lxml failed to serialise namespace declarations of elements other -than the root node of a tree
  • -
-
-
-
-

1.3.4 (2007-08-30)

-
-

Features added

-
    -
  • The ElementMaker in lxml.builder now accepts the keyword arguments -namespace and nsmap to set a namespace and nsmap for the Elements it -creates.
  • -
  • The docinfo on ElementTree objects has new properties internalDTD -and externalDTD that return a DTD object for the internal or external -subset of the document respectively.
  • -
  • Serialising an ElementTree now includes any internal DTD subsets that are -part of the document, as well as comments and PIs that are siblings of the -root node.
  • -
-
-
-

Bugs fixed

-
    -
  • Parsing with the no_network option could fail
  • -
-
-
-

Other changes

-
    -
  • lxml now raises a TagNameWarning about tag names containing ':' instead of -an Error as 1.3.3 did. The reason is that a number of projects currently -misuse the previous lack of tag name validation to generate namespace -prefixes without declaring namespaces. Apart from the danger of generating -broken XML this way, it also breaks most of the namespace-aware tools in -XML, including XPath, XSLT and validation. lxml 1.3.x will continue to -support this bug with a Warning, while lxml 2.0 will be strict about -well-formed tag names (not only regarding ':').
  • -
  • Serialising an Element no longer includes its comment and PI siblings (only -ElementTree serialisation includes them).
  • -
-
-
-
-

1.3.3 (2007-07-26)

-
-

Features added

-
    -
  • ElementTree compatible parser ETCompatXMLParser strips processing -instructions and comments while parsing XML
  • -
  • Parsers now support stripping PIs (keyword argument 'remove_pis')
  • -
  • etree.fromstring() now supports parsing both HTML and XML, depending on -the parser you pass.
  • -
  • Support base_url keyword argument in HTML() and XML()
  • -
-
-
-

Bugs fixed

-
    -
  • Parsing from Python Unicode strings failed on some platforms
  • -
  • Element() did not raise an exception on tag names containing ':'
  • -
  • Element.getiterator(tag) did not accept Comment and -ProcessingInstruction as tags. It also accepts Element now.
  • -
-
-
-
-

1.3.2 (2007-07-03)

-
-

Features added

-
-
-

Bugs fixed

-
    -
  • "deallocating None" crash bug
  • -
-
-
-
-

1.3.1 (2007-07-02)

-
-

Features added

-
    -
  • objectify.DataElement now supports setting values from existing data -elements (not just plain Python types) and reuses defined namespaces etc.
  • -
  • E-factory support for lxml.objectify (objectify.E)
  • -
-
-
-

Bugs fixed

-
    -
  • Better way to prevent crashes in Element proxy cleanup code
  • -
  • objectify.DataElement didn't set up None value correctly
  • -
  • objectify.DataElement didn't check the value against the provided type hints
  • -
  • Reference-counting bug in Element.attrib.pop()
  • -
-
-
-
-

1.3 (2007-06-24)

-
-

Features added

-
    -
  • Module lxml.pyclasslookup module implements an Element class lookup -scheme that can access the entire tree in read-only mode to help determining -a suitable Element class
  • -
  • Parsers take a remove_comments keyword argument that skips over comments
  • -
  • parse() function in objectify, corresponding to XML() etc.
  • -
  • Element.addnext(el) and Element.addprevious(el) methods to support -adding processing instructions and comments around the root node
  • -
  • Element.attrib was missing clear() and pop() methods
  • -
  • Extended type annotation in objectify: cleaner annotation namespace setup -plus new deannotate() function
  • -
  • Support for custom Element class instantiation in lxml.sax: passing a -makeelement function to the ElementTreeContentHandler will reuse the -lookup context of that function
  • -
  • '.' represents empty ObjectPath (identity)
  • -
  • Element.values() to accompany the existing .keys() and .items()
  • -
  • collectAttributes() C-function to build a list of attribute -keys/values/items for a libxml2 node
  • -
  • DTD validator class (like RelaxNG and XMLSchema)
  • -
  • HTML generator helpers by Fredrik Lundh in lxml.htmlbuilder
  • -
  • ElementMaker XML generator by Fredrik Lundh in lxml.builder.E
  • -
  • Support for pickling objectify.ObjectifiedElement objects to XML
  • -
  • update() method on Element.attrib
  • -
  • Optimised replacement for libxml2's _xmlReconsiliateNs(). This allows lxml -a better handling of namespaces when moving elements between documents.
  • -
-
-
-

Bugs fixed

-
    -
  • Removing Elements from a tree could make them lose their namespace -declarations
  • -
  • ElementInclude didn't honour base URL of original document
  • -
  • Replacing the children slice of an Element would cut off the tails of the -original children
  • -
  • Element.getiterator(tag) did not accept Comment and -ProcessingInstruction as tags
  • -
  • API functions now check incoming strings for XML conformity. Zero bytes or -low ASCII characters are no longer accepted (AssertionError).
  • -
  • XSLT parsing failed to pass resolver context on to imported documents
  • -
  • passing '' as namespace prefix in nsmap could be passed through to libxml2
  • -
  • Objectify couldn't handle prefixed XSD type names in xsi:type
  • -
  • More ET compatible behaviour when writing out XML declarations or not
  • -
  • More robust error handling in iterparse()
  • -
  • Documents lost their top-level PIs and comments on serialisation
  • -
  • lxml.sax failed on comments and PIs. Comments are now properly ignored and -PIs are copied.
  • -
  • Possible memory leaks in namespace handling when moving elements between -documents
  • -
-
-
-

Other changes

-
    -
  • major restructuring in the documentation
  • -
-
-
-
-

1.2.1 (2007-02-27)

-
-

Bugs fixed

-
    -
  • Build fixes for MS compiler
  • -
  • Item assignments to special names like element["text"] failed
  • -
  • Renamed ObjectifiedDataElement.__setText() to _setText() to make it easier -to access
  • -
  • The pattern for attribute names in ObjectPath was too restrictive
  • -
-
-
-
-

1.2 (2007-02-20)

-
-

Features added

-
    -
  • Rich comparison of QName objects
  • -
  • Support for regular expressions in benchmark selection
  • -
  • get/set emulation (not .attrib!) for attributes on processing instructions
  • -
  • ElementInclude Python module for ElementTree compatible XInclude processing -that honours custom resolvers registered with the source document
  • -
  • ElementTree.parser property holds the parser used to parse the document
  • -
  • setup.py has been refactored for greater readability and flexibility
  • -
  • --rpath flag to setup.py to induce automatic linking-in of dynamic library -runtime search paths has been renamed to --auto-rpath. This makes it -possible to pass an --rpath directly to distutils; previously this was being -shadowed.
  • -
-
-
-

Bugs fixed

-
    -
  • Element instantiation now uses locks to prevent race conditions with threads
  • -
  • ElementTree.write() did not raise an exception when the file was not writable
  • -
  • Error handling could crash under Python <= 2.4.1 - fixed by disabling thread -support in these environments
  • -
  • Element.find*() did not accept QName objects as path
  • -
-
-
-

Other changes

-
    -
  • code cleanup: redundant _NodeBase super class merged into _Element class -Note: although the impact should be zero in most cases, this change breaks -the compatibility of the public C-API
  • -
-
-
-
-

1.1.2 (2006-10-30)

-
-

Features added

-
    -
  • Data elements in objectify support repr(), which is now used by dump()
  • -
  • Source distribution now ships with a patched Pyrex
  • -
  • New C-API function makeElement() to create new elements with text, -tail, attributes and namespaces
  • -
  • Reuse original parser flags for XInclude
  • -
  • Simplified support for handling XSLT processing instructions
  • -
-
-
-

Bugs fixed

-
    -
  • Parser resources were not freed before the next parser run
  • -
  • Open files and XML strings returned by Python resolvers were not -closed/freed
  • -
  • Crash in the IDDict returned by XMLDTDID
  • -
  • Copying Comments and ProcessingInstructions failed
  • -
  • Memory leak for external URLs in _XSLTProcessingInstruction.parseXSL()
  • -
  • Memory leak when garbage collecting tailed root elements
  • -
  • HTML script/style content was not propagated to .text
  • -
  • Show text xincluded between text nodes correctly in .text and .tail
  • -
  • 'integer * objectify.StringElement' operation was not supported
  • -
-
-
-
-

1.1.1 (2006-09-21)

-
-

Features added

-
    -
  • XSLT profiling support (profile_run keyword)
  • -
  • countchildren() method on objectify.ObjectifiedElement
  • -
  • Support custom elements for tree nodes in lxml.objectify
  • -
-
-
-

Bugs fixed

-
    -
  • lxml.objectify failed to support long data values (e.g., "123L")
  • -
  • Error messages from XSLT did not reach XSLT.error_log
  • -
  • Factories objectify.Element() and objectify.DataElement() were missing -attrib and nsmap keyword arguments
  • -
  • Changing the default parser in lxml.objectify did not update the factories -Element() and DataElement()
  • -
  • Let lxml.objectify.Element() always generate tree elements (not data -elements)
  • -
  • Build under Windows failed ('0' bug in patched Pyrex version)
  • -
-
-
-
-

1.1 (2006-09-13)

-
-

Features added

-
    -
  • Comments and processing instructions return '<!-- comment -->' and -'<?pi-target content?>' for repr()
  • -
  • Parsers are now the preferred (and default) place where element class lookup -schemes should be registered. Namespace lookup is no longer supported by -default.
  • -
  • Support for Python 2.5 beta
  • -
  • Unlock the GIL for deep copying documents and for XPath()
  • -
  • New compact keyword argument for parsing read-only documents
  • -
  • Support for parser options in iterparse()
  • -
  • The namespace axis is supported in XPath and returns (prefix, URI) -tuples
  • -
  • The XPath expression "/" now returns an empty list instead of raising an -exception
  • -
  • XML-Object API on top of lxml (lxml.objectify)
  • -
  • Customizable Element class lookup:
      -
    • different pre-implemented lookup mechanisms
    • -
    • support for externally provided lookup functions
    • -
    -
  • -
  • Support for processing instructions (ET-like, not compatible)
  • -
  • Public C-level API for independent extension modules
  • -
  • Module level iterwalk() function as 'iterparse' for trees
  • -
  • Module level iterparse() function similar to ElementTree (see -documentation for differences)
  • -
  • Element.nsmap property returns a mapping of all namespace prefixes known at -the Element to their namespace URI
  • -
  • Reentrant threading support in RelaxNG, XMLSchema and XSLT
  • -
  • Threading support in parsers and serializers:
      -
    • All in-memory operations (tostring, parse(StringIO), etc.) free the GIL
    • -
    • File operations (on file names) free the GIL
    • -
    • Reading from file-like objects frees the GIL and reacquires it for reading
    • -
    • Serialisation to file-like objects is single-threaded (high lock overhead)
    • -
    -
  • -
  • Element iteration over XPath axes:
      -
    • Element.iterdescendants() iterates over the descendants of an element
    • -
    • Element.iterancestors() iterates over the ancestors of an element (from -parent to parent)
    • -
    • Element.itersiblings() iterates over either the following or preceding -siblings of an element
    • -
    • Element.iterchildren() iterates over the children of an element in either -direction
    • -
    • All iterators support the tag keyword argument to restrict the -generated elements
    • -
    -
  • -
  • Element.getnext() and Element.getprevious() return the direct siblings of an -element
  • -
-
-
-

Bugs fixed

-
    -
  • filenames with local 8-bit encoding were not supported
  • -
  • 1.1beta did not compile under Python 2.3
  • -
  • ignore unknown 'pyval' attribute values in objectify
  • -
  • objectify.ObjectifiedElement.addattr() failed to accept Elements and Lists
  • -
  • objectify.ObjectPath.setattr() failed to accept Elements and Lists
  • -
  • XPathSyntaxError now inherits from XPathError
  • -
  • Threading race conditions in RelaxNG and XMLSchema
  • -
  • Crash when mixing elements from XSLT results into other trees, concurrent -XSLT is only allowed when the stylesheet was parsed in the main thread
  • -
  • The EXSLT regexp:match function now works as defined (except for some -differences in the regular expression syntax)
  • -
  • Setting element.text to '' returned None on request, not the empty string
  • -
  • iterparse() could crash on long XML files
  • -
  • Creating documents no longer copies the parser for later URL resolving. For -performance reasons, only a reference is kept. Resolver updates on the -parser will now be reflected by documents that were parsed before the -change. Although this should rarely become visible, it is a behavioral -change from 1.0.
  • -
-
-
-
-

1.0.4 (2006-09-09)

-
-

Features added

-
    -
  • List-like Element.extend() method
  • -
-
-
-

Bugs fixed

-
    -
  • Crash in tail handling in Element.replace()
  • -
-
-
-
-

1.0.3 (2006-08-08)

-
-

Features added

-
    -
  • Element.replace(old, new) method to replace a subelement by another one
  • -
-
-
-

Bugs fixed

-
    -
  • Crash when mixing elements from XSLT results into other trees
  • -
  • Copying/deepcopying did not work for ElementTree objects
  • -
  • Setting an attribute to a non-string value did not raise an exception
  • -
  • Element.remove() deleted the tail text from the removed Element
  • -
-
-
-
-

1.0.2 (2006-06-27)

-
-

Features added

-
    -
  • Support for setting a custom default Element class as opposed to namespace -specific classes (which still override the default class)
  • -
-
-
-

Bugs fixed

-
    -
  • Rare exceptions in Python list functions were not handled
  • -
  • Parsing accepted unicode strings with XML encoding declaration in certain -cases
  • -
  • Parsing 8-bit encoded strings from StringIO objects raised an exception
  • -
  • Module function initThread() was removed - useless (and never worked)
  • -
  • XSLT and parser exception messages include the error line number
  • -
-
-
-
-

1.0.1 (2006-06-09)

-
-

Features added

-
    -
  • Repeated calls to Element.attrib now efficiently return the same instance
  • -
-
-
-

Bugs fixed

-
    -
  • Document deallocation could crash in certain garbage collection scenarios
  • -
  • Extension function calls in XSLT variable declarations could break the -stylesheet and crash on repeated calls
  • -
  • Deep copying Elements could lose namespaces declared in parents
  • -
  • Deep copying Elements did not copy tail
  • -
  • Parsing file(-like) objects failed to load external entities
  • -
  • Parsing 8-bit strings from file(-like) objects raised an exception
  • -
  • xsl:include failed when the stylesheet was parsed from a file-like object
  • -
  • lxml.sax.ElementTreeProducer did not call startDocument() / endDocument()
  • -
  • MSVC compiler complained about long strings (supports only 2048 bytes)
  • -
-
-
-
-

1.0 (2006-06-01)

-
-

Features added

-
    -
  • Element.getiterator() and the findall() methods support finding arbitrary -elements from a namespace (pattern {namespace}*)
  • -
  • Another speedup in tree iteration code
  • -
  • General speedup of Python Element object creation and deallocation
  • -
  • Writing C14N no longer serializes in memory (reduced memory footprint)
  • -
  • PyErrorLog for error logging through the Python logging module
  • -
  • Element.getroottree() returns an ElementTree for the root node of the -document that contains the element.
  • -
  • ElementTree.getpath(element) returns a simple, absolute XPath expression to -find the element in the tree structure
  • -
  • Error logs have a last_error attribute for convenience
  • -
  • Comment texts can be changed through the API
  • -
  • Formatted output via pretty_print keyword in serialization functions
  • -
  • XSLT can block access to file system and network via XSLTAccessControl
  • -
  • ElementTree.write() no longer serializes in memory (reduced memory -footprint)
  • -
  • Speedup of Element.findall(tag) and Element.getiterator(tag)
  • -
  • Support for writing the XML representation of Elements and ElementTrees to -Python unicode strings via etree.tounicode()
  • -
  • Support for writing XSLT results to Python unicode strings via unicode()
  • -
  • Parsing a unicode string no longer copies the string (reduced memory -footprint)
  • -
  • Parsing file-like objects reads chunks rather than the whole file (reduced -memory footprint)
  • -
  • Parsing StringIO objects from the start avoids copying the string (reduced -memory footprint)
  • -
  • Read-only 'docinfo' attribute in ElementTree class holds DOCTYPE -information, original encoding and XML version as seen by the parser
  • -
  • etree module can be compiled without libxslt by commenting out the line -include "xslt.pxi" near the end of the etree.pyx source file
  • -
  • Better error messages in parser exceptions
  • -
  • Error reporting also works in XSLT
  • -
  • Support for custom document loaders (URI resolvers) in parsers and XSLT, -resolvers are registered at parser level
  • -
  • Implementation of exslt:regexp for XSLT based on the Python 're' module, -enabled by default, can be switched off with 'regexp=False' keyword argument
  • -
  • Support for exslt extensions (libexslt) and libxslt extra functions -(node-set, document, write, output)
  • -
  • Substantial speedup in XPath.evaluate()
  • -
  • HTMLParser for parsing (broken) HTML
  • -
  • XMLDTDID function parses XML into tuple (root node, ID dict) based on xml:id -implementation of libxml2 (as opposed to ET compatible XMLID)
  • -
-
-
-

Bugs fixed

-
    -
  • Memory leak in Element.__setitem__
  • -
  • Memory leak in Element.attrib.items() and Element.attrib.values()
  • -
  • Memory leak in XPath extension functions
  • -
  • Memory leak in unicode related setup code
  • -
  • Element now raises ValueError on empty tag names
  • -
  • Namespace fixing after moving elements between documents could fail if the -source document was freed too early
  • -
  • Setting namespace-less tag names on namespaced elements ('{ns}t' -> 't') -didn't reset the namespace
  • -
  • Unknown constants from newer libxml2 versions could raise exceptions in the -error handlers
  • -
  • lxml.etree compiles much faster
  • -
  • On libxml2 <= 2.6.22, parsing strings with encoding declaration could fail -in certain cases
  • -
  • Document reference in ElementTree objects was not updated when the root -element was moved to a different document
  • -
  • Running absolute XPath expressions on an Element now evaluates against the -root tree
  • -
  • Evaluating absolute XPath expressions (/*) on an ElementTree could fail
  • -
  • Crashes when calling XSLT, RelaxNG, etc. with uninitialized ElementTree -objects
  • -
  • Removed public function initThreadLogging(), replaced by more general -initThread() which fixes a number of setup problems in threads
  • -
  • Memory leak when using iconv encoders in tostring/write
  • -
  • Deep copying Elements and ElementTrees maintains the document information
  • -
  • Serialization functions raise LookupError for unknown encodings
  • -
  • Memory deallocation crash resulting from deep copying elements
  • -
  • Some ElementTree methods could crash if the root node was not initialized -(neither file nor element passed to the constructor)
  • -
  • Element/SubElement failed to set attribute namespaces from passed attrib -dictionary
  • -
  • tostring() adds an XML declaration for non-ASCII encodings
  • -
  • tostring() failed to serialize encodings that contain 0-bytes
  • -
  • ElementTree.xpath() and XPathDocumentEvaluator were not using the -ElementTree root node as reference point
  • -
  • Calling document('') in XSLT failed to return the stylesheet
  • -
-
-
-
-

0.9.2 (2006-05-10)

-
-

Features added

-
    -
  • Speedup for Element.makeelement(): the new element reuses the original -libxml2 document instead of creating a new empty one
  • -
  • Speedup for reversed() iteration over element children (Py2.4+ only)
  • -
  • ElementTree compatible QName class
  • -
  • RelaxNG and XMLSchema accept any Element, not only ElementTrees
  • -
-
-
-

Bugs fixed

-
    -
  • str(xslt_result) was broken for XSLT output other than UTF-8
  • -
  • Memory leak if write_c14n fails to write the file after conversion
  • -
  • Crash in XMLSchema and RelaxNG when passing non-schema documents
  • -
  • Memory leak in RelaxNG() when RelaxNGParseError is raised
  • -
-
-
-
-

0.9.1 (2006-03-30)

-
-

Features added

-
    -
  • lxml.sax.ElementTreeContentHandler checks closing elements and raises -SaxError on mismatch
  • -
  • lxml.sax.ElementTreeContentHandler supports namespace-less SAX events -(startElement, endElement) and defaults to empty attributes (keyword -argument)
  • -
  • Speedup for repeatedly accessing element tag names
  • -
  • Minor API performance improvements
  • -
-
-
-

Bugs fixed

-
    -
  • Memory deallocation bug when using XSLT output method "html"
  • -
  • sax.py was handling UTF-8 encoded tag names where it shouldn't
  • -
  • lxml.tests package will no longer be installed (is still in source tar)
  • -
-
-
-
-

0.9 (2006-03-20)

-
-

Features added

-
    -
  • Error logging API for libxml2 error messages
  • -
  • Various performance improvements
  • -
  • Benchmark script for lxml, ElementTree and cElementTree
  • -
  • Support for registering extension functions through new FunctionNamespace -class (see doc/extensions.txt)
  • -
  • ETXPath class for XPath expressions in ElementTree notation ('//{ns}tag')
  • -
  • Support for variables in XPath expressions (also in XPath class)
  • -
  • XPath class for compiled XPath expressions
  • -
  • XMLID module level function (ElementTree compatible)
  • -
  • XMLParser API for customized libxml2 parser configuration
  • -
  • Support for custom Element classes through new Namespace API (see -doc/namespace_extensions.txt)
  • -
  • Common exception base class LxmlError for module exceptions
  • -
  • real iterator support in iter(Element), Element.getiterator()
  • -
  • XSLT objects are callable, result trees support str()
  • -
  • Added MANIFEST.in for easier creation of RPM files.
  • -
  • 'getparent' method on elements allows navigation to an element's -parent element.
  • -
  • Python core compatible SAX tree builder and SAX event generator. See -doc/sax.txt for more information.
  • -
-
-
-

Bugs fixed

-
    -
  • Segfaults and memory leaks in various API functions of Element
  • -
  • Segfault in XSLT.tostring()
  • -
  • ElementTree objects no longer interfere, Elements can be root of different -ElementTrees at the same time
  • -
  • document('') works in XSLT documents read from files (in-memory documents -cannot support this due to libxslt deficiencies)
  • -
-
-
-
-

0.8 (2005-11-03)

-
-

Features added

-
    -
  • Support for copy.deepcopy() on elements. copy.copy() works also, but -does the same thing, and does not create a shallow copy, as that -makes no sense in the context of libxml2 trees. This means a -potential incompatibility with ElementTree, but there's more chance -that it works than if copy.copy() isn't supported at all.
  • -
  • Increased compatibility with (c)ElementTree; .parse() on ElementTree is -supported and parsing of gzipped XML files works.
  • -
  • implemented index() on elements, allowing one to find the index of a -SubElement.
  • -
-
-
-

Bugs fixed

-
    -
  • Use xslt-config instead of xml2-config to find out libxml2 -directories to take into account a case where libxslt is installed -in a different directory than libxslt.
  • -
  • Eliminate crash condition in iteration when text nodes are changed.
  • -
  • Passing 'None' to tostring() does not result in a segfault anymore, -but an AssertionError.
  • -
  • Some test fixes for Windows.
  • -
  • Raise XMLSyntaxError and XPathSyntaxError instead of plain python -syntax errors. This should be less confusing.
  • -
  • Fixed error with uncaught exception in Pyrex code.
  • -
  • Calling lxml.etree.fromstring('') throws XMLSyntaxError instead of a -segfault.
  • -
  • has_key() works on attrib. 'in' tests also work correctly on attrib.
  • -
  • INSTALL.txt was saying 2.2.16 instead of 2.6.16 as a supported -libxml2 version, as it should.
  • -
  • Passing a UTF-8 encoded string to the XML() function would fail; -fixed.
  • -
-
-
-
-

0.7 (2005-06-15)

-
-

Features added

-
    -
  • parameters (XPath expressions) can be passed to XSLT using keyword -parameters.
  • -
  • Simple XInclude support. Calling the xinclude() method on a tree -will process any XInclude statements in the document.
  • -
  • XMLSchema support. Use the XMLSchema class or the convenience -xmlschema() method on a tree to do XML Schema (XSD) validation.
  • -
  • Added convenience xslt() method on tree. This is less efficient -than the XSLT object, but makes it easier to write quick code.
  • -
  • Added convenience relaxng() method on tree. This is less efficient -than the RelaxNG object, but makes it easier to write quick code.
  • -
  • Make it possible to use XPathEvaluator with elements as well. The -XPathEvaluator in this case will retain the element so multiple -XPath queries can be made against one element efficiently. This -replaces the second argument to the .evaluate() method that existed -previously.
  • -
  • Allow registerNamespace() to be called on an XPathEvaluator, after -creation, to add additional namespaces. Also allow registerNamespaces(), -which does the same for a namespace dictionary.
  • -
  • Add 'prefix' attribute to element to be able to read prefix information. -This is entirely read-only.
  • -
  • It is possible to supply an extra nsmap keyword parameter to -the Element() and SubElement() constructors, which supplies a -prefix to namespace URI mapping. This will create namespace -prefix declarations on these elements and these prefixes will show up -in XML serialization.
  • -
-
-
-

Bugs fixed

-
    -
  • Killed yet another memory management related bug: trees created -using newDoc would not get a libxml2-level dictionary, which caused -problems when deallocating these documents later if they contained a -node that came from a document with a dictionary.
  • -
  • Moving namespaced elements between documents was problematic as -references to the original document would remain. This has been fixed -by applying xmlReconciliateNs() after each move operation.
  • -
  • Can pass None to 'dump()' without segfaults.
  • -
  • tostring() works properly for non-root elements as well.
  • -
  • Cleaned out the tostring() method so it should handle encoding -correctly.
  • -
  • Cleaned out the ElementTree.write() method so it should handle encoding -correctly. Writing directly to a file should also be faster, as there is no -need to go through a Python string in that case. Made sure the test cases -test both serializing to StringIO as well as serializing to a real file.
  • -
-
-
-
-

0.6 (2005-05-14)

-
-

Features added

-
    -
  • Changed setup.py so that library_dirs is also guessed. This should -help with compilation on the Mac OS X platform, where otherwise the -wrong library (shipping with the OS) could be picked up.
  • -
  • Tweaked setup.py so that it picks up the version from version.txt.
  • -
-
-
-

Bugs fixed

-
    -
  • Do the right thing when handling namespaced attributes.
  • -
  • fix bug where tostring() moved nodes into new documents. tostring() -had very nasty side-effects before this fix, sorry!
  • -
-
-
-
-

0.5.1 (2005-04-09)

-
    -
  • Python 2.2 compatibility fixes.
  • -
  • unicode fixes in Element() and Comment() as well as XML(); unicode -input wasn't properly being UTF-8 encoded.
  • -
-
-
-

0.5 (2005-04-08)

-

Initial public release.

-
-
- - - diff --git a/doc/html/changes-4.6.4.html b/doc/html/changes-4.6.4.html new file mode 100644 index 0000000..d694b38 --- /dev/null +++ b/doc/html/changes-4.6.4.html @@ -0,0 +1,3724 @@ + + + + + + +lxml changelog + + + +
+

lxml changelog

+ +
+

4.6.4 (2021-11-01)

+
+

Features added

+
    +
  • GH#317: A new property system_url was added to DTD entities. +Patch by Thirdegree.
  • +
  • GH#314: The STATIC_* variables in setup.py can now be passed via env vars. +Patch by Isaac Jurado.
  • +
+
+
+
+

4.6.3 (2021-03-21)

+
+

Bugs fixed

+
    +
  • A vulnerability (CVE-2021-28957) was discovered in the HTML Cleaner by Kevin Chung, +which allowed JavaScript to pass through. The cleaner now removes the HTML5 +formaction attribute.
  • +
+
+
+
+

4.6.2 (2020-11-26)

+
+

Bugs fixed

+
    +
  • A vulnerability (CVE-2020-27783) was discovered in the HTML Cleaner by Yaniv Nizry, +which allowed JavaScript to pass through. The cleaner now removes more sneaky +"style" content.
  • +
+
+
+
+

4.6.1 (2020-10-18)

+
+

Bugs fixed

+
    +
  • A vulnerability was discovered in the HTML Cleaner by Yaniv Nizry, which allowed +JavaScript to pass through. The cleaner now removes more sneaky "style" content.
  • +
+
+
+
+

4.6.0 (2020-10-17)

+
+

Features added

+
    +
  • GH#310: lxml.html.InputGetter supports __len__() to count the number of input fields. +Patch by Aidan Woolley.
  • +
  • lxml.html.InputGetter has a new .items() method to ease processing all input fields.
  • +
  • lxml.html.InputGetter.keys() now returns the field names in document order.
  • +
  • GH-309: The API documentation is now generated using sphinx-apidoc. +Patch by Chris Mayo.
  • +
+
+
+

Bugs fixed

+
    +
  • LP#1869455: C14N 2.0 serialisation failed for unprefixed attributes +when a default namespace was defined.
  • +
  • TreeBuilder.close() raised AssertionError in some error cases where it +should have raised XMLSyntaxError. It now raises a combined exception to +keep up backwards compatibility, while switching to XMLSyntaxError as an +interface.
  • +
+
+
+
+

4.5.2 (2020-07-09)

+
+

Bugs fixed

+
    +
  • Cleaner() now validates that only known configuration options can be set.
  • +
  • LP#1882606: Cleaner.clean_html() discarded comments and PIs regardless of the +corresponding configuration option, if remove_unknown_tags was set.
  • +
  • LP#1880251: Instead of globally overwriting the document loader in libxml2, lxml now +sets it per parser run, which improves the interoperability with other users of libxml2 +such as libxmlsec.
  • +
  • LP#1881960: Fix build in CPython 3.10 by using Cython 0.29.21.
  • +
  • The setup options "--with-xml2-config" and "--with-xslt-config" were accidentally renamed +to "--xml2-config" and "--xslt-config" in 4.5.1 and are now available again.
  • +
+
+
+
+

4.5.1 (2020-05-19)

+
+

Bugs fixed

+
    +
  • LP#1570388: Fix failures when serialising documents larger than 2GB in some cases.
  • +
  • LP#1865141, GH#298: QName values were not accepted by the el.iter() method. +Patch by xmo-odoo.
  • +
  • LP#1863413, GH#297: The build failed to detect libraries on Linux that are only +configured via pkg-config. +Patch by Hugh McMaster.
  • +
+
+
+
+

4.5.0 (2020-01-29)

+
+

Features added

+
    +
  • A new function indent() was added to insert tail whitespace for pretty-printing +an XML tree.
  • +
+
+
+

Bugs fixed

+
    +
  • LP#1857794: Tail text of nodes that get removed from a document using item +deletion disappeared silently instead of sticking with the node that was removed.
  • +
+
+
+

Other changes

+
    +
  • MacOS builds are 64-bit-only by default. +Set CFLAGS and LDFLAGS explicitly to override it.
  • +
  • Linux/MacOS Binary wheels now use libxml2 2.9.10 and libxslt 1.1.34.
  • +
  • LP#1840234: The package version number is now available as lxml.__version__.
  • +
+
+
+
+

4.4.3 (2020-01-28)

+
+

Bugs fixed

+
    +
  • LP#1844674: itertext() was missing tail text of comments and PIs since 4.4.0.
  • +
+
+
+
+

4.4.2 (2019-11-25)

+
+

Bugs fixed

+
    +
  • LP#1835708: ElementInclude incorrectly rejected repeated non-recursive +includes as recursive. +Patch by Rainer Hausdorf.
  • +
+
+
+
+

4.4.1 (2019-08-11)

+
+

Bugs fixed

+
    +
  • LP#1838252: The order of an OrderedDict was lost in 4.4.0 when passing it as +attrib mapping during element creation.
  • +
  • LP#1838521: The package metadata now lists the supported Python versions.
  • +
+
+
+
+

4.4.0 (2019-07-27)

+
+

Features added

+
    +
  • Element.clear() accepts a new keyword argument keep_tail=True to clear +everything but the tail text. This is helpful in some document-style use cases +and for clearing the current element in iterparse() and pull parsing.
  • +
  • When creating attributes or namespaces from a dict in Python 3.6+, lxml now +preserves the original insertion order of that dict, instead of always sorting +the items by name. A similar change was made for ElementTree in CPython 3.8. +See https://bugs.python.org/issue34160
  • +
  • Integer elements in lxml.objectify implement the __index__() special method.
  • +
  • GH#269: Read-only elements in XSLT were missing the nsmap property. +Original patch by Jan Pazdziora.
  • +
  • ElementInclude can now restrict the maximum inclusion depth via a max_depth +argument to prevent content explosion. It is limited to 6 by default.
  • +
  • The target object of the XMLParser can have start_ns() and end_ns() +callback methods to listen to namespace declarations.
  • +
  • The TreeBuilder has new arguments comment_factory and pi_factory to +pass factories for creating comments and processing instructions, as well as +flag arguments insert_comments and insert_pis to discard them from the +tree when set to false.
  • +
  • A C14N 2.0 implementation was added as +etree.canonicalize(), a corresponding C14NWriterTarget class, and +a c14n2 serialisation method.
  • +
+
+
+

Bugs fixed

+
    +
  • When writing to file paths that contain the URL escape character '%', the file +path could wrongly be mangled by URL unescaping and thus write to a different +file or directory. Code that writes to file paths that are provided by untrusted +sources, but that must work with previous versions of lxml, should best either +reject paths that contain '%' characters, or otherwise make sure that the path +does not contain maliciously injected '%XX' URL hex escapes for paths like '../'.
  • +
  • Assigning to Element child slices with negative step could insert the slice at +the wrong position, starting too far on the left.
  • +
  • Assigning to Element child slices with overly large step size could take very +long, regardless of the length of the actual slice.
  • +
  • Assigning to Element child slices of the wrong size could sometimes fail to +raise a ValueError (like a list assignment would) and instead assign outside +of the original slice bounds or leave parts of it unreplaced.
  • +
  • The comment and pi events in iterwalk() were never triggered, and +instead, comments and processing instructions in the tree were reported as +start elements. Also, when walking an ElementTree (as opposed to its root +element), comments and PIs outside of the root element are now reported.
  • +
  • LP#1827833: The RelaxNG compact syntax support was broken with recent versions +of rnc2rng.
  • +
  • LP#1758553: The HTML elements source and track were added to the list +of empty tags in lxml.html.defs.
  • +
  • Registering a prefix other than "xml" for the XML namespace is now rejected.
  • +
  • Failing to write XSLT output to a file could raise a misleading exception. +It now raises IOError.
  • +
+
+
+

Other changes

+
    +
  • Support for Python 3.4 was removed.
  • +
  • When using Element.find*() with prefix-namespace mappings, the empty string +is now accepted to define a default namespace, in addition to the previously +supported None prefix. Empty strings are more convenient since they keep +all prefix keys in a namespace dict strings, which simplifies sorting etc.
  • +
  • The ElementTree.write_c14n() method has been deprecated in favour of the +long preferred ElementTree.write(f, method="c14n"). It will be removed +in a future release.
  • +
+
+
+
+

4.3.5 (2019-07-27)

+
    +
  • Rebuilt with Cython 0.29.13 to support Python 3.8.
  • +
+
+
+

4.3.4 (2019-06-10)

+
    +
  • Rebuilt with Cython 0.29.10 to support Python 3.8.
  • +
+
+
+

4.3.3 (2019-03-26)

+
+

Bugs fixed

+
    +
  • Fix leak of output buffer and unclosed files in _XSLTResultTree.write_output().
  • +
+
+
+
+

4.3.2 (2019-02-29)

+
+

Bugs fixed

+
    +
  • Crash in 4.3.1 when appending a child subtree with certain text nodes.
  • +
+
+
+

Other changes

+
    +
  • Built with Cython 0.29.6.
  • +
+
+
+
+

4.3.1 (2019-02-08)

+
+

Bugs fixed

+
    +
  • LP#1814522: Crash when appending a child subtree that contains unsubstituted +entity references.
  • +
+
+
+

Other changes

+
    +
  • Built with Cython 0.29.5.
  • +
+
+
+
+

4.3.0 (2019-01-04)

+
+

Features added

+
    +
  • The module lxml.sax is compiled using Cython in order to speed it up.
  • +
  • GH#267: lxml.sax.ElementTreeProducer now preserves the namespace prefixes. +If two prefixes point to the same URI, the first prefix in alphabetical order +is used. Patch by Lennart Regebro.
  • +
  • Updated ISO-Schematron implementation to 2013 version (now MIT licensed) +and the corresponding schema to the 2016 version (with optional "properties").
  • +
+
+
+

Other changes

+
    +
  • GH#270, GH#271: Support for Python 2.6 and 3.3 was removed. +Patch by hugovk.
  • +
  • The minimum dependency versions were raised to libxml2 2.9.2 and libxslt 1.1.27, +which were released in 2014 and 2012 respectively.
  • +
  • Built with Cython 0.29.2.
  • +
+
+
+
+

4.2.6 (2019-01-02)

+
+

Bugs fixed

+
    +
  • LP#1799755: Fix a DeprecationWarning in Py3.7+.
  • +
  • Import warnings in Python 3.6+ were resolved.
  • +
+
+
+
+

4.2.5 (2018-09-09)

+
+

Bugs fixed

+
    +
  • Javascript URLs that used URL escaping were not removed by the HTML cleaner. +Security problem found by Omar Eissa. (CVE-2018-19787)
  • +
+
+
+
+

4.2.4 (2018-08-03)

+
+

Features added

+
    +
  • GH#259: Allow using pkg-config for build configuration. +Patch by Patrick Griffis.
  • +
+
+
+

Bugs fixed

+
    +
  • LP#1773749, GH#268: Crash when moving an element to another document with +Element.insert(). +Patch by Alexander Weggerle.
  • +
+
+
+
+

4.2.3 (2018-06-27)

+
+

Bugs fixed

+
    +
  • Reverted GH#265: lxml links against zlib as a shared library again.
  • +
+
+
+
+

4.2.2 (2018-06-22)

+
+

Bugs fixed

+
    +
  • GH#266: Fix sporadic crash during GC when parse-time schema validation is used +and the parser participates in a reference cycle. +Original patch by Julien Greard.
  • +
  • GH#265: lxml no longer links against zlib as a shared library, only on static builds. +Patch by Nehal J Wani.
  • +
+
+
+
+

4.2.1 (2018-03-21)

+
+

Bugs fixed

+
    +
  • LP#1755825: iterwalk() failed to return the 'start' event for the initial +element if a tag selector is used.
  • +
  • LP#1756314: Failure to import 4.2.0 into PyPy due to a missing library symbol.
  • +
  • LP#1727864, GH#258: Add "-isysroot" linker option on MacOS as needed by XCode 9.
  • +
+
+
+
+

4.2.0 (2018-03-13)

+
+

Features added

+
    +
  • GH#255: SelectElement.value returns more standard-compliant and +browser-like defaults for non-multi-selects. If no option is selected, the +value of the first option is returned (instead of None). If multiple options +are selected, the value of the last one is returned (instead of that of the +first one). If no options are present (not standard-compliant) +SelectElement.value still returns None.
  • +
  • GH#261: The HTMLParser() now supports the huge_tree option. +Patch by stranac.
  • +
+
+
+

Bugs fixed

+
    +
  • LP#1551797: Some XSLT messages were not captured by the transform error log.
  • +
  • LP#1737825: Crash at shutdown after an interrupted iterparse run with XMLSchema +validation.
  • +
+
+
+

Other changes

+
+
+
+

4.1.1 (2017-11-04)

+
    +
  • Rebuild with Cython 0.27.3 to improve support for Py3.7.
  • +
+
+
+

4.1.0 (2017-10-13)

+
+

Features added

+
    +
  • ElementPath supports text predicates for current node, like "[.='text']".
  • +
  • ElementPath allows spaces in predicates.
  • +
  • Custom Element classes and XPath functions can now be registered with a +decorator rather than explicit dict assignments.
  • +
  • Static Linux wheels are now built with link time optimisation (LTO) enabled. +This should have a beneficial impact on the overall performance by providing +a tighter compiler integration between lxml and libxml2/libxslt.
  • +
+
+
+

Bugs fixed

+
    +
  • LP#1722776: Requesting non-Element objects like comments from a document with +PythonElementClassLookup could fail with a TypeError.
  • +
+
+
+
+

4.0.0 (2017-09-17)

+
+

Features added

+
    +
  • The ElementPath implementation is now compiled using Cython, +which speeds up the .find*() methods quite significantly.
  • +
  • The modules lxml.builder, lxml.html.diff and lxml.html.clean +are also compiled using Cython in order to speed them up.
  • +
  • xmlfile() supports async coroutines using async with and await.
  • +
  • iterwalk() has a new method skip_subtree() that prevents walking into +the descendants of the current element.
  • +
  • RelaxNG.from_rnc_string() accepts a base_url argument to +allow relative resource lookups.
  • +
  • The XSLT result object has a new method .write_output(file) that serialises +output data into a file according to the <xsl:output> configuration.
  • +
+
+
+

Bugs fixed

+
    +
  • GH#251: HTML comments were handled incorrectly by the soupparser. +Patch by mozbugbox.

    +
  • +
  • LP#1654544: The html5parser no longer passes the useChardet option +if the input is a Unicode string, unless explicitly requested. When parsing +files, the default is to enable it when a URL or file path is passed (because +the file is then opened in binary mode), and to disable it when reading from +a file(-like) object.

    +

    Note: This is a backwards incompatible change of the default configuration. +If your code parses byte strings/streams and depends on character detection, +please pass the option guess_charset=True explicitly, which already worked +in older lxml versions.

    +
  • +
  • LP#1703810: etree.fromstring() failed to parse UTF-32 data with BOM.

    +
  • +
  • LP#1526522: Some RelaxNG errors were not reported in the error log.

    +
  • +
  • LP#1567526: Empty and plain text input raised a TypeError in soupparser.

    +
  • +
  • LP#1710429: Uninitialised variable usage in HTML diff.

    +
  • +
  • LP#1415643: The closing tags context manager in xmlfile() could continue +to output end tags even after writing failed with an exception.

    +
  • +
  • LP#1465357: xmlfile.write() now accepts and ignores None as input argument.

    +
  • +
  • Compilation under Py3.7-pre failed due to a modified function signature.

    +
  • +
+
+
+

Other changes

+
    +
  • The main module source files were renamed from lxml.*.pyx to plain +*.pyx (e.g. etree.pyx) to simplify their handling in the build +process. Care was taken to keep the old header files as fallbacks for +code that compiles against the public C-API of lxml, but it might still +be worth validating that third-party code does not notice this change.
  • +
+
+
+
+

3.8.0 (2017-06-03)

+
+

Features added

+
    +
  • ElementTree.write() has a new option doctype that writes out a +doctype string before the serialisation, in the same way as tostring().
  • +
  • GH#220: xmlfile allows switching output methods at an element level. +Patch by Burak Arslan.
  • +
  • LP#1595781, GH#240: added a PyCapsule Python API and C-level API for +passing externally generated libxml2 documents into lxml.
  • +
  • GH#244: error log entries have a new property path with an XPath +expression (if known, None otherwise) that points to the tree element +responsible for the error. Patch by Bob Kline.
  • +
  • The namespace prefix mapping that can be used in ElementPath now injects +a default namespace when passing a None prefix.
  • +
+
+
+

Bugs fixed

+
    +
  • GH#238: Character escapes were not hex-encoded in the xmlfile serialiser. +Patch by matejcik.
  • +
  • GH#229: fix for externally created XML documents. Patch by Theodore Dubois.
  • +
  • LP#1665241, GH#228: Form data handling in lxml.html no longer strips the +option values specified in form attributes but only the text values. +Patch by Ashish Kulkarni.
  • +
  • LP#1551797: revert previous fix for XSLT error logging as it breaks +multi-threaded XSLT processing.
  • +
  • LP#1673355, GH#233: fromstring() html5parser failed to parse byte strings.
  • +
+
+
+

Other changes

+
    +
  • The previously undocumented docstring option in ElementTree.write() +produces a deprecation warning and will eventually be removed.
  • +
+
+
+
+

3.7.4 (2017-??-??)

+
+

Bugs fixed

+
    +
  • LP#1551797: revert previous fix for XSLT error logging as it breaks +multi-threaded XSLT processing.
  • +
  • LP#1673355, GH#233: fromstring() html5parser failed to parse byte strings.
  • +
+
+
+
+

3.7.3 (2017-02-18)

+
+

Bugs fixed

+
    +
  • GH#218 was ineffective in Python 3.
  • +
  • GH#222: lxml.html.submit_form() failed in Python 3. +Patch by Jakub Wilk.
  • +
+
+
+
+

3.7.2 (2017-01-08)

+
    +
  • GH#220: xmlfile allows switching output methods at an element level. +Patch by Burak Arslan.
  • +
+
+

Bugs fixed

+
    +
  • Work around installation problems in recent Python 2.7 versions +due to FTP download failures.
  • +
  • GH#219: xmlfile.element() was not properly quoting attribute values. +Patch by Burak Arslan.
  • +
  • GH#218: xmlfile.element() was not properly escaping text content of +script/style tags. Patch by Burak Arslan.
  • +
+
+
+
+

3.7.1 (2016-12-23)

+
    +
  • No source changes, issued only to solve problems with the +binary packages released for 3.7.0.
  • +
+
+
+

3.7.0 (2016-12-10)

+
+

Features added

+
    +
  • GH#217: XMLSyntaxError now behaves more like its SyntaxError +baseclass. Patch by Philipp A.
  • +
  • GH#216: HTMLParser() now supports the same collect_ids parameter +as XMLParser(). Patch by Burak Arslan.
  • +
  • GH#210: Allow specifying a serialisation method in xmlfile.write(). +Patch by Burak Arslan.
  • +
  • GH#203: New option default_doctype in HTMLParser that allows +disabling the automatic doctype creation. Patch by Shadab Zafar.
  • +
  • GH#201: Calling the method .set('attrname') without value argument +(or None) on HTML elements creates an attribute without value that +serialises like <div attrname></div>. Patch by Daniel Holth.
  • +
  • GH#197: Ignore form input fields in form_values() when they are +marked as disabled in HTML. Patch by Kristian Klemon.
  • +
+
+
+

Bugs fixed

+
    +
  • GH#206: File name and line number were missing from XSLT error messages. +Patch by Marcus Brinkmann.
  • +
+
+
+

Other changes

+
    +
  • Log entries no longer allow anything but plain string objects as message text +and file name.
  • +
  • zlib is included in the list of statically built libraries.
  • +
+
+
+
+

3.6.4 (2016-08-20)

+ +
+
+

3.6.3 (2016-08-18)

+
    +
  • LP#1614603: change linker flags to build multi-linux wheels
  • +
+
+
+

3.6.2 (2016-08-18)

+
    +
  • LP#1614603: release without source changes to provide cleanly built Linux wheels
  • +
+
+
+

3.6.1 (2016-07-24)

+
+

Features added

+
    +
  • GH#180: Separate option inline_style for Cleaner that only removes style +attributes instead of all styles. Patch by Christian Pedersen.
  • +
  • GH#196: Windows build support for Python 3.5. Contribution by Maximilian Hils.
  • +
+
+
+

Bugs fixed

+
    +
  • GH#199: Exclude file fields from FormElement.form_values (as browsers do). +Patch by Tomas Divis.
  • +
  • GH#198, LP#1568167: Try to provide base URL from Resolver.resolve_string(). +Patch by Michael van Tellingen.
  • +
  • GH#191: More accurate float serialisation in objectify.FloatElement. +Patch by Holger Joukl.
  • +
  • LP#1551797: Repair XSLT error logging. Patch by Marcus Brinkmann.
  • +
+
+
+
+

3.6.0 (2016-03-17)

+
+

Features added

+
    +
  • GH#187: Now supports (only) version 5.x and later of PyPy. +Patch by Armin Rigo.
  • +
  • GH#181: Direct support for .rnc files in RelaxNG() if rnc2rng +is installed. Patch by Dirkjan Ochtman.
  • +
+
+
+

Bugs fixed

+
    +
  • GH#189: Static builds honour FTP proxy configurations when downloading +the external libs. Patch by Youhei Sakurai.
  • +
  • GH#186: Soupparser failed to process entities in Python 3.x. +Patch by Duncan Morris.
  • +
  • GH#185: Rare encoding related TypeError on import was fixed. +Patch by Petr Demin.
  • +
+
+
+
+

3.5.0 (2015-11-13)

+
+

Bugs fixed

+
    +
  • Unicode string results failed XPath queries in PyPy.
  • +
  • LP#1497051: HTML target parser failed to terminate on exceptions +and continued parsing instead.
  • +
  • Deprecated API usage in doctestcompare.
  • +
+
+
+
+

3.5.0b1 (2015-09-18)

+
+

Features added

+
    +
  • cleanup_namespaces() accepts a new argument keep_ns_prefixes +that does not remove definitions of the provided prefix-namespace +mapping from the tree.
  • +
  • cleanup_namespaces() accepts a new argument top_nsmap that +moves definitions of the provided prefix-namespace mapping to the +top of the tree.
  • +
  • LP#1490451: Element objects gained a cssselect() method as +known from lxml.html. Patch by Simon Sapin.
  • +
  • API functions and methods behave and look more like Python functions, +which allows introspection on them etc. One side effect to be aware of +is that the functions now bind as methods when assigned to a class +variable. A quick fix is to wrap them in staticmethod() (as for +normal Python functions).
  • +
  • ISO-Schematron support gained an option error_finder that allows +passing a filter function for picking validation errors from reports.
  • +
  • LP#1243600: Elements in lxml.html gained a classes property +that provides a set-like interface to the class attribute. +Original patch by masklinn.
  • +
  • LP#1341964: The soupparser now handles DOCTYPE declarations, comments +and processing instructions outside of the root element. +Patch by Olli Pottonen.
  • +
  • LP#1421512: The docinfo of a tree was made editable to allow +setting and removing the public ID and system ID of the DOCTYPE. +Patch by Olli Pottonen.
  • +
  • LP#1442427: More work-arounds for quirks and bugs in pypy and pypy3.
  • +
  • lxml.html.soupparser now uses BeautifulSoup version 4 instead +of version 3 if available.
  • +
+
+
+

Bugs fixed

+
    +
  • Memory errors that occur during tree adaptations (e.g. moving subtrees +to foreign documents) could leave the tree in a crash prone state.
  • +
  • Calling process_children() in an XSLT extension element without +an output_parent argument failed with a TypeError. +Fix by Jens Tröger.
  • +
  • GH#162: Image data in HTML data URLs is considered safe and +no longer removed by lxml.html.clean JavaScript cleaner.
  • +
  • GH#166: Static build could link libraries in wrong order.
  • +
  • GH#172: Rely a bit more on libxml2 for encoding detection rather than +rolling our own in some cases. Patch by Olli Pottonen.
  • +
  • GH#159: Validity checks for names and string content were tightened +to detect the use of illegal characters early. Patch by Olli Pottonen.
  • +
  • LP#1421921: Comments/PIs before the DOCTYPE declaration were not +serialised. Patch by Olli Pottonen.
  • +
  • LP#659367: Some HTML DOCTYPE declarations were not serialised. +Patch by Olli Pottonen.
  • +
  • LP#1238503: lxml.doctestcompare is now consistent with stdlib's doctest +in how it uses + and - to refer to unexpected and missing output.
  • +
  • Empty prefixes are explicitly rejected when a namespace mapping is used +with ElementPath to avoid hiding bugs in user code.
  • +
  • Several problems with PyPy were fixed by switching to Cython 0.23.
  • +
+
+
+
+

3.4.4 (2015-04-25)

+
+

Bugs fixed

+
    +
  • An ElementTree compatibility test added in lxml 3.4.3 that failed in +Python 3.4+ was removed again.
  • +
+
+
+
+

3.4.3 (2015-04-15)

+
+

Bugs fixed

+
    +
  • Expression cache in ElementPath was ignored. Fix by Changaco.
  • +
  • LP#1426868: Passing a default namespace and a prefixed namespace mapping +as nsmap into xmlfile.element() raised a TypeError.
  • +
  • LP#1421927: DOCTYPE system URLs were incorrectly quoted when containing +double quotes. Patch by Olli Pottonen.
  • +
  • LP#1419354: meta-redirect URLs were incorrectly processed by +iterlinks() if preceded by whitespace.
  • +
+
+
+
+

3.4.2 (2015-02-07)

+
+

Bugs fixed

+
    +
  • LP#1415907: Crash when creating an XMLSchema from a non-root element +of an XML document.
  • +
  • LP#1369362: HTML cleaning failed when hitting processing instructions +with pseudo-attributes.
  • +
  • CDATA() wrapped content was rejected for tail text.
  • +
  • CDATA sections were not serialised as tail text of the top-level element.
  • +
+
+
+
+

3.4.1 (2014-11-20)

+
+

Features added

+
    +
  • New htmlfile HTML generator to accompany the incremental xmlfile +serialisation API. Patch by Burak Arslan.
  • +
+
+
+

Bugs fixed

+
    +
  • lxml.sax.ElementTreeContentHandler did not initialise its superclass.
  • +
+
+
+
+

3.4.0 (2014-09-10)

+
+

Features added

+
    +
  • xmlfile(buffered=False) disables output buffering and flushes the +content after each API operation (starting/ending element blocks or writes). +A new method xf.flush() can alternatively be used to explicitly flush +the output.
  • +
  • lxml.html.document_fromstring has a new option ensure_head_body=True +which will add an empty head and/or body element to the result document if +missing.
  • +
  • lxml.html.iterlinks now returns links inside meta refresh tags.
  • +
  • New XMLParser option collect_ids=False to disable ID hash table +creation. This can substantially speed up parsing of documents with many +different IDs that are not used.
  • +
  • The parser uses per-document hash tables for XML IDs. This reduces the +load of the global parser dict and speeds up parsing for documents with +many different IDs.
  • +
  • ElementTree.getelementpath(element) returns a structural ElementPath +expression for the given element, which can be used for lookups later.
  • +
  • xmlfile() accepts a new argument close=True to close file(-like) +objects after writing to them. Before, xmlfile() only closed the file +if it had opened it internally.
  • +
  • Allow "bytearray" type for ASCII text input.
  • +
+
+
+

Bugs fixed

+
+
+

Other changes

+
    +
  • LP#400588: decoding errors have become hard errors even in recovery mode. +Previously, they could lead to an internal tree representation in a mixed +encoding state, which lead to very late errors or even silently incorrect +behaviour during tree traversal or serialisation.
  • +
  • Requires Python 2.6, 2.7, 3.2 or later. No longer supports +Python 2.4, 2.5 and 3.1, use lxml 3.3.x for those.
  • +
  • Requires libxml2 2.7.0 or later and libxslt 1.1.23 or later, +use lxml 3.3.x with older versions.
  • +
+
+
+
+

3.3.6 (2014-08-28)

+
+

Bugs fixed

+
    +
  • Prevent tree cycle creation when adding Elements as siblings.
  • +
  • LP#1361948: crash when deallocating Element siblings without parent.
  • +
  • LP#1354652: crash when traversing internally loaded documents in XSLT +extension functions.
  • +
+
+
+
+

3.3.5 (2014-04-18)

+
+

Bugs fixed

+
    +
  • HTML cleaning could fail to strip javascript links that mix control +characters into the link scheme.
  • +
+
+
+
+

3.3.4 (2014-04-03)

+
+

Features added

+
    +
  • Source line numbers above 65535 are available on Elements when +using libxml2 2.9 or later.
  • +
+
+
+

Bugs fixed

+
    +
  • lxml.html.fragment_fromstring() failed for bytes input in Py3.
  • +
+
+
+

Other changes

+
+
+
+

3.3.3 (2014-03-04)

+
+

Bugs fixed

+
    +
  • LP#1287118: Crash when using Element subtypes with __slots__.
  • +
+
+
+

Other changes

+
    +
  • The internal classes _LogEntry and _Attrib can no longer be +subclassed from Python code.
  • +
+
+
+
+

3.3.2 (2014-02-26)

+
+

Bugs fixed

+
    +
  • The properties resolvers and version, as well as the methods +set_element_class_lookup() and makeelement(), were lost from +iterparse objects in 3.3.0.
  • +
  • LP#1222132: instances of XMLSchema, Schematron and RelaxNG +did not clear their local error_log before running a validation.
  • +
  • LP#1238500: lxml.doctestcompare mixed up "expected" and "actual" in +attribute values.
  • +
  • Some file I/O tests were failing in MS-Windows due to non-portable temp +file usage. Initial patch by Gabi Davar.
  • +
  • LP#910014: duplicate IDs in a document were not reported by DTD validation.
  • +
  • LP#1185332: tostring(method="html") did not use HTML serialisation +semantics for trailing tail text. Initial patch by Sylvain Viollon.
  • +
  • LP#1281139: .attrib value of Comments lost its mutation methods +in 3.3.0. Even though it is empty and immutable, it should still +provide the same interface as that returned for Elements.
  • +
+
+
+
+

3.3.1 (2014-02-12)

+
+

Features added

+
+
+

Bugs fixed

+
    +
  • LP#1014290: HTML documents parsed with parser.feed() failed to find +elements during tag iteration.
  • +
  • LP#1273709: Building in PyPy failed due to missing support for +PyUnicode_Compare() and PyByteArray_*() in PyPy's C-API.
  • +
  • LP#1274413: Compilation in MSVC failed due to missing "stdint.h" standard +header file.
  • +
  • LP#1274118: iterparse() failed to parse BOM prefixed files.
  • +
+
+
+

Other changes

+
+
+
+

3.3.0 (2014-01-26)

+
+

Features added

+
+
+

Bugs fixed

+
    +
  • The heuristic that distinguishes file paths from URLs was tightened +to produce less false negatives.
  • +
+
+
+

Other changes

+
+
+
+

3.3.0beta5 (2014-01-18)

+
+

Features added

+
    +
  • The PEP 393 unicode parsing support gained a fallback for wchar strings +which might still be somewhat common on Windows systems.
  • +
+
+
+

Bugs fixed

+
    +
  • Several error handling problems were fixed throughout the code base that +could previously lead to exceptions being silently swallowed or not +properly reported.
  • +
  • The C-API function appendChild() is now deprecated as it does not +propagate exceptions (its return type is void). The new function +appendChildToElement() was added as a safe replacement.
  • +
  • Passing a string into fromstringlist() raises an exception instead of +parsing the string character by character.
  • +
+
+
+

Other changes

+
    +
  • Document cleanup code was simplified using the new GC features in +Cython 0.20.
  • +
+
+
+
+

3.3.0beta4 (2014-01-12)

+
+

Features added

+
+
+

Bugs fixed

+
    +
  • The (empty) value returned by the attrib property of Entity and Comment +objects was mutable.
  • +
  • Element class lookup wasn't available for the new pull parsers or when using +a custom parser target.
  • +
  • Setting Element attributes on instantiation with both the attrib argument +and keyword arguments could modify the mapping passed as attrib.
  • +
  • LP#1266171: DTDs instantiated from internal/external subsets (i.e. through +the docinfo property) lost their attribute declarations.
  • +
+
+
+

Other changes

+
    +
  • Built with Cython 0.20pre (gitrev 012ae82eb) to prepare support for +Python 3.4.
  • +
+
+
+
+

3.3.0beta3 (2014-01-02)

+
+

Features added

+
    +
  • Unicode string parsing was optimised for Python 3.3 (PEP 393).
  • +
+
+
+

Bugs fixed

+
    +
  • HTML parsing of Unicode strings could misdecode the input on some platforms.
  • +
  • Crash in xmlfile() when closing open elements out of order in an error case.
  • +
+
+
+

Other changes

+
+
+
+

3.3.0beta2 (2013-12-20)

+
+

Features added

+
    +
  • iterparse() supports the recover option.
  • +
+
+
+

Bugs fixed

+
    +
  • Crash in iterparse() for HTML parsing.
  • +
  • Crash in target parsing with attributes.
  • +
+
+
+

Other changes

+
    +
  • The safety check in the read-only tree implementation (e.g. used by +PythonElementClassLookup) raises a more appropriate ReferenceError +for illegal access after tree disposal instead of an AssertionError. +This should only impact test code that specifically checks the original +behaviour.
  • +
+
+
+
+

3.3.0beta1 (2013-12-12)

+
+

Features added

+
    +
  • New option handle_failures in make_links_absolute() and +resolve_base_href() (lxml.html) that enables ignoring or +discarding links that fail to parse as URLs.
  • +
  • New parser classes XMLPullParser and HTMLPullParser for +incremental parsing, as implemented for ElementTree in Python 3.4.
  • +
  • iterparse() enables recovery mode by default for HTML parsing +(html=True).
  • +
+
+
+

Bugs fixed

+
    +
  • LP#1255132: crash when trying to run validation over non-Element (e.g. +comment or PI).
  • +
  • Error messages in the log and in exception messages that originated +from libxml2 could accidentally be picked up from preceding warnings +instead of the actual error.
  • +
  • The ElementMaker in lxml.objectify did not accept a dict as +argument for adding attributes to the element it's building. This +works as in lxml.builder now.
  • +
  • LP#1228881: repr(XSLTAccessControl) failed in Python 3.
  • +
  • Raise ValueError when trying to append an Element to itself or +to one of its own descendants, instead of running into an infinite +loop.
  • +
  • LP#1206077: htmldiff discarded whitespace from the output.
  • +
  • Compressed plain-text serialisation to file-like objects was broken.
  • +
  • lxml.html.formfill: Fix textarea form filling. +The textarea used to be cleared before the new content was set, +which removed the name attribute.
  • +
+
+
+

Other changes

+
    +
  • Some basic API classes use freelists internally for faster +instantiation. This can speed up some iterparse() scenarios, +for example.
  • +
  • iterparse() was rewritten to use the new *PullParser +classes internally instead of being a parser itself.
  • +
+
+
+
+

3.2.5 (2014-01-02)

+
+

Features added

+
+
+

Bugs fixed

+
    +
  • Crash in xmlfile() when closing open elements out of order in an error case.
  • +
  • Crash in target parsing with attributes.
  • +
  • LP#1255132: crash when trying to run validation over non-Element (e.g. +comment or PI).
  • +
+
+
+

Other changes

+
+
+
+

3.2.4 (2013-11-07)

+
+

Features added

+
+
+

Bugs fixed

+
    +
  • Memory leak when creating an XPath evaluator in a thread.
  • +
  • LP#1228881: repr(XSLTAccessControl) failed in Python 3.
  • +
  • Raise ValueError when trying to append an Element to itself or +to one of its own descendants.
  • +
  • LP#1206077: htmldiff discarded whitespace from the output.
  • +
  • Compressed plain-text serialisation to file-like objects was broken.
  • +
+
+
+

Other changes

+
+
+
+

3.2.3 (2013-07-28)

+
+

Bugs fixed

+
    +
  • Fix support for Python 2.4 which was lost in 3.2.2.
  • +
+
+
+
+

3.2.2 (2013-07-28)

+
+

Features added

+
+
+

Bugs fixed

+
    +
  • LP#1185701: spurious XMLSyntaxError after finishing iterparse().
  • +
  • Crash in lxml.objectify during xsi annotation.
  • +
+
+
+

Other changes

+
    +
  • Return values of user provided element class lookup methods are now +validated against the type of the XML node they represent to prevent +API class mismatches.
  • +
+
+
+
+

3.2.1 (2013-05-11)

+
+

Features added

+
    +
  • The methods apply_templates() and process_children() of XSLT +extension elements have gained two new boolean options elements_only +and remove_blank_text that discard either all strings or whitespace-only +strings from the result list.
  • +
+
+
+

Bugs fixed

+
    +
  • When moving Elements to another tree, the namespace cleanup mechanism +no longer drops namespace prefixes from attributes for which it finds +a default namespace declaration, to prevent them from appearing as +unnamespaced attributes after serialisation.
  • +
  • Returning non-type objects from a custom class lookup method could lead +to a crash.
  • +
  • Instantiating and using subtypes of Comments and ProcessingInstructions +crashed.
  • +
+
+
+

Other changes

+
+
+
+

3.2.0 (2013-04-28)

+
+

Features added

+
+
+

Bugs fixed

+
    +
  • LP#690319: Leading whitespace could change the behaviour of the string +parsing functions in lxml.html.
  • +
  • LP#599318: The string parsing functions in lxml.html are more robust +in the face of uncommon HTML content like framesets or missing body tags. +Patch by Stefan Seelmann.
  • +
  • LP#712941: I/O errors while trying to access files with paths that contain +non-ASCII characters could raise UnicodeDecodeError instead of properly +reporting the IOError.
  • +
  • LP#673205: Parsing from in-memory strings disabled network access in the +default parser and made subsequent attempts to parse from a URL fail.
  • +
  • LP#971754: lxml.html.clean appends 'nofollow' to 'rel' attributes instead +of overwriting the current value.
  • +
  • LP#715687: lxml.html.clean no longer discards scripts that are explicitly +allowed by the user provided whitelist. Patch by Christine Koppelt.
  • +
+
+
+

Other changes

+
+
+
+

3.1.2 (2013-04-12)

+
+

Features added

+
+
+

Bugs fixed

+
    +
  • LP#1136509: Passing attributes through the namespace-unaware API of +the sax bridge (i.e. the handler.startElement() method) failed +with a TypeError. Patch by Mike Bayer.
  • +
  • LP#1123074: Fix serialisation error in XSLT output when converting +the result tree to a Unicode string.
  • +
  • GH#105: Replace illegal usage of xmlBufLength() in libxml2 2.9.0 +by properly exported API function xmlBufUse().
  • +
+
+
+

Other changes

+
+
+
+

3.1.1 (2013-03-29)

+
+

Features added

+
+
+

Bugs fixed

+
    +
  • LP#1160386: Write access to lxml.html.FormElement.fields raised +an AttributeError in Py3.
  • +
  • Illegal memory access during cleanup in incremental xmlfile writer.
  • +
+
+
+

Other changes

+
    +
  • The externally useless class lxml.etree._BaseParser was removed +from the module dict.
  • +
+
+
+
+

3.1.0 (2013-02-10)

+
+

Features added

+
    +
  • GH#89: lxml.html.clean allows overriding the set of attributes that it +considers 'safe'. Patch by Francis Devereux.
  • +
+
+
+

Bugs fixed

+
    +
  • LP#1104370: copy.copy(el.attrib) raised an exception. It now returns +a copy of the attributes as a plain Python dict.
  • +
  • GH#95: When used with namespace prefixes, the el.find*() methods +always used the first namespace mapping that was provided for each +path expression instead of using the one that was actually passed +in for the current run.
  • +
  • LP#1092521, GH#91: Fix undefined C symbol in Python runtimes compiled +without threading support. Patch by Ulrich Seidl.
  • +
+
+
+

Other changes

+
+
+
+

3.1beta1 (2012-12-21)

+
+

Features added

+
    +
  • New build-time option --with-unicode-strings for Python 2 that +makes the API always return Unicode strings for names and text +instead of byte strings for plain ASCII content.
  • +
  • New incremental XML file writing API etree.xmlfile().
  • +
  • E factory in lxml.objectify is callable to simplify the creation of +tags with non-identifier names without having to resort to getattr().
  • +
+
+
+

Bugs fixed

+
    +
  • When starting from a non-namespaced element in lxml.objectify, searching +for a child without explicitly specifying a namespace incorrectly found +namespaced elements with the requested local name, instead of restricting +the search to non-namespaced children.
  • +
  • GH#85: Deprecation warnings were fixed for Python 3.x.
  • +
  • GH#33: lxml.html.fromstring() failed to accept bytes input in Py3.
  • +
  • LP#1080792: Static build of libxml2 2.9.0 failed due to missing file.
  • +
+
+
+

Other changes

+
    +
  • The externally useless class _ObjectifyElementMakerCaller was +removed from the module API of lxml.objectify.
  • +
  • LP#1075622: lxml.builder is faster for adding text to elements with +many children. Patch by Anders Hammarquist.
  • +
+
+
+
+

3.0.2 (2012-12-14)

+
+

Features added

+
+
+

Bugs fixed

+
    +
  • Fix crash during interpreter shutdown by switching to Cython 0.17.3 for building.
  • +
+
+
+

Other changes

+
+
+
+

3.0.1 (2012-10-14)

+
+

Features added

+
+
+

Bugs fixed

+
    +
  • LP#1065924: Element proxies could disappear during garbage collection +in PyPy without proper cleanup.
  • +
  • GH#71: Failure to work with libxml2 2.6.x.
  • +
  • LP#1065139: static MacOS-X build failed in Py3.
  • +
+
+
+

Other changes

+
+
+
+

3.0 (2012-10-08)

+
+

Features added

+
+
+

Bugs fixed

+
    +
  • End-of-file handling was incorrect in iterparse() when reading from +a low-level C file stream and failed in libxml2 2.9.0 due to its +improved consistency checks.
  • +
+
+
+

Other changes

+
    +
  • The build no longer uses Cython by default unless the generated C files +are missing. To use Cython, pass the option "--with-cython". To ignore +the fatal build error when Cython is required but not available (e.g. to +run special setup.py commands that do not actually run a build), pass +"--without-cython".
  • +
+
+
+
+

3.0beta1 (2012-09-26)

+
+

Features added

+
    +
  • Python level access to (optional) libxml2 memory debugging features +to simplify debugging of memory leaks etc.
  • +
+
+
+

Bugs fixed

+
    +
  • Fix a memory leak in XPath by switching to Cython 0.17.1.
  • +
  • Some tests were adapted to work with PyPy.
  • +
+
+
+

Other changes

+
    +
  • The code was adapted to work with the upcoming libxml2 2.9.0 release.
  • +
+
+
+
+

3.0alpha2 (2012-08-23)

+
+

Features added

+
    +
  • The .iter() method of elements now accepts tag arguments like +"{*}name" to search for elements with a given local name in any +namespace. With this addition, all combinations of wildcards now work +as expected: +"{ns}name", "{}name", "{*}name", "{ns}*", "{}*" +and "{*}*". Note that "name" is equivalent to "{}name", +but "*" is "{*}*". +The same change applies to the .getiterator(), .itersiblings(), +.iterancestors(), .iterdescendants(), .iterchildren() +and .itertext() methods;the strip_attributes(), +strip_elements() and strip_tags() functions as well as the +iterparse() class. Patch by Simon Sapin.
  • +
  • C14N allows specifying the inclusive prefixes to be promoted +to top-level during exclusive serialisation.
  • +
+
+
+

Bugs fixed

+
    +
  • Passing long Unicode strings into the feed() parser interface +failed to read the entire string.
  • +
+
+
+

Other changes

+
+
+
+

3.0alpha1 (2012-07-31)

+
+

Features added

+
    +
  • Initial support for building in PyPy (through cpyext).
  • +
  • DTD objects gained an API that allows read access to their +declarations.
  • +
  • xpathgrep.py gained support for parsing line-by-line (e.g. +from grep output) and for surrounding the output with a new root +tag.
  • +
  • E-factory in lxml.builder accepts subtypes of known data +types (such as string subtypes) when building elements around them.
  • +
  • Tree iteration and iterparse() with a selective tag +argument supports passing a set of tags. Tree nodes will be +returned by the iterators if they match any of the tags.
  • +
+
+
+

Bugs fixed

+
    +
  • The .find*() methods in lxml.objectify no longer use XPath +internally, which makes them faster in many cases (especially when +short circuiting after a single or couple of elements) and fixes +some behavioural differences compared to lxml.etree. Note that +this means that they no longer support arbitrary XPath expressions +but only the subset that the ElementPath language supports. +The previous implementation was also redundant with the normal +XPath support, which can be used as a replacement.
  • +
  • el.find('*') could accidentally return a comment or processing +instruction that happened to be in the wrong spot. (Same for the +other .find*() methods.)
  • +
  • The error logging is less intrusive and avoids a global setup where +possible.
  • +
  • Fixed undefined names in html5lib parser.
  • +
  • xpathgrep.py did not work in Python 3.
  • +
  • Element.attrib.update() did not accept an attrib of +another Element as parameter.
  • +
  • For subtypes of ElementBase that make the .text or .tail +properties immutable (as in objectify, for example), inserting text +when creating Elements through the E-Factory feature of the class +constructor would fail with an exception, stating that the text +cannot be modified.
  • +
+
+
+

Other changes

+
    +
  • The code base was overhauled to properly use 'const' where the API +of libxml2 and libxslt requests it. This also has an impact on the +public C-API of lxml itself, as defined in etreepublic.pxd, as +well as the provided declarations in the lxml/includes/ directory. +Code that uses these declarations may have to be adapted. On the +plus side, this fixes several C compiler warnings, also for user +code, thus making it easier to spot real problems again.
  • +
  • The functionality of "lxml.cssselect" was moved into a separate PyPI +package called "cssselect". To continue using it, you must install +that package separately. The "lxml.cssselect" module is still +available and provides the same interface, provided the "cssselect" +package can be imported at runtime.
  • +
  • Element attributes passed in as an attrib dict or as keyword +arguments are now sorted by (namespaced) name before being created +to make their order predictable for serialisation and iteration. +Note that adding or deleting attributes afterwards does not take +that order into account, i.e. setting a new attribute appends it +after the existing ones.
  • +
  • Several classes that are for internal use only were removed +from the lxml.etree module dict: +_InputDocument, _ResolverRegistry, _ResolverContext, _BaseContext, +_ExsltRegExp, _IterparseContext, _TempStore, _ExceptionContext, +__ContentOnlyElement, _AttribIterator, _NamespaceRegistry, +_ClassNamespaceRegistry, _FunctionNamespaceRegistry, +_XPathFunctionNamespaceRegistry, _ParserDictionaryContext, +_FileReaderContext, _ParserContext, _PythonSaxParserTarget, +_TargetParserContext, _ReadOnlyProxy, _ReadOnlyPIProxy, +_ReadOnlyEntityProxy, _ReadOnlyElementProxy, _OpaqueNodeWrapper, +_OpaqueDocumentWrapper, _ModifyContentOnlyProxy, +_ModifyContentOnlyPIProxy, _ModifyContentOnlyEntityProxy, +_AppendOnlyElementProxy, _SaxParserContext, _FilelikeWriter, +_ParserSchemaValidationContext, _XPathContext, +_XSLTResolverContext, _XSLTContext, _XSLTQuotedStringParam
  • +
  • Several internal classes can no longer be inherited from: +_InputDocument, _ResolverRegistry, _ExsltRegExp, _ElementUnicodeResult, +_IterparseContext, _TempStore, _AttribIterator, _ClassNamespaceRegistry, +_XPathFunctionNamespaceRegistry, _ParserDictionaryContext, +_FileReaderContext, _PythonSaxParserTarget, _TargetParserContext, +_ReadOnlyPIProxy, _ReadOnlyEntityProxy, _OpaqueDocumentWrapper, +_ModifyContentOnlyPIProxy, _ModifyContentOnlyEntityProxy, +_AppendOnlyElementProxy, _FilelikeWriter, _ParserSchemaValidationContext, +_XPathContext, _XSLTResolverContext, _XSLTContext, _XSLTQuotedStringParam, +_XSLTResultTree, _XSLTProcessingInstruction
  • +
+
+
+
+

2.3.6 (2012-09-28)

+
+

Features added

+
+
+

Bugs fixed

+
    +
  • Passing long Unicode strings into the feed() parser interface +failed to read the entire string.
  • +
+
+
+

Other changes

+
+
+
+

2.3.5 (2012-07-31)

+
+

Features added

+
+
+

Bugs fixed

+
    +
  • Crash when merging text nodes in element.remove().
  • +
  • Crash in sax/target parser when reporting empty doctype.
  • +
+
+
+

Other changes

+
+
+
+

2.3.4 (2012-03-26)

+
+

Features added

+
+
+

Bugs fixed

+
    +
  • Crash when building an nsmap (Element property) with empty +namespace URIs.
  • +
  • Crash due to race condition when errors (or user messages) occur +during threaded XSLT processing.
  • +
  • XSLT stylesheet compilation could ignore compilation errors.
  • +
+
+
+

Other changes

+
+
+
+

2.3.3 (2012-01-04)

+
+

Features added

+
    +
  • lxml.html.tostring() gained new serialisation options +with_tail and doctype.
  • +
+
+
+

Bugs fixed

+
    +
  • Fixed a crash when using iterparse() for HTML parsing and +requesting start events.
  • +
  • Fixed parsing of more selectors in cssselect. Whitespace before +pseudo-elements and pseudo-classes is significant as it is a +descendant combinator. +"E :pseudo" should parse the same as "E *:pseudo", not "E:pseudo". +Patch by Simon Sapin.
  • +
  • lxml.html.diff no longer raises an exception when hitting +'img' tags without 'src' attribute.
  • +
+
+
+

Other changes

+
+
+
+

2.3.2 (2011-11-11)

+
+

Features added

+
    +
  • lxml.objectify.deannotate() has a new boolean option +cleanup_namespaces to remove the objectify namespace +declarations (and generally clean up the namespace declarations) +after removing the type annotations.
  • +
  • lxml.objectify gained its own SubElement() function as a +copy of etree.SubElement to avoid an otherwise redundant import +of lxml.etree on the user side.
  • +
+
+
+

Bugs fixed

+
    +
  • Fixed the "descendant" bug in cssselect a second time (after a first +fix in lxml 2.3.1). The previous change resulted in a serious +performance regression for the XPath based evaluation of the +translated expression. Note that this breaks the usage of some of +the generated XPath expressions as XSLT location paths that +previously worked in 2.3.1.
  • +
  • Fixed parsing of some selectors in cssselect. Whitespace after combinators +">", "+" and "~" is now correctly ignored. Previously it was parsed as +a descendant combinator. For example, "div> .foo" was parsed the same as +"div>* .foo" instead of "div>.foo". Patch by Simon Sapin.
  • +
+
+
+

Other changes

+
+
+
+

2.3.1 (2011-09-25)

+
+

Features added

+
    +
  • New option kill_tags in lxml.html.clean to remove specific +tags and their content (i.e. their whole subtree).
  • +
  • pi.get() and pi.attrib on processing instructions to parse +pseudo-attributes from the text content of processing instructions.
  • +
  • lxml.get_include() returns a list of include paths that can be +used to compile external C code against lxml.etree. This is +specifically required for statically linked lxml builds when code +needs to compile against the exact same header file versions as lxml +itself.
  • +
  • Resolver.resolve_file() takes an additional option +close_file that configures if the file(-like) object will be +closed after reading or not. By default, the file will be closed, +as the user is not expected to keep a reference to it.
  • +
+
+
+

Bugs fixed

+
    +
  • HTML cleaning didn't remove 'data:' links.
  • +
  • The html5lib parser integration now uses the 'official' +implementation in html5lib itself, which makes it work with newer +releases of the library.
  • +
  • In lxml.sax, endElementNS() could incorrectly reject a plain +tag name when the corresponding start event inferred the same plain +tag name to be in the default namespace.
  • +
  • When an open file-like object is passed into parse() or +iterparse(), the parser will no longer close it after use. This +reverts a change in lxml 2.3 where all files would be closed. It is +the users responsibility to properly close the file(-like) object, +also in error cases.
  • +
  • Assertion error in lxml.html.cleaner when discarding top-level elements.
  • +
  • In lxml.cssselect, use the xpath 'A//B' (short for +'A/descendant-or-self::node()/B') instead of 'A/descendant::B' for +the css descendant selector ('A B'). This makes a few edge cases +like "div *:last-child" consistent with the selector behavior in +WebKit and Firefox, and makes more css expressions valid location +paths (for use in xsl:template match).
  • +
  • In lxml.html, non-selected <option> tags no longer show up in the +collected form values.
  • +
  • Adding/removing <option> values to/from a multiple select form +field properly selects them and unselects them.
  • +
+
+
+

Other changes

+
    +
  • Static builds can specify the download directory with the +--download-dir option.
  • +
+
+
+
+

2.3 (2011-02-06)

+
+

Features added

+
    +
  • When looking for children, lxml.objectify takes '{}tag' as +meaning an empty namespace, as opposed to the parent namespace.
  • +
+
+
+

Bugs fixed

+
    +
  • When finished reading from a file-like object, the parser +immediately calls its .close() method.
  • +
  • When finished parsing, iterparse() immediately closes the input +file.
  • +
  • Work-around for libxml2 bug that can leave the HTML parser in a +non-functional state after parsing a severely broken document (fixed +in libxml2 2.7.8).
  • +
  • marque tag in HTML cleanup code is correctly named marquee.
  • +
+
+
+

Other changes

+
    +
  • Some public functions in the Cython-level C-API have more explicit +return types.
  • +
+
+
+
+

2.3beta1 (2010-09-06)

+
+

Features added

+
+
+

Bugs fixed

+
    +
  • Crash in newer libxml2 versions when moving elements between +documents that had attributes on replaced XInclude nodes.
  • +
  • XMLID() function was missing the optional parser and +base_url parameters.
  • +
  • Searching for wildcard tags in iterparse() was broken in Py3.
  • +
  • lxml.html.open_in_browser() didn't work in Python 3 due to the +use of os.tempnam. It now takes an optional 'encoding' parameter.
  • +
+
+
+

Other changes

+
+
+
+

2.3alpha2 (2010-07-24)

+
+

Features added

+
+
+

Bugs fixed

+
    +
  • Crash in XSLT when generating text-only result documents with a +stylesheet created in a different thread.
  • +
+
+
+

Other changes

+
    +
  • repr() of Element objects shows the hex ID with leading 0x +(following ElementTree 1.3).
  • +
+
+
+
+

2.3alpha1 (2010-06-19)

+
+

Features added

+
    +
  • Keyword argument namespaces in lxml.cssselect.CSSSelector() +to pass a prefix-to-namespace mapping for the selector.
  • +
  • New function lxml.etree.register_namespace(prefix, uri) that +globally registers a namespace prefix for a namespace that newly +created Elements in that namespace will use automatically. Follows +ElementTree 1.3.
  • +
  • Support 'unicode' string name as encoding parameter in +tostring(), following ElementTree 1.3.
  • +
  • Support 'c14n' serialisation method in ElementTree.write() and +tostring(), following ElementTree 1.3.
  • +
  • The ElementPath expression syntax (el.find*()) was extended to +match the upcoming ElementTree 1.3 that will ship in the standard +library of Python 3.2/2.7. This includes extended support for +predicates as well as namespace prefixes (as known from XPath).
  • +
  • During regular XPath evaluation, various ESXLT functions are +available within their namespace when using libxslt 1.1.26 or later.
  • +
  • Support passing a readily configured logger instance into +PyErrorLog, instead of a logger name.
  • +
  • On serialisation, the new doctype parameter can be used to +override the DOCTYPE (internal subset) of the document.
  • +
  • New parameter output_parent to XSLTExtension.apply_templates() +to append the resulting content directly to an output element.
  • +
  • XSLTExtension.process_children() to process the content of the +XSLT extension element itself.
  • +
  • ISO-Schematron support based on the de-facto Schematron reference +'skeleton implementation'.
  • +
  • XSLT objects now take XPath object as __call__ stylesheet +parameters.
  • +
  • Enable path caching in ElementPath (el.find*()) to avoid parsing +overhead.
  • +
  • Setting the value of a namespaced attribute always uses a prefixed +namespace instead of the default namespace even if both declare the +same namespace URI. This avoids serialisation problems when an +attribute from a default namespace is set on an element from a +different namespace.
  • +
  • XSLT extension elements: support for XSLT context nodes other than +elements: document root, comments, processing instructions.
  • +
  • Support for strings (in addition to Elements) in node-sets returned +by extension functions.
  • +
  • Forms that lack an action attribute default to the base URL of +the document on submit.
  • +
  • XPath attribute result strings have an attrname property.
  • +
  • Namespace URIs get validated against RFC 3986 at the API level +(required by the XML namespace specification).
  • +
  • Target parsers show their target object in the .target property +(compatible with ElementTree).
  • +
+
+
+

Bugs fixed

+
    +
  • API is hardened against invalid proxy instances to prevent crashes +due to incorrectly instantiated Element instances.
  • +
  • Prevent crash when instantiating CommentBase and friends.
  • +
  • Export ElementTree compatible XML parser class as +XMLTreeBuilder, as it is called in ET 1.2.
  • +
  • ObjectifiedDataElements in lxml.objectify were not hashable. They +now use the hash value of the underlying Python value (string, +number, etc.) to which they compare equal.
  • +
  • Parsing broken fragments in lxml.html could fail if the fragment +contained an orphaned closing '</div>' tag.
  • +
  • Using XSLT extension elements around the root of the output document +crashed.
  • +
  • lxml.cssselect did not distinguish between x[attr="val"] and +x [attr="val"] (with a space). The latter now matches the +attribute independent of the element.
  • +
  • Rewriting multiple links inside of HTML text content could end up +replacing unrelated content as replacements could impact the +reported position of subsequent matches. Modifications are now +simplified by letting the iterlinks() generator in lxml.html +return links in reversed order if they appear inside the same text +node. Thus, replacements and link-internal modifications no longer +change the position of links reported afterwards.
  • +
  • The .value attribute of textarea elements in lxml.html did +not represent the complete raw value (including child tags etc.). It +now serialises the complete content on read and replaces the +complete content by a string on write.
  • +
  • Target parser didn't call .close() on the target object if +parsing failed. Now it is guaranteed that .close() will be +called after parsing, regardless of the outcome.
  • +
+
+
+

Other changes

+
    +
  • Official support for Python 3.1.2 and later.
  • +
  • Static MS Windows builds can now download their dependencies +themselves.
  • +
  • Element.attrib no longer uses a cyclic reference back to its +Element object. It therefore no longer requires the garbage +collector to clean up.
  • +
  • Static builds include libiconv, in addition to libxml2 and libxslt.
  • +
+
+
+
+

2.2.8 (2010-09-02)

+
+

Bugs fixed

+
    +
  • Crash in newer libxml2 versions when moving elements between +documents that had attributes on replaced XInclude nodes.
  • +
  • Import fix for urljoin in Python 3.1+.
  • +
+
+
+
+

2.2.7 (2010-07-24)

+
+

Bugs fixed

+
    +
  • Crash in XSLT when generating text-only result documents with a +stylesheet created in a different thread.
  • +
+
+
+
+

2.2.6 (2010-03-02)

+
+

Bugs fixed

+
    +
  • Fixed several Python 3 regressions by building with Cython 0.11.3.
  • +
+
+
+
+

2.2.5 (2010-02-28)

+
+

Features added

+
    +
  • Support for running XSLT extension elements on the input root node +(e.g. in a template matching on "/").
  • +
+
+
+

Bugs fixed

+
    +
  • Crash in XPath evaluation when reading smart strings from a document +other than the original context document.
  • +
  • Support recent versions of html5lib by not requiring its +XHTMLParser in htmlparser.py anymore.
  • +
  • Manually instantiating the custom element classes in +lxml.objectify could crash.
  • +
  • Invalid XML text characters were not rejected by the API when they +appeared in unicode strings directly after non-ASCII characters.
  • +
  • lxml.html.open_http_urllib() did not work in Python 3.
  • +
  • The functions strip_tags() and strip_elements() in +lxml.etree did not remove all occurrences of a tag in all cases.
  • +
  • Crash in XSLT extension elements when the XSLT context node is not +an element.
  • +
+
+
+
+

2.2.4 (2009-11-11)

+
+

Bugs fixed

+
    +
  • Static build of libxml2/libxslt was broken.
  • +
+
+
+
+

2.2.3 (2009-10-30)

+
+

Features added

+
+
+

Bugs fixed

+
    +
  • The resolve_entities option did not work in the incremental feed +parser.
  • +
  • Looking up and deleting attributes without a namespace could hit a +namespaced attribute of the same name instead.
  • +
  • Late errors during calls to SubElement() (e.g. attribute related +ones) could leave a partially initialised element in the tree.
  • +
  • Modifying trees that contain parsed entity references could result +in an infinite loop.
  • +
  • ObjectifiedElement.__setattr__ created an empty-string child element when the +attribute value was rejected as a non-unicode/non-ascii string
  • +
  • Syntax errors in lxml.cssselect could result in misleading error +messages.
  • +
  • Invalid syntax in CSS expressions could lead to an infinite loop in +the parser of lxml.cssselect.
  • +
  • CSS special character escapes were not properly handled in +lxml.cssselect.
  • +
  • CSS Unicode escapes were not properly decoded in lxml.cssselect.
  • +
  • Select options in HTML forms that had no explicit value +attribute were not handled correctly. The HTML standard dictates +that their value is defined by their text content. This is now +supported by lxml.html.
  • +
  • XPath raised a TypeError when finding CDATA sections. This is now +fully supported.
  • +
  • Calling help(lxml.objectify) didn't work at the prompt.
  • +
  • The ElementMaker in lxml.objectify no longer defines the default +namespaces when annotation is disabled.
  • +
  • Feed parser failed to honour the 'recover' option on parse errors.
  • +
  • Diverting the error logging to Python's logging system was broken.
  • +
+
+
+

Other changes

+
+
+
+

2.2.2 (2009-06-21)

+
+

Features added

+
    +
  • New helper functions strip_attributes(), strip_elements(), +strip_tags() in lxml.etree to remove attributes/subtrees/tags +from a subtree.
  • +
+
+
+

Bugs fixed

+
    +
  • Namespace cleanup on subtree insertions could result in missing +namespace declarations (and potentially crashes) if the element +defining a namespace was deleted and the namespace was not used by +the top element of the inserted subtree but only in deeper subtrees.
  • +
  • Raising an exception from a parser target callback didn't always +terminate the parser.
  • +
  • Only {true, false, 1, 0} are accepted as the lexical representation for +BoolElement ({True, False, T, F, t, f} not any more), restoring lxml <= 2.0 +behaviour.
  • +
+
+
+

Other changes

+
+
+
+

2.2.1 (2009-06-02)

+
+

Features added

+
    +
  • Injecting default attributes into a document during XML Schema +validation (also at parse time).
  • +
  • Pass huge_tree parser option to disable parser security +restrictions imposed by libxml2 2.7.
  • +
+
+
+

Bugs fixed

+
    +
  • The script for statically building libxml2 and libxslt didn't work +in Py3.
  • +
  • XMLSchema() also passes invalid schema documents on to libxml2 +for parsing (which could lead to a crash before release 2.6.24).
  • +
+
+
+

Other changes

+
+
+
+

2.2 (2009-03-21)

+
+

Features added

+
    +
  • Support for standalone flag in XML declaration through +tree.docinfo.standalone and by passing standalone=True/False +on serialisation.
  • +
+
+
+

Bugs fixed

+
    +
  • Crash when parsing an XML Schema with external imports from a +filename.
  • +
+
+
+
+

2.2beta4 (2009-02-27)

+
+

Features added

+
    +
  • Support strings and instantiable Element classes as child arguments +to the constructor of custom Element classes.
  • +
  • GZip compression support for serialisation to files and file-like +objects.
  • +
+
+
+

Bugs fixed

+
    +
  • Deep-copying an ElementTree copied neither its sibling PIs and +comments nor its internal/external DTD subsets.
  • +
  • Soupparser failed on broken attributes without values.
  • +
  • Crash in XSLT when overwriting an already defined attribute using +xsl:attribute.
  • +
  • Crash bug in exception handling code under Python 3. This was due +to a problem in Cython, not lxml itself.
  • +
  • lxml.html.FormElement._name() failed for non top-level forms.
  • +
  • TAG special attribute in constructor of custom Element classes +was evaluated incorrectly.
  • +
+
+
+

Other changes

+
    +
  • Official support for Python 3.0.1.
  • +
  • Element.findtext() now returns an empty string instead of None +for Elements without text content.
  • +
+
+
+
+

2.2beta3 (2009-02-17)

+
+

Features added

+
    +
  • XSLT.strparam() class method to wrap quoted string parameters +that require escaping.
  • +
+
+
+

Bugs fixed

+
    +
  • Memory leak in XPath evaluators.
  • +
  • Crash when parsing indented XML in one thread and merging it with +other documents parsed in another thread.
  • +
  • Setting the base attribute in lxml.objectify from a unicode +string failed.
  • +
  • Fixes following changes in Python 3.0.1.
  • +
  • Minor fixes for Python 3.
  • +
+
+
+

Other changes

+
    +
  • The global error log (which is copied into the exception log) is now +local to a thread, which fixes some race conditions.
  • +
  • More robust error handling on serialisation.
  • +
+
+
+
+

2.2beta2 (2009-01-25)

+
+

Bugs fixed

+
    +
  • Potential memory leak on exception handling. This was due to a +problem in Cython, not lxml itself.
  • +
  • iter_links (and related link-rewriting functions) in +lxml.html would interpret CSS like url("link") incorrectly +(treating the quotation marks as part of the link).
  • +
  • Failing import on systems that have an io module.
  • +
+
+
+
+

2.1.5 (2009-01-06)

+
+

Bugs fixed

+
    +
  • Potential memory leak on exception handling. This was due to a +problem in Cython, not lxml itself.
  • +
  • Failing import on systems that have an io module.
  • +
+
+
+
+

2.2beta1 (2008-12-12)

+
+

Features added

+
    +
  • Allow lxml.html.diff.htmldiff to accept Element objects, not +just HTML strings.
  • +
+
+
+

Bugs fixed

+
    +
  • Crash when using an XPath evaluator in multiple threads.
  • +
  • Fixed missing whitespace before Link:... in lxml.html.diff.
  • +
+
+
+

Other changes

+
    +
  • Export lxml.html.parse.
  • +
+
+
+
+

2.1.4 (2008-12-12)

+
+

Bugs fixed

+
    +
  • Crash when using an XPath evaluator in multiple threads.
  • +
+
+
+
+

2.0.11 (2008-12-12)

+
+

Bugs fixed

+
    +
  • Crash when using an XPath evaluator in multiple threads.
  • +
+
+
+
+

2.2alpha1 (2008-11-23)

+
+

Features added

+
    +
  • Support for XSLT result tree fragments in XPath/XSLT extension +functions.
  • +
  • QName objects have new properties namespace and localname.
  • +
  • New options for exclusive C14N and C14N without comments.
  • +
  • Instantiating a custom Element classes creates a new Element.
  • +
+
+
+

Bugs fixed

+
    +
  • XSLT didn't inherit the parse options of the input document.
  • +
  • 0-bytes could slip through the API when used inside of Unicode +strings.
  • +
  • With lxml.html.clean.autolink, links with balanced parenthesis, +that end in a parenthesis, will be linked in their entirety (typical +with Wikipedia links).
  • +
+
+
+

Other changes

+
+
+
+

2.1.3 (2008-11-17)

+
+

Features added

+
+
+

Bugs fixed

+
    +
  • Ref-count leaks when lxml enters a try-except statement while an +outside exception lives in sys.exc_*(). This was due to a problem in +Cython, not lxml itself.
  • +
  • Parser Unicode decoding errors could get swallowed by other +exceptions.
  • +
  • Name/import errors in some Python modules.
  • +
  • Internal DTD subsets that did not specify a system or public ID were +not serialised and did not appear in the docinfo property of +ElementTrees.
  • +
  • Fix a pre-Py3k warning when parsing from a gzip file in Py2.6.
  • +
  • Test suite fixes for libxml2 2.7.
  • +
  • Resolver.resolve_string() did not work for non-ASCII byte strings.
  • +
  • Resolver.resolve_file() was broken.
  • +
  • Overriding the parser encoding didn't work for many encodings.
  • +
+
+
+

Other changes

+
+
+
+

2.0.10 (2008-11-17)

+
+

Bugs fixed

+
    +
  • Ref-count leaks when lxml enters a try-except statement while an +outside exception lives in sys.exc_*(). This was due to a problem in +Cython, not lxml itself.
  • +
+
+
+
+

2.1.2 (2008-09-05)

+
+

Features added

+
    +
  • lxml.etree now tries to find the absolute path name of files when +parsing from a file-like object. This helps custom resolvers when +resolving relative URLs, as lixbml2 can prepend them with the path +of the source document.
  • +
+
+
+

Bugs fixed

+
    +
  • Memory problem when passing documents between threads.
  • +
  • Target parser did not honour the recover option and raised an +exception instead of calling .close() on the target.
  • +
+
+
+

Other changes

+
+
+
+

2.0.9 (2008-09-05)

+
+

Bugs fixed

+
    +
  • Memory problem when passing documents between threads.
  • +
  • Target parser did not honour the recover option and raised an +exception instead of calling .close() on the target.
  • +
+
+
+
+

2.1.1 (2008-07-24)

+
+

Features added

+
+
+

Bugs fixed

+
    +
  • Crash when parsing XSLT stylesheets in a thread and using them in +another.
  • +
  • Encoding problem when including text with ElementInclude under +Python 3.
  • +
+
+
+

Other changes

+
+
+
+

2.0.8 (2008-07-24)

+
+

Features added

+
    +
  • lxml.html.rewrite_links() strips links to work around documents +with whitespace in URL attributes.
  • +
+
+
+

Bugs fixed

+
    +
  • Crash when parsing XSLT stylesheets in a thread and using them in +another.
  • +
  • CSS selector parser dropped remaining expression after a function +with parameters.
  • +
+
+
+

Other changes

+
+
+
+

2.1 (2008-07-09)

+
+

Features added

+
    +
  • Smart strings can be switched off in XPath (smart_strings +keyword option).
  • +
  • lxml.html.rewrite_links() strips links to work around documents +with whitespace in URL attributes.
  • +
+
+
+

Bugs fixed

+
    +
  • Custom resolvers were not used for XMLSchema includes/imports and +XInclude processing.
  • +
  • CSS selector parser dropped remaining expression after a function +with parameters.
  • +
+
+
+

Other changes

+
    +
  • objectify.enableRecursiveStr() was removed, use +objectify.enable_recursive_str() instead
  • +
  • Speed-up when running XSLTs on documents from other threads
  • +
+
+
+
+

2.0.7 (2008-06-20)

+
+

Features added

+
    +
  • Pickling ElementTree objects in lxml.objectify.
  • +
+
+
+

Bugs fixed

+
    +
  • Descending dot-separated classes in CSS selectors were not resolved +correctly.
  • +
  • ElementTree.parse() didn't handle target parser result.
  • +
  • Potential threading problem in XInclude.
  • +
  • Crash in Element class lookup classes when the __init__() method of +the super class is not called from Python subclasses.
  • +
+
+
+

Other changes

+
    +
  • Non-ASCII characters in attribute values are no longer escaped on +serialisation.
  • +
+
+
+
+

2.1beta3 (2008-06-19)

+
+

Features added

+
    +
  • Major overhaul of tools/xpathgrep.py script.
  • +
  • Pickling ElementTree objects in lxml.objectify.
  • +
  • Support for parsing from file-like objects that return unicode +strings.
  • +
  • New function etree.cleanup_namespaces(el) that removes unused +namespace declarations from a (sub)tree (experimental).
  • +
  • XSLT results support the buffer protocol in Python 3.
  • +
  • Polymorphic functions in lxml.html that accept either a tree or +a parsable string will return either a UTF-8 encoded byte string, a +unicode string or a tree, based on the type of the input. +Previously, the result was always a byte string or a tree.
  • +
  • Support for Python 2.6 and 3.0 beta.
  • +
  • File name handling now uses a heuristic to convert between byte +strings (usually filenames) and unicode strings (usually URLs).
  • +
  • Parsing from a plain file object frees the GIL under Python 2.x.
  • +
  • Running iterparse() on a plain file (or filename) frees the GIL +on reading under Python 2.x.
  • +
  • Conversion functions html_to_xhtml() and xhtml_to_html() in +lxml.html (experimental).
  • +
  • Most features in lxml.html work for XHTML namespaced tag names +(experimental).
  • +
+
+
+

Bugs fixed

+
    +
  • ElementTree.parse() didn't handle target parser result.
  • +
  • Crash in Element class lookup classes when the __init__() method of +the super class is not called from Python subclasses.
  • +
  • A number of problems related to unicode/byte string conversion of +filenames and error messages were fixed.
  • +
  • Building on MacOS-X now passes the "flat_namespace" option to the C +compiler, which reportedly prevents build quirks and crashes on this +platform.
  • +
  • Windows build was broken.
  • +
  • Rare crash when serialising to a file object with certain encodings.
  • +
+
+
+

Other changes

+
    +
  • Non-ASCII characters in attribute values are no longer escaped on +serialisation.
  • +
  • Passing non-ASCII byte strings or invalid unicode strings as .tag, +namespaces, etc. will result in a ValueError instead of an +AssertionError (just like the tag well-formedness check).
  • +
  • Up to several times faster attribute access (i.e. tree traversal) in +lxml.objectify.
  • +
+
+
+
+

2.0.6 (2008-05-31)

+
+

Features added

+
+
+

Bugs fixed

+
    +
  • Incorrect evaluation of el.find("tag[child]").
  • +
  • Windows build was broken.
  • +
  • Moving a subtree from a document created in one thread into a +document of another thread could crash when the rest of the source +document is deleted while the subtree is still in use.
  • +
  • Rare crash when serialising to a file object with certain encodings.
  • +
+
+
+

Other changes

+
    +
  • lxml should now build without problems on MacOS-X.
  • +
+
+
+
+

2.1beta2 (2008-05-02)

+
+

Features added

+
    +
  • All parse functions in lxml.html take a parser keyword argument.
  • +
  • lxml.html has a new parser class XHTMLParser and a module +attribute xhtml_parser that provide XML parsers that are +pre-configured for the lxml.html package.
  • +
+
+
+

Bugs fixed

+
    +
  • Moving a subtree from a document created in one thread into a +document of another thread could crash when the rest of the source +document is deleted while the subtree is still in use.
  • +
  • Passing an nsmap when creating an Element will no longer strip +redundantly defined namespace URIs. This prevented the definition +of more than one prefix for a namespace on the same Element.
  • +
+
+
+

Other changes

+
    +
  • If the default namespace is redundantly defined with a prefix on the +same Element, the prefix will now be preferred for subelements and +attributes. This allows users to work around a problem in libxml2 +where attributes from the default namespace could serialise without +a prefix even when they appear on an Element with a different +namespace (i.e. they would end up in the wrong namespace).
  • +
+
+
+
+

2.0.5 (2008-05-01)

+
+

Features added

+
+
+

Bugs fixed

+
    +
  • Resolving to a filename in custom resolvers didn't work.
  • +
  • lxml did not honour libxslt's second error state "STOPPED", which +let some XSLT errors pass silently.
  • +
  • Memory leak in Schematron with libxml2 >= 2.6.31.
  • +
+
+
+

Other changes

+
+
+
+

2.1beta1 (2008-04-15)

+
+

Features added

+
    +
  • Error logging in Schematron (requires libxml2 2.6.32 or later).
  • +
  • Parser option strip_cdata for normalising or keeping CDATA +sections. Defaults to True as before, thus replacing CDATA +sections by their text content.
  • +
  • CDATA() factory to wrap string content as CDATA section.
  • +
+
+
+

Bugs fixed

+
    +
  • Resolving to a filename in custom resolvers didn't work.
  • +
  • lxml did not honour libxslt's second error state "STOPPED", which +let some XSLT errors pass silently.
  • +
  • Memory leak in Schematron with libxml2 >= 2.6.31.
  • +
  • lxml.etree accepted non well-formed namespace prefix names.
  • +
+
+
+

Other changes

+
    +
  • Major cleanup in internal moveNodeToDocument() function, which +takes care of namespace cleanup when moving elements between +different namespace contexts.
  • +
  • New Elements created through the makeelement() method of an HTML +parser or through lxml.html now end up in a new HTML document +(doctype HTML 4.01 Transitional) instead of a generic XML document. +This mostly impacts the serialisation and the availability of a DTD +context.
  • +
+
+
+
+

2.0.4 (2008-04-13)

+
+

Features added

+
+
+

Bugs fixed

+
    +
  • Hanging thread in conjunction with GTK threading.
  • +
  • Crash bug in iterparse when moving elements into other documents.
  • +
  • HTML elements' .cssselect() method was broken.
  • +
  • ElementTree.find*() didn't accept QName objects.
  • +
+
+
+

Other changes

+
+
+
+

2.1alpha1 (2008-03-27)

+
+

Features added

+
    +
  • New event types 'comment' and 'pi' in iterparse().
  • +
  • XSLTAccessControl instances have a property options that +returns a dict of access configuration options.
  • +
  • Constant instances DENY_ALL and DENY_WRITE on +XSLTAccessControl class.
  • +
  • Extension elements for XSLT (experimental!)
  • +
  • Element.base property returns the xml:base or HTML base URL of +an Element.
  • +
  • docinfo.URL property is writable.
  • +
+
+
+

Bugs fixed

+
    +
  • Default encoding for plain text serialisation was different from +that of XML serialisation (UTF-8 instead of ASCII).
  • +
+
+
+

Other changes

+
    +
  • Minor API speed-ups.
  • +
  • The benchmark suite now uses tail text in the trees, which makes the +absolute numbers incomparable to previous results.
  • +
  • Generating the HTML documentation now requires Pygments, which is +used to enable syntax highlighting for the doctest examples.
  • +
+

Most long-time deprecated functions and methods were removed:

+
    +
  • etree.clearErrorLog(), use etree.clear_error_log()

    +
  • +
  • etree.useGlobalPythonLog(), use +etree.use_global_python_log()

    +
  • +
  • etree.ElementClassLookup.setFallback(), use +etree.ElementClassLookup.set_fallback()

    +
  • +
  • etree.getDefaultParser(), use etree.get_default_parser()

    +
  • +
  • etree.setDefaultParser(), use etree.set_default_parser()

    +
  • +
  • etree.setElementClassLookup(), use +etree.set_element_class_lookup()

    +

    Note that parser.setElementClassLookup() has not been removed +yet, although parser.set_element_class_lookup() should be used +instead.

    +
  • +
  • xpath_evaluator.registerNamespace(), use +xpath_evaluator.register_namespace()

    +
  • +
  • xpath_evaluator.registerNamespaces(), use +xpath_evaluator.register_namespaces()

    +
  • +
  • objectify.setPytypeAttributeTag, use +objectify.set_pytype_attribute_tag

    +
  • +
  • objectify.setDefaultParser(), use +objectify.set_default_parser()

    +
  • +
+
+
+
+

2.0.3 (2008-03-26)

+
+

Features added

+
    +
  • soupparser.parse() allows passing keyword arguments on to +BeautifulSoup.
  • +
  • fromstring() method in lxml.html.soupparser.
  • +
+
+
+

Bugs fixed

+
    +
  • lxml.html.diff didn't treat empty tags properly (e.g., +<br>).
  • +
  • Handle entity replacements correctly in target parser.
  • +
  • Crash when using iterparse() with XML Schema validation.
  • +
  • The BeautifulSoup parser (soupparser.py) did not replace entities, +which made them turn up in text content.
  • +
  • Attribute assignment of custom PyTypes in objectify could fail to +correctly serialise the value to a string.
  • +
+
+
+

Other changes

+
    +
  • lxml.html.ElementSoup was replaced by a new module +lxml.html.soupparser with a more consistent API. The old module +remains for compatibility with ElementTree's own ElementSoup module.
  • +
  • Setting the XSLT_CONFIG and XML2_CONFIG environment variables at +build time will let setup.py pick up the xml2-config and +xslt-config scripts from the supplied path name.
  • +
  • Passing --with-xml2-config=/path/to/xml2-config to setup.py will +override the xml2-config script that is used to determine the C +compiler options. The same applies for the --with-xslt-config +option.
  • +
+
+
+
+

2.0.2 (2008-02-22)

+
+

Features added

+
    +
  • Support passing base_url to file parser functions to override +the filename of the file(-like) object.
  • +
+
+
+

Bugs fixed

+
    +
  • The prefix for objectify's pytype namespace was missing from the set +of default prefixes.
  • +
  • Memory leak in Schematron (fixed only for libxml2 2.6.31+).
  • +
  • Error type names in RelaxNG were reported incorrectly.
  • +
  • Slice deletion bug fixed in objectify.
  • +
+
+
+

Other changes

+
    +
  • Enabled doctests for some Python modules (especially lxml.html).
  • +
  • Add a method argument to lxml.html.tostring() +(method="xml" for XHTML output).
  • +
  • Make it clearer that methods like lxml.html.fromstring() take a +base_url argument.
  • +
+
+
+
+

2.0.1 (2008-02-13)

+
+

Features added

+
    +
  • Child iteration in lxml.pyclasslookup.
  • +
  • Loads of new docstrings reflect the signature of functions and +methods to make them visible in API docs and help()
  • +
+
+
+

Bugs fixed

+
    +
  • The module lxml.html.builder was duplicated as +lxml.htmlbuilder
  • +
  • Form elements would return None for form.fields.keys() if there +was an unnamed input field. Now unnamed input fields are completely +ignored.
  • +
  • Setting an element slice in objectify could insert slice-overlapping +elements at the wrong position.
  • +
+
+
+

Other changes

+
    +
  • The generated API documentation was cleaned up and disburdened from +non-public classes etc.
  • +
  • The previously public module lxml.html.setmixin was renamed to +lxml.html._setmixin as it is not an official part of lxml. If +you want to use it, feel free to copy it over to your own source +base.
  • +
  • Passing --with-xslt-config=/path/to/xslt-config to setup.py will +override the xslt-config script that is used to determine the C +compiler options.
  • +
+
+
+
+

2.0 (2008-02-01)

+
+

Features added

+
    +
  • Passing the unicode type as encoding to tostring() will +serialise to unicode. The tounicode() function is now +deprecated.
  • +
  • XMLSchema() and RelaxNG() can parse from StringIO.
  • +
  • makeparser() function in lxml.objectify to create a new +parser with the usual objectify setup.
  • +
  • Plain ASCII XPath string results are no longer forced into unicode +objects as in 2.0beta1, but are returned as plain strings as before.
  • +
  • All XPath string results are 'smart' objects that have a +getparent() method to retrieve their parent Element.
  • +
  • with_tail option in serialiser functions.
  • +
  • More accurate exception messages in validator creation.
  • +
  • Parse-time XML schema validation (schema parser keyword).
  • +
  • XPath string results of the text() function and attribute +selection make their Element container accessible through a +getparent() method. As a side-effect, they are now always +unicode objects (even ASCII strings).
  • +
  • XSLT objects are usable in any thread - at the cost of a deep +copy if they were not created in that thread.
  • +
  • Invalid entity names and character references will be rejected by +the Entity() factory.
  • +
  • entity.text returns the textual representation of the entity, +e.g. &amp;.
  • +
  • New properties position and code on ParseError exception (as +in ET 1.3)
  • +
  • Rich comparison of element.attrib proxies.
  • +
  • ElementTree compatible TreeBuilder class.
  • +
  • Use default prefixes for some common XML namespaces.
  • +
  • lxml.html.clean.Cleaner now allows for a host_whitelist, and +two overridable methods: allow_embedded_url(el, url) and the +more general allow_element(el).
  • +
  • Extended slicing of Elements as in element[1:-1:2], both in +etree and in objectify
  • +
  • Resolvers can now provide a base_url keyword argument when +resolving a document as string data.
  • +
  • When using lxml.doctestcompare you can give the doctest option +NOPARSE_MARKUP (like # doctest: +NOPARSE_MARKUP) to suppress +the special checking for one test.
  • +
  • Separate feed_error_log property for the feed parser interface. +The normal parser interface and iterparse continue to use +error_log.
  • +
  • The normal parsers and the feed parser interface are now separated +and can be used concurrently on the same parser instance.
  • +
  • fromstringlist() and tostringlist() functions as in +ElementTree 1.3
  • +
  • iterparse() accepts an html boolean keyword argument for +parsing with the HTML parser (note that this interface may be +subject to change)
  • +
  • Parsers accept an encoding keyword argument that overrides the encoding +of the parsed documents.
  • +
  • New C-API function hasChild() to test for children
  • +
  • annotate() function in objectify can annotate with Python types and XSI +types in one step. Accompanied by xsiannotate() and pyannotate().
  • +
  • ET.write(), tostring() and tounicode() now accept a keyword +argument method that can be one of 'xml' (or None), 'html' or 'text' to +serialise as XML, HTML or plain text content.
  • +
  • iterfind() method on Elements returns an iterator equivalent to +findall()
  • +
  • itertext() method on Elements
  • +
  • Setting a QName object as value of the .text property or as an attribute +will resolve its prefix in the respective context
  • +
  • ElementTree-like parser target interface as described in +http://effbot.org/elementtree/elementtree-xmlparser.htm
  • +
  • ElementTree-like feed parser interface on XMLParser and HTMLParser +(feed() and close() methods)
  • +
  • Reimplemented objectify.E for better performance and improved +integration with objectify. Provides extended type support based on +registered PyTypes.
  • +
  • XSLT objects now support deep copying
  • +
  • New makeSubElement() C-API function that allows creating a new +subelement straight with text, tail and attributes.
  • +
  • XPath extension functions can now access the current context node +(context.context_node) and use a context dictionary +(context.eval_context) from the context provided in their first +parameter
  • +
  • HTML tag soup parser based on BeautifulSoup in lxml.html.ElementSoup
  • +
  • New module lxml.doctestcompare by Ian Bicking for writing simplified +doctests based on XML/HTML output. Use by importing lxml.usedoctest or +lxml.html.usedoctest from within a doctest.
  • +
  • New module lxml.cssselect by Ian Bicking for selecting Elements with CSS +selectors.
  • +
  • New package lxml.html written by Ian Bicking for advanced HTML +treatment.
  • +
  • Namespace class setup is now local to the ElementNamespaceClassLookup +instance and no longer global.
  • +
  • Schematron validation (incomplete in libxml2)
  • +
  • Additional stringify argument to objectify.PyType() takes a +conversion function to strings to support setting text values from arbitrary +types.
  • +
  • Entity support through an Entity factory and element classes. XML +parsers now have a resolve_entities keyword argument that can be set to +False to keep entities in the document.
  • +
  • column field on error log entries to accompany the line field
  • +
  • Error specific messages in XPath parsing and evaluation +NOTE: for evaluation errors, you will now get an XPathEvalError instead of +an XPathSyntaxError. To catch both, you can except on XPathError
  • +
  • The regular expression functions in XPath now support passing a node-set +instead of a string
  • +
  • Extended type annotation in objectify: new xsiannotate() function
  • +
  • EXSLT RegExp support in standard XPath (not only XSLT)
  • +
+
+
+

Bugs fixed

+
    +
  • Missing import in lxml.html.clean.
  • +
  • Some Python 2.4-isms prevented lxml from building/running under +Python 2.3.
  • +
  • XPath on ElementTrees could crash when selecting the virtual root +node of the ElementTree.
  • +
  • Compilation --without-threading was buggy in alpha5/6.
  • +
  • Memory leak in the parse() function.
  • +
  • Minor bugs in XSLT error message formatting.
  • +
  • Result document memory leak in target parser.
  • +
  • Target parser failed to report comments.
  • +
  • In the lxml.html iter_links method, links in <object> +tags weren't recognized. (Note: plugin-specific link parameters +still aren't recognized.) Also, the <embed> tag, though not +standard, is now included in lxml.html.defs.special_inline_tags.
  • +
  • Using custom resolvers on XSLT stylesheets parsed from a string +could request ill-formed URLs.
  • +
  • With lxml.doctestcompare if you do <tag xmlns="..."> in your +output, it will then be namespace-neutral (before the ellipsis was +treated as a real namespace).
  • +
  • AttributeError in feed parser on parse errors
  • +
  • XML feed parser setup problem
  • +
  • Type annotation for unicode strings in DataElement()
  • +
  • lxml failed to serialise namespace declarations of elements other than the +root node of a tree
  • +
  • Race condition in XSLT where the resolver context leaked between concurrent +XSLT calls
  • +
  • lxml.etree did not check tag/attribute names
  • +
  • The XML parser did not report undefined entities as error
  • +
  • The text in exceptions raised by XML parsers, validators and XPath +evaluators now reports the first error that occurred instead of the last
  • +
  • Passing '' as XPath namespace prefix did not raise an error
  • +
  • Thread safety in XPath evaluators
  • +
+
+
+

Other changes

+
    +
  • Exceptions carry only the part of the error log that is related to +the operation that caused the error.
  • +
  • XMLSchema() and RelaxNG() now enforce passing the source +file/filename through the file keyword argument.
  • +
  • The test suite now skips most doctests under Python 2.3.
  • +
  • make clean no longer removes the .c files (use make +realclean instead)
  • +
  • Minor performance tweaks for Element instantiation and subelement +creation
  • +
  • Various places in the XPath, XSLT and iteration APIs now require +keyword-only arguments.
  • +
  • The argument order in element.itersiblings() was changed to +match the order used in all other iteration methods. The second +argument ('preceding') is now a keyword-only argument.
  • +
  • The getiterator() method on Elements and ElementTrees was +reverted to return an iterator as it did in lxml 1.x. The ET API +specification allows it to return either a sequence or an iterator, +and it traditionally returned a sequence in ET and an iterator in +lxml. However, it is now deprecated in favour of the iter() +method, which should be used in new code wherever possible.
  • +
  • The 'pretty printed' serialisation of ElementTree objects now +inserts newlines at the root level between processing instructions, +comments and the root tag.
  • +
  • A 'pretty printed' serialisation is now terminated with a newline.
  • +
  • Second argument to lxml.etree.Extension() helper is no longer +required, third argument is now a keyword-only argument ns.
  • +
  • lxml.html.tostring takes an encoding argument.
  • +
  • The module source files were renamed to "lxml.*.pyx", such as +"lxml.etree.pyx". This was changed for consistency with the way +Pyrex commonly handles package imports. The main effect is that +classes now know about their fully qualified class name, including +the package name of their module.
  • +
  • Keyword-only arguments in some API functions, especially in the +parsers and serialisers.
  • +
  • Tag name validation in lxml.etree (and lxml.html) now distinguishes +between HTML tags and XML tags based on the parser that was used to +parse or create them. HTML tags no longer reject any non-ASCII +characters in tag names but only spaces and the special characters +<>&/"'.
  • +
  • lxml.etree now emits a warning if you use XPath with libxml2 2.6.27 +(which can crash on certain XPath errors)
  • +
  • Type annotation in objectify now preserves the already annotated type by +default to prevent losing type information that is already there.
  • +
  • element.getiterator() returns a list, use element.iter() to retrieve +an iterator (ElementTree 1.3 compatible behaviour)
  • +
  • objectify.PyType for None is now called "NoneType"
  • +
  • el.getiterator() renamed to el.iter(), following ElementTree 1.3 - +original name is still available as alias
  • +
  • In the public C-API, findOrBuildNodeNs() was replaced by the more +generic findOrBuildNodeNsPrefix
  • +
  • Major refactoring in XPath/XSLT extension function code
  • +
  • Network access in parsers disabled by default
  • +
+
+
+
+

1.3.6 (2007-10-29)

+
+

Bugs fixed

+
    +
  • Backported decref crash fix from 2.0
  • +
  • Well hidden free-while-in-use crash bug in ObjectPath
  • +
+
+
+

Other changes

+
    +
  • The test suites now run gc.collect() in the tearDown() +methods. While this makes them take a lot longer to run, it also +makes it easier to link a specific test to garbage collection +problems that would otherwise appear in later tests.
  • +
+
+
+
+

1.3.5 (2007-10-22)

+
+

Features added

+
+
+

Bugs fixed

+
    +
  • lxml.etree could crash when adding more than 10000 namespaces to a +document
  • +
  • lxml failed to serialise namespace declarations of elements other +than the root node of a tree
  • +
+
+
+
+

1.3.4 (2007-08-30)

+
+

Features added

+
    +
  • The ElementMaker in lxml.builder now accepts the keyword arguments +namespace and nsmap to set a namespace and nsmap for the Elements it +creates.
  • +
  • The docinfo on ElementTree objects has new properties internalDTD +and externalDTD that return a DTD object for the internal or external +subset of the document respectively.
  • +
  • Serialising an ElementTree now includes any internal DTD subsets that are +part of the document, as well as comments and PIs that are siblings of the +root node.
  • +
+
+
+

Bugs fixed

+
    +
  • Parsing with the no_network option could fail
  • +
+
+
+

Other changes

+
    +
  • lxml now raises a TagNameWarning about tag names containing ':' instead of +an Error as 1.3.3 did. The reason is that a number of projects currently +misuse the previous lack of tag name validation to generate namespace +prefixes without declaring namespaces. Apart from the danger of generating +broken XML this way, it also breaks most of the namespace-aware tools in +XML, including XPath, XSLT and validation. lxml 1.3.x will continue to +support this bug with a Warning, while lxml 2.0 will be strict about +well-formed tag names (not only regarding ':').
  • +
  • Serialising an Element no longer includes its comment and PI siblings (only +ElementTree serialisation includes them).
  • +
+
+
+
+

1.3.3 (2007-07-26)

+
+

Features added

+
    +
  • ElementTree compatible parser ETCompatXMLParser strips processing +instructions and comments while parsing XML
  • +
  • Parsers now support stripping PIs (keyword argument 'remove_pis')
  • +
  • etree.fromstring() now supports parsing both HTML and XML, depending on +the parser you pass.
  • +
  • Support base_url keyword argument in HTML() and XML()
  • +
+
+
+

Bugs fixed

+
    +
  • Parsing from Python Unicode strings failed on some platforms
  • +
  • Element() did not raise an exception on tag names containing ':'
  • +
  • Element.getiterator(tag) did not accept Comment and +ProcessingInstruction as tags. It also accepts Element now.
  • +
+
+
+
+

1.3.2 (2007-07-03)

+
+

Features added

+
+
+

Bugs fixed

+
    +
  • "deallocating None" crash bug
  • +
+
+
+
+

1.3.1 (2007-07-02)

+
+

Features added

+
    +
  • objectify.DataElement now supports setting values from existing data +elements (not just plain Python types) and reuses defined namespaces etc.
  • +
  • E-factory support for lxml.objectify (objectify.E)
  • +
+
+
+

Bugs fixed

+
    +
  • Better way to prevent crashes in Element proxy cleanup code
  • +
  • objectify.DataElement didn't set up None value correctly
  • +
  • objectify.DataElement didn't check the value against the provided type hints
  • +
  • Reference-counting bug in Element.attrib.pop()
  • +
+
+
+
+

1.3 (2007-06-24)

+
+

Features added

+
    +
  • Module lxml.pyclasslookup module implements an Element class lookup +scheme that can access the entire tree in read-only mode to help determining +a suitable Element class
  • +
  • Parsers take a remove_comments keyword argument that skips over comments
  • +
  • parse() function in objectify, corresponding to XML() etc.
  • +
  • Element.addnext(el) and Element.addprevious(el) methods to support +adding processing instructions and comments around the root node
  • +
  • Element.attrib was missing clear() and pop() methods
  • +
  • Extended type annotation in objectify: cleaner annotation namespace setup +plus new deannotate() function
  • +
  • Support for custom Element class instantiation in lxml.sax: passing a +makeelement function to the ElementTreeContentHandler will reuse the +lookup context of that function
  • +
  • '.' represents empty ObjectPath (identity)
  • +
  • Element.values() to accompany the existing .keys() and .items()
  • +
  • collectAttributes() C-function to build a list of attribute +keys/values/items for a libxml2 node
  • +
  • DTD validator class (like RelaxNG and XMLSchema)
  • +
  • HTML generator helpers by Fredrik Lundh in lxml.htmlbuilder
  • +
  • ElementMaker XML generator by Fredrik Lundh in lxml.builder.E
  • +
  • Support for pickling objectify.ObjectifiedElement objects to XML
  • +
  • update() method on Element.attrib
  • +
  • Optimised replacement for libxml2's _xmlReconsiliateNs(). This allows lxml +a better handling of namespaces when moving elements between documents.
  • +
+
+
+

Bugs fixed

+
    +
  • Removing Elements from a tree could make them lose their namespace +declarations
  • +
  • ElementInclude didn't honour base URL of original document
  • +
  • Replacing the children slice of an Element would cut off the tails of the +original children
  • +
  • Element.getiterator(tag) did not accept Comment and +ProcessingInstruction as tags
  • +
  • API functions now check incoming strings for XML conformity. Zero bytes or +low ASCII characters are no longer accepted (AssertionError).
  • +
  • XSLT parsing failed to pass resolver context on to imported documents
  • +
  • passing '' as namespace prefix in nsmap could be passed through to libxml2
  • +
  • Objectify couldn't handle prefixed XSD type names in xsi:type
  • +
  • More ET compatible behaviour when writing out XML declarations or not
  • +
  • More robust error handling in iterparse()
  • +
  • Documents lost their top-level PIs and comments on serialisation
  • +
  • lxml.sax failed on comments and PIs. Comments are now properly ignored and +PIs are copied.
  • +
  • Possible memory leaks in namespace handling when moving elements between +documents
  • +
+
+
+

Other changes

+
    +
  • major restructuring in the documentation
  • +
+
+
+
+

1.2.1 (2007-02-27)

+
+

Bugs fixed

+
    +
  • Build fixes for MS compiler
  • +
  • Item assignments to special names like element["text"] failed
  • +
  • Renamed ObjectifiedDataElement.__setText() to _setText() to make it easier +to access
  • +
  • The pattern for attribute names in ObjectPath was too restrictive
  • +
+
+
+
+

1.2 (2007-02-20)

+
+

Features added

+
    +
  • Rich comparison of QName objects
  • +
  • Support for regular expressions in benchmark selection
  • +
  • get/set emulation (not .attrib!) for attributes on processing instructions
  • +
  • ElementInclude Python module for ElementTree compatible XInclude processing +that honours custom resolvers registered with the source document
  • +
  • ElementTree.parser property holds the parser used to parse the document
  • +
  • setup.py has been refactored for greater readability and flexibility
  • +
  • --rpath flag to setup.py to induce automatic linking-in of dynamic library +runtime search paths has been renamed to --auto-rpath. This makes it +possible to pass an --rpath directly to distutils; previously this was being +shadowed.
  • +
+
+
+

Bugs fixed

+
    +
  • Element instantiation now uses locks to prevent race conditions with threads
  • +
  • ElementTree.write() did not raise an exception when the file was not writable
  • +
  • Error handling could crash under Python <= 2.4.1 - fixed by disabling thread +support in these environments
  • +
  • Element.find*() did not accept QName objects as path
  • +
+
+
+

Other changes

+
    +
  • code cleanup: redundant _NodeBase super class merged into _Element class +Note: although the impact should be zero in most cases, this change breaks +the compatibility of the public C-API
  • +
+
+
+
+

1.1.2 (2006-10-30)

+
+

Features added

+
    +
  • Data elements in objectify support repr(), which is now used by dump()
  • +
  • Source distribution now ships with a patched Pyrex
  • +
  • New C-API function makeElement() to create new elements with text, +tail, attributes and namespaces
  • +
  • Reuse original parser flags for XInclude
  • +
  • Simplified support for handling XSLT processing instructions
  • +
+
+
+

Bugs fixed

+
    +
  • Parser resources were not freed before the next parser run
  • +
  • Open files and XML strings returned by Python resolvers were not +closed/freed
  • +
  • Crash in the IDDict returned by XMLDTDID
  • +
  • Copying Comments and ProcessingInstructions failed
  • +
  • Memory leak for external URLs in _XSLTProcessingInstruction.parseXSL()
  • +
  • Memory leak when garbage collecting tailed root elements
  • +
  • HTML script/style content was not propagated to .text
  • +
  • Show text xincluded between text nodes correctly in .text and .tail
  • +
  • 'integer * objectify.StringElement' operation was not supported
  • +
+
+
+
+

1.1.1 (2006-09-21)

+
+

Features added

+
    +
  • XSLT profiling support (profile_run keyword)
  • +
  • countchildren() method on objectify.ObjectifiedElement
  • +
  • Support custom elements for tree nodes in lxml.objectify
  • +
+
+
+

Bugs fixed

+
    +
  • lxml.objectify failed to support long data values (e.g., "123L")
  • +
  • Error messages from XSLT did not reach XSLT.error_log
  • +
  • Factories objectify.Element() and objectify.DataElement() were missing +attrib and nsmap keyword arguments
  • +
  • Changing the default parser in lxml.objectify did not update the factories +Element() and DataElement()
  • +
  • Let lxml.objectify.Element() always generate tree elements (not data +elements)
  • +
  • Build under Windows failed ('0' bug in patched Pyrex version)
  • +
+
+
+
+

1.1 (2006-09-13)

+
+

Features added

+
    +
  • Comments and processing instructions return '<!-- comment -->' and +'<?pi-target content?>' for repr()
  • +
  • Parsers are now the preferred (and default) place where element class lookup +schemes should be registered. Namespace lookup is no longer supported by +default.
  • +
  • Support for Python 2.5 beta
  • +
  • Unlock the GIL for deep copying documents and for XPath()
  • +
  • New compact keyword argument for parsing read-only documents
  • +
  • Support for parser options in iterparse()
  • +
  • The namespace axis is supported in XPath and returns (prefix, URI) +tuples
  • +
  • The XPath expression "/" now returns an empty list instead of raising an +exception
  • +
  • XML-Object API on top of lxml (lxml.objectify)
  • +
  • Customizable Element class lookup:
      +
    • different pre-implemented lookup mechanisms
    • +
    • support for externally provided lookup functions
    • +
    +
  • +
  • Support for processing instructions (ET-like, not compatible)
  • +
  • Public C-level API for independent extension modules
  • +
  • Module level iterwalk() function as 'iterparse' for trees
  • +
  • Module level iterparse() function similar to ElementTree (see +documentation for differences)
  • +
  • Element.nsmap property returns a mapping of all namespace prefixes known at +the Element to their namespace URI
  • +
  • Reentrant threading support in RelaxNG, XMLSchema and XSLT
  • +
  • Threading support in parsers and serializers:
      +
    • All in-memory operations (tostring, parse(StringIO), etc.) free the GIL
    • +
    • File operations (on file names) free the GIL
    • +
    • Reading from file-like objects frees the GIL and reacquires it for reading
    • +
    • Serialisation to file-like objects is single-threaded (high lock overhead)
    • +
    +
  • +
  • Element iteration over XPath axes:
      +
    • Element.iterdescendants() iterates over the descendants of an element
    • +
    • Element.iterancestors() iterates over the ancestors of an element (from +parent to parent)
    • +
    • Element.itersiblings() iterates over either the following or preceding +siblings of an element
    • +
    • Element.iterchildren() iterates over the children of an element in either +direction
    • +
    • All iterators support the tag keyword argument to restrict the +generated elements
    • +
    +
  • +
  • Element.getnext() and Element.getprevious() return the direct siblings of an +element
  • +
+
+
+

Bugs fixed

+
    +
  • filenames with local 8-bit encoding were not supported
  • +
  • 1.1beta did not compile under Python 2.3
  • +
  • ignore unknown 'pyval' attribute values in objectify
  • +
  • objectify.ObjectifiedElement.addattr() failed to accept Elements and Lists
  • +
  • objectify.ObjectPath.setattr() failed to accept Elements and Lists
  • +
  • XPathSyntaxError now inherits from XPathError
  • +
  • Threading race conditions in RelaxNG and XMLSchema
  • +
  • Crash when mixing elements from XSLT results into other trees, concurrent +XSLT is only allowed when the stylesheet was parsed in the main thread
  • +
  • The EXSLT regexp:match function now works as defined (except for some +differences in the regular expression syntax)
  • +
  • Setting element.text to '' returned None on request, not the empty string
  • +
  • iterparse() could crash on long XML files
  • +
  • Creating documents no longer copies the parser for later URL resolving. For +performance reasons, only a reference is kept. Resolver updates on the +parser will now be reflected by documents that were parsed before the +change. Although this should rarely become visible, it is a behavioral +change from 1.0.
  • +
+
+
+
+

1.0.4 (2006-09-09)

+
+

Features added

+
    +
  • List-like Element.extend() method
  • +
+
+
+

Bugs fixed

+
    +
  • Crash in tail handling in Element.replace()
  • +
+
+
+
+

1.0.3 (2006-08-08)

+
+

Features added

+
    +
  • Element.replace(old, new) method to replace a subelement by another one
  • +
+
+
+

Bugs fixed

+
    +
  • Crash when mixing elements from XSLT results into other trees
  • +
  • Copying/deepcopying did not work for ElementTree objects
  • +
  • Setting an attribute to a non-string value did not raise an exception
  • +
  • Element.remove() deleted the tail text from the removed Element
  • +
+
+
+
+

1.0.2 (2006-06-27)

+
+

Features added

+
    +
  • Support for setting a custom default Element class as opposed to namespace +specific classes (which still override the default class)
  • +
+
+
+

Bugs fixed

+
    +
  • Rare exceptions in Python list functions were not handled
  • +
  • Parsing accepted unicode strings with XML encoding declaration in certain +cases
  • +
  • Parsing 8-bit encoded strings from StringIO objects raised an exception
  • +
  • Module function initThread() was removed - useless (and never worked)
  • +
  • XSLT and parser exception messages include the error line number
  • +
+
+
+
+

1.0.1 (2006-06-09)

+
+

Features added

+
    +
  • Repeated calls to Element.attrib now efficiently return the same instance
  • +
+
+
+

Bugs fixed

+
    +
  • Document deallocation could crash in certain garbage collection scenarios
  • +
  • Extension function calls in XSLT variable declarations could break the +stylesheet and crash on repeated calls
  • +
  • Deep copying Elements could lose namespaces declared in parents
  • +
  • Deep copying Elements did not copy tail
  • +
  • Parsing file(-like) objects failed to load external entities
  • +
  • Parsing 8-bit strings from file(-like) objects raised an exception
  • +
  • xsl:include failed when the stylesheet was parsed from a file-like object
  • +
  • lxml.sax.ElementTreeProducer did not call startDocument() / endDocument()
  • +
  • MSVC compiler complained about long strings (supports only 2048 bytes)
  • +
+
+
+
+

1.0 (2006-06-01)

+
+

Features added

+
    +
  • Element.getiterator() and the findall() methods support finding arbitrary +elements from a namespace (pattern {namespace}*)
  • +
  • Another speedup in tree iteration code
  • +
  • General speedup of Python Element object creation and deallocation
  • +
  • Writing C14N no longer serializes in memory (reduced memory footprint)
  • +
  • PyErrorLog for error logging through the Python logging module
  • +
  • Element.getroottree() returns an ElementTree for the root node of the +document that contains the element.
  • +
  • ElementTree.getpath(element) returns a simple, absolute XPath expression to +find the element in the tree structure
  • +
  • Error logs have a last_error attribute for convenience
  • +
  • Comment texts can be changed through the API
  • +
  • Formatted output via pretty_print keyword in serialization functions
  • +
  • XSLT can block access to file system and network via XSLTAccessControl
  • +
  • ElementTree.write() no longer serializes in memory (reduced memory +footprint)
  • +
  • Speedup of Element.findall(tag) and Element.getiterator(tag)
  • +
  • Support for writing the XML representation of Elements and ElementTrees to +Python unicode strings via etree.tounicode()
  • +
  • Support for writing XSLT results to Python unicode strings via unicode()
  • +
  • Parsing a unicode string no longer copies the string (reduced memory +footprint)
  • +
  • Parsing file-like objects reads chunks rather than the whole file (reduced +memory footprint)
  • +
  • Parsing StringIO objects from the start avoids copying the string (reduced +memory footprint)
  • +
  • Read-only 'docinfo' attribute in ElementTree class holds DOCTYPE +information, original encoding and XML version as seen by the parser
  • +
  • etree module can be compiled without libxslt by commenting out the line +include "xslt.pxi" near the end of the etree.pyx source file
  • +
  • Better error messages in parser exceptions
  • +
  • Error reporting also works in XSLT
  • +
  • Support for custom document loaders (URI resolvers) in parsers and XSLT, +resolvers are registered at parser level
  • +
  • Implementation of exslt:regexp for XSLT based on the Python 're' module, +enabled by default, can be switched off with 'regexp=False' keyword argument
  • +
  • Support for exslt extensions (libexslt) and libxslt extra functions +(node-set, document, write, output)
  • +
  • Substantial speedup in XPath.evaluate()
  • +
  • HTMLParser for parsing (broken) HTML
  • +
  • XMLDTDID function parses XML into tuple (root node, ID dict) based on xml:id +implementation of libxml2 (as opposed to ET compatible XMLID)
  • +
+
+
+

Bugs fixed

+
    +
  • Memory leak in Element.__setitem__
  • +
  • Memory leak in Element.attrib.items() and Element.attrib.values()
  • +
  • Memory leak in XPath extension functions
  • +
  • Memory leak in unicode related setup code
  • +
  • Element now raises ValueError on empty tag names
  • +
  • Namespace fixing after moving elements between documents could fail if the +source document was freed too early
  • +
  • Setting namespace-less tag names on namespaced elements ('{ns}t' -> 't') +didn't reset the namespace
  • +
  • Unknown constants from newer libxml2 versions could raise exceptions in the +error handlers
  • +
  • lxml.etree compiles much faster
  • +
  • On libxml2 <= 2.6.22, parsing strings with encoding declaration could fail +in certain cases
  • +
  • Document reference in ElementTree objects was not updated when the root +element was moved to a different document
  • +
  • Running absolute XPath expressions on an Element now evaluates against the +root tree
  • +
  • Evaluating absolute XPath expressions (/*) on an ElementTree could fail
  • +
  • Crashes when calling XSLT, RelaxNG, etc. with uninitialized ElementTree +objects
  • +
  • Removed public function initThreadLogging(), replaced by more general +initThread() which fixes a number of setup problems in threads
  • +
  • Memory leak when using iconv encoders in tostring/write
  • +
  • Deep copying Elements and ElementTrees maintains the document information
  • +
  • Serialization functions raise LookupError for unknown encodings
  • +
  • Memory deallocation crash resulting from deep copying elements
  • +
  • Some ElementTree methods could crash if the root node was not initialized +(neither file nor element passed to the constructor)
  • +
  • Element/SubElement failed to set attribute namespaces from passed attrib +dictionary
  • +
  • tostring() adds an XML declaration for non-ASCII encodings
  • +
  • tostring() failed to serialize encodings that contain 0-bytes
  • +
  • ElementTree.xpath() and XPathDocumentEvaluator were not using the +ElementTree root node as reference point
  • +
  • Calling document('') in XSLT failed to return the stylesheet
  • +
+
+
+
+

0.9.2 (2006-05-10)

+
+

Features added

+
    +
  • Speedup for Element.makeelement(): the new element reuses the original +libxml2 document instead of creating a new empty one
  • +
  • Speedup for reversed() iteration over element children (Py2.4+ only)
  • +
  • ElementTree compatible QName class
  • +
  • RelaxNG and XMLSchema accept any Element, not only ElementTrees
  • +
+
+
+

Bugs fixed

+
    +
  • str(xslt_result) was broken for XSLT output other than UTF-8
  • +
  • Memory leak if write_c14n fails to write the file after conversion
  • +
  • Crash in XMLSchema and RelaxNG when passing non-schema documents
  • +
  • Memory leak in RelaxNG() when RelaxNGParseError is raised
  • +
+
+
+
+

0.9.1 (2006-03-30)

+
+

Features added

+
    +
  • lxml.sax.ElementTreeContentHandler checks closing elements and raises +SaxError on mismatch
  • +
  • lxml.sax.ElementTreeContentHandler supports namespace-less SAX events +(startElement, endElement) and defaults to empty attributes (keyword +argument)
  • +
  • Speedup for repeatedly accessing element tag names
  • +
  • Minor API performance improvements
  • +
+
+
+

Bugs fixed

+
    +
  • Memory deallocation bug when using XSLT output method "html"
  • +
  • sax.py was handling UTF-8 encoded tag names where it shouldn't
  • +
  • lxml.tests package will no longer be installed (is still in source tar)
  • +
+
+
+
+

0.9 (2006-03-20)

+
+

Features added

+
    +
  • Error logging API for libxml2 error messages
  • +
  • Various performance improvements
  • +
  • Benchmark script for lxml, ElementTree and cElementTree
  • +
  • Support for registering extension functions through new FunctionNamespace +class (see doc/extensions.txt)
  • +
  • ETXPath class for XPath expressions in ElementTree notation ('//{ns}tag')
  • +
  • Support for variables in XPath expressions (also in XPath class)
  • +
  • XPath class for compiled XPath expressions
  • +
  • XMLID module level function (ElementTree compatible)
  • +
  • XMLParser API for customized libxml2 parser configuration
  • +
  • Support for custom Element classes through new Namespace API (see +doc/namespace_extensions.txt)
  • +
  • Common exception base class LxmlError for module exceptions
  • +
  • real iterator support in iter(Element), Element.getiterator()
  • +
  • XSLT objects are callable, result trees support str()
  • +
  • Added MANIFEST.in for easier creation of RPM files.
  • +
  • 'getparent' method on elements allows navigation to an element's +parent element.
  • +
  • Python core compatible SAX tree builder and SAX event generator. See +doc/sax.txt for more information.
  • +
+
+
+

Bugs fixed

+
    +
  • Segfaults and memory leaks in various API functions of Element
  • +
  • Segfault in XSLT.tostring()
  • +
  • ElementTree objects no longer interfere, Elements can be root of different +ElementTrees at the same time
  • +
  • document('') works in XSLT documents read from files (in-memory documents +cannot support this due to libxslt deficiencies)
  • +
+
+
+
+

0.8 (2005-11-03)

+
+

Features added

+
    +
  • Support for copy.deepcopy() on elements. copy.copy() works also, but +does the same thing, and does not create a shallow copy, as that +makes no sense in the context of libxml2 trees. This means a +potential incompatibility with ElementTree, but there's more chance +that it works than if copy.copy() isn't supported at all.
  • +
  • Increased compatibility with (c)ElementTree; .parse() on ElementTree is +supported and parsing of gzipped XML files works.
  • +
  • implemented index() on elements, allowing one to find the index of a +SubElement.
  • +
+
+
+

Bugs fixed

+
    +
  • Use xslt-config instead of xml2-config to find out libxml2 +directories to take into account a case where libxslt is installed +in a different directory than libxslt.
  • +
  • Eliminate crash condition in iteration when text nodes are changed.
  • +
  • Passing 'None' to tostring() does not result in a segfault anymore, +but an AssertionError.
  • +
  • Some test fixes for Windows.
  • +
  • Raise XMLSyntaxError and XPathSyntaxError instead of plain python +syntax errors. This should be less confusing.
  • +
  • Fixed error with uncaught exception in Pyrex code.
  • +
  • Calling lxml.etree.fromstring('') throws XMLSyntaxError instead of a +segfault.
  • +
  • has_key() works on attrib. 'in' tests also work correctly on attrib.
  • +
  • INSTALL.txt was saying 2.2.16 instead of 2.6.16 as a supported +libxml2 version, as it should.
  • +
  • Passing a UTF-8 encoded string to the XML() function would fail; +fixed.
  • +
+
+
+
+

0.7 (2005-06-15)

+
+

Features added

+
    +
  • parameters (XPath expressions) can be passed to XSLT using keyword +parameters.
  • +
  • Simple XInclude support. Calling the xinclude() method on a tree +will process any XInclude statements in the document.
  • +
  • XMLSchema support. Use the XMLSchema class or the convenience +xmlschema() method on a tree to do XML Schema (XSD) validation.
  • +
  • Added convenience xslt() method on tree. This is less efficient +than the XSLT object, but makes it easier to write quick code.
  • +
  • Added convenience relaxng() method on tree. This is less efficient +than the RelaxNG object, but makes it easier to write quick code.
  • +
  • Make it possible to use XPathEvaluator with elements as well. The +XPathEvaluator in this case will retain the element so multiple +XPath queries can be made against one element efficiently. This +replaces the second argument to the .evaluate() method that existed +previously.
  • +
  • Allow registerNamespace() to be called on an XPathEvaluator, after +creation, to add additional namespaces. Also allow registerNamespaces(), +which does the same for a namespace dictionary.
  • +
  • Add 'prefix' attribute to element to be able to read prefix information. +This is entirely read-only.
  • +
  • It is possible to supply an extra nsmap keyword parameter to +the Element() and SubElement() constructors, which supplies a +prefix to namespace URI mapping. This will create namespace +prefix declarations on these elements and these prefixes will show up +in XML serialization.
  • +
+
+
+

Bugs fixed

+
    +
  • Killed yet another memory management related bug: trees created +using newDoc would not get a libxml2-level dictionary, which caused +problems when deallocating these documents later if they contained a +node that came from a document with a dictionary.
  • +
  • Moving namespaced elements between documents was problematic as +references to the original document would remain. This has been fixed +by applying xmlReconciliateNs() after each move operation.
  • +
  • Can pass None to 'dump()' without segfaults.
  • +
  • tostring() works properly for non-root elements as well.
  • +
  • Cleaned out the tostring() method so it should handle encoding +correctly.
  • +
  • Cleaned out the ElementTree.write() method so it should handle encoding +correctly. Writing directly to a file should also be faster, as there is no +need to go through a Python string in that case. Made sure the test cases +test both serializing to StringIO as well as serializing to a real file.
  • +
+
+
+
+

0.6 (2005-05-14)

+
+

Features added

+
    +
  • Changed setup.py so that library_dirs is also guessed. This should +help with compilation on the Mac OS X platform, where otherwise the +wrong library (shipping with the OS) could be picked up.
  • +
  • Tweaked setup.py so that it picks up the version from version.txt.
  • +
+
+
+

Bugs fixed

+
    +
  • Do the right thing when handling namespaced attributes.
  • +
  • fix bug where tostring() moved nodes into new documents. tostring() +had very nasty side-effects before this fix, sorry!
  • +
+
+
+
+

0.5.1 (2005-04-09)

+
    +
  • Python 2.2 compatibility fixes.
  • +
  • unicode fixes in Element() and Comment() as well as XML(); unicode +input wasn't properly being UTF-8 encoded.
  • +
+
+
+

0.5 (2005-04-08)

+

Initial public release.

+
+
+ + + diff --git a/doc/html/compatibility.html b/doc/html/compatibility.html index 65ae1f1..205988d 100644 --- a/doc/html/compatibility.html +++ b/doc/html/compatibility.html @@ -2,7 +2,7 @@ - + ElementTree compatibility of lxml.etree
-

ElementTree compatibility of lxml.etree

+

ElementTree compatibility of lxml.etree

A lot of care has been taken to ensure compatibility between etree and ElementTree. Nonetheless, some differences and incompatibilities exist:

@@ -147,11 +147,11 @@ argument given) to XML, etree serializes this successfully.

not. This means that a comment text "text" that ElementTree serializes as "<!-- text -->" will become "<!--text-->" in lxml.

-
  • When the string '*' is used as tag filter in the Element.getiterator() -method, ElementTree returns all elements in the tree, including comments and -processing instructions. lxml.etree only returns real Elements, i.e. tree -nodes that have a string tag name. Without a filter, both libraries iterate -over all nodes.

    +
  • When the string '*' is used as tag filter in the Element.iter() and +.find*() methods, ElementTree returns all elements in the tree, including +comments and processing instructions. lxml.etree only returns real Elements, +i.e. tree nodes that have a string tag name. Without a filter, both libraries +iterate over all nodes.

    Note that currently only lxml.etree supports passing the Element factory function as filter to select only Elements. Both libraries support passing the Comment and ProcessingInstruction factories to select the @@ -199,7 +199,7 @@ enough to replace a shallow copy in your case.

  • diff --git a/doc/html/credits.html b/doc/html/credits.html index 079b56d..d3350aa 100644 --- a/doc/html/credits.html +++ b/doc/html/credits.html @@ -2,7 +2,7 @@ - + Credits
    -

    Credits

    +

    Credits

    Main contributors

    @@ -88,7 +88,7 @@ Holger Krekel for originally hosting lxml on codespeak.net
    diff --git a/doc/html/cssselect.html b/doc/html/cssselect.html index dd24b52..584e371 100644 --- a/doc/html/cssselect.html +++ b/doc/html/cssselect.html @@ -2,7 +2,7 @@ - + lxml.cssselect
    -

    lxml.cssselect

    +

    lxml.cssselect

    lxml supports a number of interesting languages for tree traversal and element selection. The most important is obviously XPath, but there is also @@ -113,7 +113,7 @@ namespace URIs: the CSSSelector class accepts

    diff --git a/doc/html/element_classes.html b/doc/html/element_classes.html index 216dde3..a8a36b0 100644 --- a/doc/html/element_classes.html +++ b/doc/html/element_classes.html @@ -2,7 +2,7 @@ - + Using custom Element classes in lxml
    -

    Using custom Element classes in lxml

    +

    Using custom Element classes in lxml

    lxml has very sophisticated support for custom Element classes. You can provide your own classes for Elements and have lxml use them by @@ -148,14 +148,14 @@ for a parser works as follows:

    does not know about your specialised parser and creates a new document that deploys the default parser:

    >>> el = etree.Element("root")
    ->>> print(isinstance(el, honk))
    +>>> print(isinstance(el, honk))
     False
     

    You should therefore avoid using this factory function in code that uses custom classes. The makeelement() method of parsers provides a simple replacement:

    >>> el = parser.makeelement("root")
    ->>> print(isinstance(el, honk))
    +>>> print(isinstance(el, honk))
     True
     

    If you use a parser at the module level, you can easily redirect a module @@ -166,21 +166,21 @@ level Element() factory to the parser method b

    While the XML() and HTML() factories also depend on the default parser, you can pass them a different parser as second argument:

    >>> element = etree.XML("<test/>")
    ->>> print(isinstance(element, honk))
    +>>> print(isinstance(element, honk))
     False
     
     >>> element = etree.XML("<test/>", parser)
    ->>> print(isinstance(element, honk))
    +>>> print(isinstance(element, honk))
     True
     

    Whenever you create a document with a parser, it will inherit the lookup scheme and all subsequent element instantiations for this document will use it:

    >>> element = etree.fromstring("<test/>", parser)
    ->>> print(isinstance(element, honk))
    +>>> print(isinstance(element, honk))
     True
     >>> el = etree.SubElement(element, "subel")
    ->>> print(isinstance(el, honk))
    +>>> print(isinstance(el, honk))
     True
     

    For testing code in the Python interpreter and for small projects, you @@ -207,14 +207,14 @@ also the default lookup (if not configured otherwise).

    the constructor. While it accepts classes for element, comment and pi nodes, most use cases will only override the element class:

    >>> el = parser.makeelement("myelement")
    ->>> print(isinstance(el, honk))
    +>>> print(isinstance(el, honk))
     False
     
     >>> lookup = etree.ElementDefaultClassLookup(element=honk)
     >>> parser.set_element_class_lookup(lookup)
     
     >>> el = parser.makeelement("myelement")
    ->>> print(isinstance(el, honk))
    +>>> print(isinstance(el, honk))
     True
     >>> el.honking
     False
    @@ -228,7 +228,7 @@ the constructor.  While it accepts classes for elem
     ...     '<root honking="true"><!--comment--></root>', parser)
     >>> root.honking
     True
    ->>> print(root[0].text)
    +>>> print(root[0].text)
     comment
     
    @@ -254,7 +254,7 @@ desired fallback lookup scheme to the constructor:

    ... '<root honking="true"><!--comment--></root>', parser) >>> root.honking True ->>> print(root[0].text) +>>> print(root[0].text) comment
    @@ -303,7 +303,7 @@ basis. It allows you to implement a custom lookup scheme in a subclass:

    ... if node_type == 'element': ... return honk # be a bit more selective here ... ... else: -... return None # pass on to (default) fallback +... return None # pass on to (default) fallback >>> parser = etree.XMLParser() >>> parser.set_element_class_lookup(MyLookup()) @@ -312,7 +312,7 @@ basis. It allows you to implement a custom lookup scheme in a subclass:

    ... '<root honking="true"><!--comment--></root>', parser) >>> root.honking True ->>> print(root[0].text) +>>> print(root[0].text) comment

    The .lookup() method must return either None (which triggers the @@ -383,7 +383,7 @@ your Element proxy classes for the elements that they create. The >>> el = hale( "some ", honk(honking = 'true'), bopp, " text" ) ->>> print(etree.tostring(el, encoding='unicode')) +>>> print(etree.tostring(el, encoding='unicode')) <hale>some <honk honking="true"/><bopp/> text</hale> @@ -412,13 +412,13 @@ everything that is not an Element class.

    lxml:

    >>> xml = '<honk xmlns="http://hui.de/honk" honking="true"/>'
     >>> honk_element = etree.XML(xml, parser)
    ->>> print(honk_element.honking)
    +>>> print(honk_element.honking)
     True
     

    The same works when creating elements by hand:

    >>> honk_element = parser.makeelement('{http://hui.de/honk}honk',
     ...                                   honking='true')
    ->>> print(honk_element.honking)
    +>>> print(honk_element.honking)
     True
     

    Essentially, what this allows you to do, is to give Elements a custom API @@ -433,13 +433,13 @@ implementation:

    ... '<bla/><!--comment-->' ... '</honk>') >>> honk_element = etree.XML(xml, parser) ->>> print(honk_element.honking) +>>> print(honk_element.honking) True ->>> print(honk_element[0].honking) +>>> print(honk_element[0].honking) Traceback (most recent call last): ... AttributeError: 'lxml.etree._Element' object has no attribute 'honking' ->>> print(honk_element[1].text) +>>> print(honk_element[1].text) comment

    You can therefore provide one implementation per element name in each @@ -455,7 +455,7 @@ can just pass None as an element name:

    >>> class HonkNSElement(etree.ElementBase):
     ...    def honk(self):
     ...       return "HONK"
    ->>> namespace[None] = HonkNSElement  # default Element for namespace
    +>>> namespace[None] = HonkNSElement  # default Element for namespace
     
     >>> class HonkElement(HonkNSElement):
     ...    @property
    @@ -470,24 +470,24 @@ subclasses for elements of this namespace:

    ... '</honk>') >>> honk_element = etree.fromstring(xml, parser) ->>> print(type(honk_element)) +>>> print(type(honk_element)) <class 'HonkElement'> ->>> print(type(honk_element[0])) +>>> print(type(honk_element[0])) <class 'HonkNSElement'> ->>> print(honk_element.honking) +>>> print(honk_element.honking) True ->>> print(honk_element.honk()) +>>> print(honk_element.honk()) HONK ->>> print(honk_element[0].honk()) +>>> print(honk_element[0].honk()) HONK ->>> print(honk_element[0].honking) +>>> print(honk_element[0].honking) Traceback (most recent call last): ... AttributeError: 'HonkNSElement' object has no attribute 'honking' ->>> print(honk_element[1].text) # uses fallback for non-elements +>>> print(honk_element[1].text) # uses fallback for non-elements comment

    Since lxml 4.1, the registration is more conveniently done with @@ -495,7 +495,7 @@ class decorators. The namespace registry object is callable with a name (or None) as argument and can then be used as decorator.

    >>> honk_elements = lookup.get_namespace('http://hui.de/honk')
     
    ->>> @honk_elements(None)
    +>>> @honk_elements(None)
     ... class HonkNSElement(etree.ElementBase):
     ...    def honk(self):
     ...       return "HONK"
    @@ -525,7 +525,7 @@ and use the blank decorator instead:

    diff --git a/doc/html/elementsoup.html b/doc/html/elementsoup.html index e71849f..d874daa 100644 --- a/doc/html/elementsoup.html +++ b/doc/html/elementsoup.html @@ -2,7 +2,7 @@ - + BeautifulSoup Parser
    -

    BeautifulSoup Parser

    +

    BeautifulSoup Parser

    BeautifulSoup is a Python package for working with real-world and broken HTML, just like lxml.html. As of version 4.x, it can use @@ -74,7 +74,7 @@ Previous versions of lxml 2.0.x only have the Eleme

    To see what we have here, you can serialise it:

    >>> from lxml.etree import tostring
    ->>> print(tostring(root, pretty_print=True).strip())
    +>>> print(tostring(root, pretty_print=True).strip())
     <html>
       <meta/>
       <head>
    @@ -189,7 +189,7 @@ you can simply pass the resulting Unicode string into lxml's parser.

    ... from BeautifulSoup import UnicodeDammit # BeautifulSoup 3 ... ... def decode_html(html_string): -... converted = UnicodeDammit(html_string, isHTML=True) +... converted = UnicodeDammit(html_string, isHTML=True) ... if not converted.unicode: ... raise UnicodeDecodeError( ... "Failed to detect encoding, tried [%s]", @@ -203,7 +203,7 @@ you can simply pass the resulting Unicode string into lxml's parser.

    diff --git a/doc/html/extensions.html b/doc/html/extensions.html index 9f87d67..5d7bb89 100644 --- a/doc/html/extensions.html +++ b/doc/html/extensions.html @@ -2,7 +2,7 @@ - + Python extensions for XPath and XSLT
    -

    Python extensions for XPath and XSLT

    +

    Python extensions for XPath and XSLT

    This document describes how to use Python extension functions in XPath and XSLT like this:

    @@ -77,7 +77,7 @@ the following examples. Any number of arguments is allowed:

    is done using the FunctionNamespace class. For simplicity, we choose the empty namespace (None):

    >>> from lxml import etree
    ->>> ns = etree.FunctionNamespace(None)
    +>>> ns = etree.FunctionNamespace(None)
     >>> ns['hello'] = hello
     >>> ns['countargs'] = loadsofargs
     
    @@ -96,13 +96,13 @@ against:

    >>> doc = etree.ElementTree(root)

    Done. Now we can have XPath expressions call our new function:

    -
    >>> print(root.xpath("hello('Dr. Falken')"))
    +
    >>> print(root.xpath("hello('Dr. Falken')"))
     Hello Dr. Falken
    ->>> print(root.xpath('hello(local-name(*))'))
    +>>> print(root.xpath('hello(local-name(*))'))
     Hello b
    ->>> print(root.xpath('hello(string(b))'))
    +>>> print(root.xpath('hello(string(b))'))
     Hello Haegar
    ->>> print(root.xpath('countargs(., b, ./*)'))
    +>>> print(root.xpath('countargs(., b, ./*)'))
     Got 3 arguments.
     

    Note how we call both a Python function (hello()) and an XPath built-in @@ -113,7 +113,7 @@ allows you to do this:

    >>> ns['hello'] = hello >>> prefixmap = {'f' : 'http://mydomain.org/myfunctions'} ->>> print(root.xpath('f:hello(local-name(*))', namespaces=prefixmap)) +>>> print(root.xpath('f:hello(local-name(*))', namespaces=prefixmap)) Hello b
    @@ -126,7 +126,7 @@ register it with the namespace:

    >>> ns.prefix = 'es' >>> ns['hello'] = ola ->>> print(root.xpath('es:hello(local-name(*))')) +>>> print(root.xpath('es:hello(local-name(*))')) Ola b

    This is a global assignment, so take care not to assign the same prefix to @@ -145,7 +145,7 @@ was None, but since lxml 2.0 it provides two properties: context_node. The context node is the Element where the current function is called:

    >>> def print_tag(context, nodes):
    -...     print("%s: %s" % (context.context_node.tag, [ n.tag for n in nodes ]))
    +...     print("%s: %s" % (context.context_node.tag, [ n.tag for n in nodes ]))
     
     >>> ns = etree.FunctionNamespace('http://mydomain.org/printtag')
     >>> ns.prefix = "pt"
    @@ -159,7 +159,7 @@ is called:

    allows functions to keep state:

    >>> def print_context(context):
     ...     context.eval_context[context.context_node.tag] = "done"
    -...     print(sorted(context.eval_context.items()))
    +...     print(sorted(context.eval_context.items()))
     >>> ns["print_context"] = print_context
     
     >>> ignore = root.xpath("//*[pt:print_context()]")
    @@ -172,12 +172,12 @@ allows functions to keep state:

    Extension functions work for all ways of evaluating XPath expressions and for XSL transformations:

    >>> e = etree.XPathEvaluator(doc)
    ->>> print(e('es:hello(local-name(/a))'))
    +>>> print(e('es:hello(local-name(/a))'))
     Ola a
     
     >>> namespaces = {'f' : 'http://mydomain.org/myfunctions'}
     >>> e = etree.XPathEvaluator(doc, namespaces=namespaces)
    ->>> print(e('f:hello(local-name(/a))'))
    +>>> print(e('f:hello(local-name(/a))'))
     Hello a
     
     >>> xslt = etree.XSLT(etree.XML('''
    @@ -190,7 +190,7 @@ XSL transformations:

    ... </template> ... </stylesheet> ... ''')) ->>> print(xslt(doc)) +>>> print(xslt(doc)) Ola Haegar

    It is also possible to register namespaces with a single evaluator after its @@ -228,7 +228,7 @@ The value is a dictionary mapping (namespace, name) tuples to functions:

    >>> namespaces = {'l' : 'local-ns'} >>> e = etree.XPathEvaluator(doc, namespaces=namespaces, extensions=extensions) ->>> print(e('l:local-hello(string(b))')) +>>> print(e('l:local-hello(string(b))')) Hello Haegar

    For larger numbers of extension functions, you can define classes or modules @@ -246,7 +246,7 @@ and use the Extension helper:

    >>> extensions = etree.Extension( ext_module, functions, ns='local-ns' ) >>> e = etree.XPathEvaluator(doc, namespaces=namespaces, extensions=extensions) ->>> print(e('l:function1(string(b))')) +>>> print(e('l:function1(string(b))')) 1Haegar

    The optional second argument to Extension can either be a @@ -260,17 +260,17 @@ examples will therefore all do the same thing:

    >>> functions = ('function1', 'function2', 'function3')
     >>> extensions = etree.Extension( ext_module, functions )
     >>> e = etree.XPathEvaluator(doc, extensions=extensions)
    ->>> print(e('function1(function2(function3(string(b))))'))
    +>>> print(e('function1(function2(function3(string(b))))'))
     123Haegar
     
    ->>> extensions = etree.Extension( ext_module, functions, ns=None )
    +>>> extensions = etree.Extension( ext_module, functions, ns=None )
     >>> e = etree.XPathEvaluator(doc, extensions=extensions)
    ->>> print(e('function1(function2(function3(string(b))))'))
    +>>> print(e('function1(function2(function3(string(b))))'))
     123Haegar
     
     >>> extensions = etree.Extension(ext_module)
     >>> e = etree.XPathEvaluator(doc, extensions=extensions)
    ->>> print(e('function1(function2(function3(string(b))))'))
    +>>> print(e('function1(function2(function3(string(b))))'))
     123Haegar
     
     >>> functions = {
    @@ -280,7 +280,7 @@ examples will therefore all do the same thing:

    ... } >>> extensions = etree.Extension(ext_module, functions) >>> e = etree.XPathEvaluator(doc, extensions=extensions) ->>> print(e('function1(function2(function3(string(b))))')) +>>> print(e('function1(function2(function3(string(b))))')) 123Haegar

    For convenience, you can also pass a sequence of extensions:

    @@ -288,7 +288,7 @@ examples will therefore all do the same thing:

    >>> extensions2 = etree.Extension(ext_module, ns='local-ns') >>> e = etree.XPathEvaluator(doc, extensions=[extensions1, extensions2], ... namespaces=namespaces) ->>> print(e('function1(l:function2(function3(string(b))))')) +>>> print(e('function1(l:function2(function3(string(b))))')) 123Haegar @@ -303,11 +303,11 @@ will also be returned as floats:

    >>> def returnsInteger(_): ... return 1 >>> def returnsBool(_): -... return True +... return True >>> def returnFirstNode(_, nodes): ... return nodes[0] ->>> ns = etree.FunctionNamespace(None) +>>> ns = etree.FunctionNamespace(None) >>> ns['float'] = returnsFloat >>> ns['int'] = returnsInteger >>> ns['bool'] = returnsBool @@ -345,13 +345,13 @@ XPath node-sets:

    >>> e = etree.XPathEvaluator(doc) >>> r = e("new-node-set()/result") ->>> print([ t.text for t in r ]) +>>> print([ t.text for t in r ]) ['Alpha', 'Beta', 'Gamma', 'Delta'] >>> r = e("new-node-set()") ->>> print([ t.tag for t in r ]) +>>> print([ t.tag for t in r ]) ['results1', 'results2', 'subresult'] ->>> print([ len(t) for t in r ]) +>>> print([ len(t) for t in r ]) [2, 3, 0] >>> r[0][0].text 'Alpha' @@ -370,13 +370,13 @@ Only the elements and their children are passed on, no outlying parents or tail texts will be available in the result. This also means that in the above example, the subresult elements in results2 and results3 are no longer identical within the node-set, they belong to independent trees:

    -
    >>> print("%s - %s" % (r[1][-1].tag, r[2].tag))
    +
    >>> print("%s - %s" % (r[1][-1].tag, r[2].tag))
     subresult - subresult
    ->>> print(r[1][-1] == r[2])
    +>>> print(r[1][-1] == r[2])
     False
    ->>> print(r[1][-1].getparent().tag)
    +>>> print(r[1][-1].getparent().tag)
     results2
    ->>> print(r[2].getparent())
    +>>> print(r[2].getparent())
     None
     

    This is an implementation detail that you should be aware of, but you should @@ -399,7 +399,7 @@ code like this:

    And then you can implement the element in Python like this:

    >>> class MyExtElement(etree.XSLTExtension):
     ...     def execute(self, context, self_node, input_node, output_parent):
    -...         print("Hello from XSLT!")
    +...         print("Hello from XSLT!")
     ...         output_parent.text = "I did it!"
     ...         # just copy own content input to output
     ...         output_parent.extend( list(self_node) )
    @@ -530,7 +530,7 @@ will work:

    diff --git a/doc/html/flattr-badge-large.png b/doc/html/flattr-badge-large.png deleted file mode 100644 index 1105305..0000000 Binary files a/doc/html/flattr-badge-large.png and /dev/null differ diff --git a/doc/html/html5parser.html b/doc/html/html5parser.html index f610bdc..d705b6c 100644 --- a/doc/html/html5parser.html +++ b/doc/html/html5parser.html @@ -2,7 +2,7 @@ - + html5lib Parser
    -

    html5lib Parser

    +

    html5lib Parser

    html5lib is a Python package that implements the HTML5 parsing algorithm which is heavily influenced by current browsers and based on the WHATWG @@ -90,7 +90,7 @@ module. Note that these are the parser classes provided by html5lib.

    diff --git a/doc/html/index.html b/doc/html/index.html index 11c0d50..0757387 100644 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -2,7 +2,7 @@ - + lxml - Processing XML and HTML with Python @@ -26,7 +26,7 @@ function hide_menu() {
    -

    lxml - XML and HTML with Python

    +

    lxml - XML and HTML with Python

    @@ -66,11 +66,15 @@ Thank you for your support.

    Support lxml through GitHub Sponsors

    via a Tidelift subscription

    or via PayPal:

    -

    Donate to the lxml project

    +

    Donate to the lxml project

    Please contact Stefan Behnel for other ways to support the lxml project, as well as commercial consulting, customisations and trainings on lxml and fast Python XML processing.

    +

    Note that we are not accepting donations in crypto currencies. +Much of the development and hosting for lxml is done in a carbon-neutral way +or with compensated and very low emissions. +Crypto currencies do not fit into that ambition.

    Travis-CI and AppVeyor support the lxml project with their build and CI servers. Jetbrains supports the lxml project by donating free licenses of their @@ -81,7 +85,7 @@ Another supporter of the lxml project is

    Documentation

    -

    The complete lxml documentation is available for download as PDF +

    The complete lxml documentation is available for download as PDF documentation. The HTML documentation from this web site is part of the normal source download.

    Project income report

      +
    • Total project income in 2020: EUR 6065,86 (506.49 € / month)
        +
      • Tidelift: EUR 4064.77
      • +
      • Paypal: EUR 1401.09
      • +
      • other: EUR 600.00
      • +
      +
    • Total project income in 2019: EUR 717.52 (59.79 € / month)
      • Tidelift: EUR 360.30
      • Paypal: EUR 157.22
      • @@ -260,7 +271,7 @@ donation is non-refundable.

    diff --git a/doc/html/installation.html b/doc/html/installation.html index c9f80a1..d1673c0 100644 --- a/doc/html/installation.html +++ b/doc/html/installation.html @@ -2,7 +2,7 @@ - + Installing lxml
    -

    Installing lxml

    +

    Installing lxml

    Contents

    @@ -208,7 +208,7 @@ read the
    diff --git a/doc/html/intro.html b/doc/html/intro.html index 790f838..709ae5a 100644 --- a/doc/html/intro.html +++ b/doc/html/intro.html @@ -2,7 +2,7 @@ - + Why lxml?
    -

    Why lxml?

    +

    Why lxml?

    Contents

    @@ -82,7 +82,7 @@ having to learn new things -- XML is complicated enough.

    diff --git a/doc/html/lxml-source-howto.html b/doc/html/lxml-source-howto.html index 7345dc0..5407988 100644 --- a/doc/html/lxml-source-howto.html +++ b/doc/html/lxml-source-howto.html @@ -2,7 +2,7 @@ - + How to read the source of lxml @@ -27,7 +27,7 @@ function hide_menu() {
    -

    How to read the source of lxml

    +

    How to read the source of lxml

    @@ -286,7 +286,7 @@ implemented in pure Python.

    diff --git a/doc/html/lxmlhtml.html b/doc/html/lxmlhtml.html index 5c9f700..a38097f 100644 --- a/doc/html/lxmlhtml.html +++ b/doc/html/lxmlhtml.html @@ -2,7 +2,7 @@ - +lxml.html @@ -25,7 +25,7 @@ function hide_menu() {
    -

    lxml.html

    +

    lxml.html

    @@ -199,13 +199,13 @@ document in a doctest, you can do the following:

    ... </body></html>... ''') ->>> printlxml.html.tostring(html) +>>> printlxml.html.tostring(html)<html><body onload="" color="white"><p>Hi !</p></body></html> ->>> printlxml.html.tostring(html) +>>> printlxml.html.tostring(html)<html> <body color="white" onload=""> <p>Hi !</p> </body> </html> ->>> printlxml.html.tostring(html) +>>> printlxml.html.tostring(html)<html> <body color="white" onload=""> <p>Hi !</p> @@ -241,7 +241,7 @@ pages and fragments:

    ... )... ) ->>> printlxml.html.tostring(html) +>>> printlxml.html.tostring(html)<html> <head> <link href="great.css" rel="stylesheet" type="text/css"> @@ -412,7 +412,7 @@ You can, for instance, do:

    ... name='John Smith',... phone='555-555-3949',... interest=set(['cats','llamas'])) ->>> printtostring(form) +>>> printtostring(form)<html> <body> <form> @@ -493,7 +493,7 @@ content that upsets browsers and tries to run evil code on the client side:

    To remove the all suspicious content from this unparsed document, use the clean_html function:

    >>> from lxml.html.clean import clean_html
    ->>> print clean_html(html)
    +>>> print clean_html(html)
     <div><style>/* deleted */</style><body>
     
        <a href="">a link</a>
    @@ -511,8 +511,8 @@ content that upsets browsers and tries to run evil code on the client side:

    which content is removed:

    >>> from lxml.html.clean import Cleaner
     
    ->>> cleaner = Cleaner(page_structure=False, links=False)
    ->>> print cleaner.clean_html(html)
    +>>> cleaner = Cleaner(page_structure=False, links=False)
    +>>> print cleaner.clean_html(html)
     <html>
       <head>
         <link rel="alternate" src="evil-rss" type="text/rss">
    @@ -531,10 +531,10 @@ which content is removed:

    </body> </html> ->>> cleaner = Cleaner(style=True, links=True, add_nofollow=True, -... page_structure=False, safe_attrs_only=False) +>>> cleaner = Cleaner(style=True, links=True, add_nofollow=True, +... page_structure=False, safe_attrs_only=False) ->>> print cleaner.clean_html(html) +>>> print cleaner.clean_html(html) <html> <head> </head> @@ -620,9 +620,9 @@ documents.

    >>> doc1 = '''<p>Here is some text.</p>''' >>> doc2 = '''<p>Here is <b>a lot</b> of <i>text</i>.</p>''' >>> doc3 = '''<p>Here is <b>a little</b> <i>text</i>.</p>''' ->>> print htmldiff(doc1, doc2) +>>> print htmldiff(doc1, doc2) <p>Here is <ins><b>a lot</b> of <i>text</i>.</ins> <del>some text.</del> </p> ->>> print html_annotate([(doc1, 'author1'), (doc2, 'author2'), +>>> print html_annotate([(doc1, 'author1'), (doc2, 'author2'), ... (doc3, 'author3')]) <p><span title="author1">Here is</span> <b><span title="author2">a</span> @@ -639,7 +639,7 @@ version. The default version, the output of which you see in the example, looks like:

    def default_markup(text, version):
         return '<span title="%s">%s</span>' % (
    -        cgi.escape(unicode(version), 1), text)
    +        cgi.escape(unicode(version), 1), text)
     
    @@ -696,7 +696,7 @@ microformat.

    diff --git a/doc/html/objectify.html b/doc/html/objectify.html index f88dc23..14e6412 100644 --- a/doc/html/objectify.html +++ b/doc/html/objectify.html @@ -2,7 +2,7 @@ - + lxml.objectify @@ -25,7 +25,7 @@ function hide_menu() {
    -

    lxml.objectify

    +

    lxml.objectify

    @@ -100,20 +100,20 @@ behind the usual object attribute access pattern. Asking an element for an attribute will return the sequence of children with corresponding tag names:

    >>> root = objectify.Element("root")
     >>> b = objectify.SubElement(root, "b")
    ->>> print(root.b[0].tag)
    +>>> print(root.b[0].tag)
     b
     >>> root.index(root.b[0])
     0
     >>> b = objectify.SubElement(root, "b")
    ->>> print(root.b[0].tag)
    +>>> print(root.b[0].tag)
     b
    ->>> print(root.b[1].tag)
    +>>> print(root.b[1].tag)
     b
     >>> root.index(root.b[1])
     1
     

    For convenience, you can omit the index '0' to access the first child:

    -
    >>> print(root.b.tag)
    +
    >>> print(root.b.tag)
     b
     >>> root.index(root.b)
     0
    @@ -151,11 +151,11 @@ methods for iteration, it supports an optional tag keyword argument:

    XML attributes are accessed as in the normal ElementTree API:

    >>> c = objectify.SubElement(root, "c", myattr="someval")
    ->>> print(root.c.get("myattr"))
    +>>> print(root.c.get("myattr"))
     someval
     
     >>> root.c.set("c", "oh-oh")
    ->>> print(root.c.get("c"))
    +>>> print(root.c.get("c"))
     oh-oh
     

    In addition to the normal ElementTree API for appending elements to trees, @@ -164,9 +164,9 @@ case, the subtree is automatically deep copied and the tag name of its root is updated to match the attribute name:

    >>> el = objectify.Element("yet_another_child")
     >>> root.new_child = el
    ->>> print(root.new_child.tag)
    +>>> print(root.new_child.tag)
     new_child
    ->>> print(el.tag)
    +>>> print(el.tag)
     yet_another_child
     
     >>> root.y = [ objectify.Element("y"), objectify.Element("y") ]
    @@ -187,22 +187,22 @@ updated to match the attribute name:

    >>> subel = objectify.SubElement(el, "sub") >>> root.child = el ->>> print(root.child.sub.tag) +>>> print(root.child.sub.tag) sub >>> root.child[2] = el ->>> print(root.child[2].sub.tag) +>>> print(root.child[2].sub.tag) sub

    Note that special care must be taken when changing the tag name of an element:

    -
    >>> print(root.b.tag)
    +
    >>> print(root.b.tag)
     b
     >>> root.b.tag = "notB"
     >>> root.b
     Traceback (most recent call last):
       ...
     AttributeError: no such child: b
    ->>> print(root.notB.tag)
    +>>> print(root.notB.tag)
     notB
     
    @@ -215,17 +215,17 @@ the module:

    >>> fileobject = StringIO('<test/>')
     
     >>> tree = objectify.parse(fileobject)
    ->>> print(isinstance(tree.getroot(), objectify.ObjectifiedElement))
    +>>> print(isinstance(tree.getroot(), objectify.ObjectifiedElement))
     True
     
     >>> root = objectify.fromstring('<test/>')
    ->>> print(isinstance(root, objectify.ObjectifiedElement))
    +>>> print(isinstance(root, objectify.ObjectifiedElement))
     True
     

    To build a new tree in memory, objectify replicates the standard factory function Element() from lxml.etree:

    >>> obj_el = objectify.Element("new")
    ->>> print(isinstance(obj_el, objectify.ObjectifiedElement))
    +>>> print(isinstance(obj_el, objectify.ObjectifiedElement))
     True
     

    After creating such an Element, you can use the usual API of @@ -237,11 +237,11 @@ from their tree. However, all independent elements that you create through the Element() factory of lxml.etree (instead of objectify) will not support the objectify API by themselves:

    >>> subel = objectify.SubElement(obj_el, "sub")
    ->>> print(isinstance(subel, objectify.ObjectifiedElement))
    +>>> print(isinstance(subel, objectify.ObjectifiedElement))
     True
     
     >>> independent_el = etree.Element("new")
    ->>> print(isinstance(independent_el, objectify.ObjectifiedElement))
    +>>> print(isinstance(independent_el, objectify.ObjectifiedElement))
     False
     
    @@ -252,11 +252,11 @@ will not support the objectify API by themselv >>> root=E.root(... E.a(5),... E.b(6.21), -... E.c(True), +... E.c(True),... E.d("how",tell="me")... ) ->>> print(etree.tostring(root,pretty_print=True)) +>>> print(etree.tostring(root,pretty_print=True))<root xmlns:py="http://codespeak.net/lxml/objectify/pytype"> <a py:pytype="int">5</a> <b py:pytype="float">6.21</b> @@ -274,7 +274,7 @@ will not support the objectify API by themselv ... HOWMANY(5)... ) ->>> print(etree.tostring(root,pretty_print=True)) +>>> print(etree.tostring(root,pretty_print=True))<root xmlns:py="http://codespeak.net/lxml/objectify/pytype"> <title py:pytype="str">The title</title> <how-many py:pytype="int">5</how-many> @@ -284,12 +284,12 @@ will not support the objectify API by themselv creates pytype annotated Elements without a namespace. You can switch off the pytype annotation by passing False to the annotate keyword argument of the constructor. You can also pass a default namespace and an nsmap:

    -
    >>> myE = objectify.ElementMaker(annotate=False,
    -...           namespace="http://my/ns", nsmap={None : "http://my/ns"})
    +
    >>> myE = objectify.ElementMaker(annotate=False,
    +...           namespace="http://my/ns", nsmap={None : "http://my/ns"})
     
     >>> root = myE.root( myE.someint(2) )
     
    ->>> print(etree.tostring(root, pretty_print=True))
    +>>> print(etree.tostring(root, pretty_print=True))
     <root xmlns="http://my/ns">
       <someint>2</someint>
     </root>
    @@ -304,7 +304,7 @@ the lookup will use the namespace of the parent:

    >>> b = objectify.SubElement(root, "{http://ns/}b") >>> c = objectify.SubElement(root, "{http://other/}c") ->>> print(root.b.tag) +>>> print(root.b.tag) {http://ns/}b

    Note that the SubElement() factory of lxml.etree does not @@ -312,10 +312,10 @@ inherit any namespaces when creating a new subelement. Element creation must be explicit about the namespace, and is simplified through the E-factory as described above.

    Lookups, however, inherit namespaces implicitly:

    -
    >>> print(root.b.tag)
    +
    >>> print(root.b.tag)
     {http://ns/}b
     
    ->>> print(root.c)
    +>>> print(root.c)
     Traceback (most recent call last):
         ...
     AttributeError: no such child: {http://ns/}c
    @@ -323,18 +323,18 @@ through the E-factory as described above.

    To access an element in a different namespace than its parent, you can use getattr():

    >>> c = getattr(root, "{http://other/}c")
    ->>> print(c.tag)
    +>>> print(c.tag)
     {http://other/}c
     

    For convenience, there is also a quick way through item access:

    >>> c = root["{http://other/}c"]
    ->>> print(c.tag)
    +>>> print(c.tag)
     {http://other/}c
     

    The same approach must be used to access children with tag names that are not valid Python identifiers:

    >>> el = objectify.SubElement(root, "{http://ns/}tag-name")
    ->>> print(root["tag-name"].tag)
    +>>> print(root["tag-name"].tag)
     {http://ns/}tag-name
     
     >>> new_el = objectify.Element("{http://ns/}new-element")
    @@ -343,27 +343,27 @@ valid Python identifiers:

    >>> el = objectify.SubElement(new_el, "{http://ns/}child") >>> root["tag-name"] = [ new_el, new_el ] ->>> print(len(root["tag-name"])) +>>> print(len(root["tag-name"])) 2 ->>> print(root["tag-name"].tag) +>>> print(root["tag-name"].tag) {http://ns/}tag-name ->>> print(len(root["tag-name"].child)) +>>> print(len(root["tag-name"].child)) 3 ->>> print(root["tag-name"].child.tag) +>>> print(root["tag-name"].child.tag) {http://ns/}child ->>> print(root["tag-name"][1].child.tag) +>>> print(root["tag-name"][1].child.tag) {http://ns/}child

    or for names that have a special meaning in lxml.objectify:

    >>> root = objectify.XML("<root><text>TEXT</text></root>")
     
    ->>> print(root.text.text)
    +>>> print(root.text.text)
     Traceback (most recent call last):
       ...
     AttributeError: 'NoneType' object has no attribute 'text'
     
    ->>> print(root["text"].text)
    +>>> print(root["text"].text)
     TEXT
     
    @@ -389,7 +389,7 @@ parse the schema from a file-like object (or file or filename):

    ... </xsd:complexType> ... </xsd:schema> ... ''') ->>> schema = etree.XMLSchema(file=f) +>>> schema = etree.XMLSchema(file=f)

    When creating the validating parser, we must make sure it returns objectify trees. This is best done with the makeparser() @@ -400,7 +400,7 @@ function:

    >>> xml = "<a><b>test</b></a>"
     >>> a = objectify.fromstring(xml, parser)
     
    ->>> print(a.b)
    +>>> print(a.b)
     test
     

    Or an invalid document:

    @@ -423,75 +423,75 @@ represented by the ObjectPath class:

    >>> d = objectify.SubElement(root, "{http://other/}d") >>> path = objectify.ObjectPath("root.b.c") ->>> print(path) +>>> print(path) root.b.c >>> path.hasattr(root) True ->>> print(path.find(root).tag) +>>> print(path.find(root).tag) {http://ns/}c >>> find = objectify.ObjectPath("root.b.c") ->>> print(find(root).tag) +>>> print(find(root).tag) {http://ns/}c >>> find = objectify.ObjectPath("root.{http://other/}d") ->>> print(find(root).tag) +>>> print(find(root).tag) {http://other/}d ->>> find = objectify.ObjectPath("root.{not}there") ->>> print(find(root).tag) +>>> find = objectify.ObjectPath("root.{not}there") +>>> print(find(root).tag) Traceback (most recent call last): ... AttributeError: no such child: {not}there ->>> find = objectify.ObjectPath("{not}there") ->>> print(find(root).tag) +>>> find = objectify.ObjectPath("{not}there") +>>> print(find(root).tag) Traceback (most recent call last): ... ValueError: root element does not match: need {not}there, got {http://ns/}root >>> find = objectify.ObjectPath("root.b[1]") ->>> print(find(root).tag) +>>> print(find(root).tag) {http://ns/}b >>> find = objectify.ObjectPath("root.{http://ns/}b[1]") ->>> print(find(root).tag) +>>> print(find(root).tag) {http://ns/}b

    Apart from strings, ObjectPath also accepts lists of path segments:

    >>> find = objectify.ObjectPath(['root', 'b', 'c'])
    ->>> print(find(root).tag)
    +>>> print(find(root).tag)
     {http://ns/}c
     
     >>> find = objectify.ObjectPath(['root', '{http://ns/}b[1]'])
    ->>> print(find(root).tag)
    +>>> print(find(root).tag)
     {http://ns/}b
     

    You can also use relative paths starting with a '.' to ignore the actual root element and only inherit its namespace:

    >>> find = objectify.ObjectPath(".b[1]")
    ->>> print(find(root).tag)
    +>>> print(find(root).tag)
     {http://ns/}b
     
     >>> find = objectify.ObjectPath(['', 'b[1]'])
    ->>> print(find(root).tag)
    +>>> print(find(root).tag)
     {http://ns/}b
     
     >>> find = objectify.ObjectPath(".unknown[1]")
    ->>> print(find(root).tag)
    +>>> print(find(root).tag)
     Traceback (most recent call last):
       ...
     AttributeError: no such child: {http://ns/}unknown
     
     >>> find = objectify.ObjectPath(".{http://other/}unknown[1]")
    ->>> print(find(root).tag)
    +>>> print(find(root).tag)
     Traceback (most recent call last):
       ...
     AttributeError: no such child: {http://other/}unknown
     

    For convenience, a single dot represents the empty ObjectPath (identity):

    >>> find = objectify.ObjectPath(".")
    ->>> print(find(root).tag)
    +>>> print(find(root).tag)
     {http://ns/}root
     

    ObjectPath objects can be used to manipulate trees:

    @@ -508,15 +508,15 @@ element and only inherit its namespace:

    >>> path.setattr(root,"my value")# creates children as necessary>>> path.hasattr(root)True ->>> print(path.find(root).text) +>>> print(path.find(root).text)my value ->>> print(root.some.child["{http://other/}unknown"].text) +>>> print(root.some.child["{http://other/}unknown"].text)my value ->>> print(len(path.find(root))) +>>> print(len(path.find(root)))1>>> path.addattr(root,"my new value") ->>> print(len(path.find(root))) +>>> print(len(path.find(root)))2>>> [el.textforelinpath.find(root)]['my value', 'my new value'] @@ -529,7 +529,7 @@ element and only inherit its namespace:

    Note, however, that indexing is only supported in this context if the children exist. Indexing of non existing children will not extend or create a list of such children but raise an exception:

    -
    >>> path = objectify.ObjectPath(".{non}existing[1]")
    +
    >>> path = objectify.ObjectPath(".{non}existing[1]")
     >>> path.setattr(root, "my value")
     Traceback (most recent call last):
       ...
    @@ -549,26 +549,26 @@ operators:

    >>> root.a + root.b 16 >>> root.a += root.b ->>> print(root.a) +>>> print(root.a) 16 >>> root.a = 2 ->>> print(root.a + 2) +>>> print(root.a + 2) 4 ->>> print(1 + root.a) +>>> print(1 + root.a) 3 ->>> print(root.c) +>>> print(root.c) True ->>> root.c = False +>>> root.c = False >>> if not root.c: -... print("false!") +... print("false!") false! ->>> print(root.d + " test !") +>>> print(root.d + " test !") hoi test ! >>> root.d = "%s - %s" ->>> print(root.d % (1234, 12345)) +>>> print(root.d % (1234, 12345)) 1234 - 12345

    However, data elements continue to provide the objectify API. This means that @@ -576,16 +576,16 @@ sequence operations such as len(), slicing and cannot behave as the Python types. Like all other tree elements, they show the normal slicing behaviour of objectify elements:

    >>> root = objectify.fromstring("<root><a>test</a><b>toast</b></root>")
    ->>> print(root.a + ' me') # behaves like a string, right?
    +>>> print(root.a + ' me') # behaves like a string, right?
     test me
     >>> len(root.a) # but there's only one 'a' element!
     1
     >>> [ a.tag for a in root.a ]
     ['a']
    ->>> print(root.a[0].tag)
    +>>> print(root.a[0].tag)
     a
     
    ->>> print(root.a)
    +>>> print(root.a)
     test
     >>> [ str(a) for a in root.a[:1] ]
     ['test']
    @@ -618,9 +618,9 @@ to change values, just assign them directly to the attribute:

    TypeError: attribute 'pyval' of 'StringElement' objects is not writable >>> root.a = 25 ->>> print(root.a) +>>> print(root.a) 25 ->>> print(root.a.pyval) +>>> print(root.a.pyval) 25

    In other words, objectify data elements behave like immutable Python @@ -641,7 +641,7 @@ elements:

    ... </root> ... """) ->>> print(objectify.dump(root)) +>>> print(objectify.dump(root)) root = None [ObjectifiedElement] a = 1 [IntElement] * attr1 = 'foo' @@ -655,24 +655,24 @@ elements:

    You can freely switch between different types for the same child:

    >>> root = objectify.fromstring("<root><a>5</a></root>")
    ->>> print(objectify.dump(root))
    +>>> print(objectify.dump(root))
     root = None [ObjectifiedElement]
         a = 5 [IntElement]
     
     >>> root.a = 'nice string!'
    ->>> print(objectify.dump(root))
    +>>> print(objectify.dump(root))
     root = None [ObjectifiedElement]
         a = 'nice string!' [StringElement]
           * py:pytype = 'str'
     
    ->>> root.a = True
    ->>> print(objectify.dump(root))
    +>>> root.a = True
    +>>> print(objectify.dump(root))
     root = None [ObjectifiedElement]
         a = True [BoolElement]
           * py:pytype = 'bool'
     
     >>> root.a = [1, 2, 3]
    ->>> print(objectify.dump(root))
    +>>> print(objectify.dump(root))
     root = None [ObjectifiedElement]
         a = 1 [IntElement]
           * py:pytype = 'int'
    @@ -682,7 +682,7 @@ elements:

    * py:pytype = 'int' >>> root.a = (1, 2, 3) ->>> print(objectify.dump(root)) +>>> print(objectify.dump(root)) root = None [ObjectifiedElement] a = 1 [IntElement] * py:pytype = 'int' @@ -710,7 +710,7 @@ objectify elements like this:

    ... </root> ... """) ->>> print(str(root)) +>>> print(str(root)) root = None [ObjectifiedElement] a = 1 [IntElement] * attr1 = 'foo' @@ -723,7 +723,7 @@ objectify elements like this:

    * xsi:nil = 'true'

    This behaviour can be switched off in the same way:

    -
    >>> objectify.enable_recursive_str(False)
    +
    >>> objectify.enable_recursive_str(False)
     
    @@ -759,7 +759,7 @@ classes used in these cases. By default, tree_clas

    The "type hint" mechanism deploys an XML attribute defined as lxml.objectify.PYTYPE_ATTRIBUTE. It may contain any of the following string values: int, long, float, str, unicode, NoneType:

    -
    >>> print(objectify.PYTYPE_ATTRIBUTE)
    +
    >>> print(objectify.PYTYPE_ATTRIBUTE)
     {http://codespeak.net/lxml/objectify/pytype}pytype
     >>> ns, name = objectify.PYTYPE_ATTRIBUTE[1:].split('}')
     
    @@ -771,11 +771,11 @@ string values: int, long, float, str, unicode, NoneType:

    ... </root> ... """ % ns) ->>> print(root.a + 10) +>>> print(root.a + 10) 510 ->>> print(root.b + 10) +>>> print(root.b + 10) 15 ->>> print(root.c) +>>> print(root.c) None

    Note that you can change the name and namespace used for this @@ -784,14 +784,14 @@ function, in case your application ever needs to. There is also a utility function annotate() that recursively generates this attribute for the elements of a tree:

    >>> root = objectify.fromstring("<root><a>test</a><b>5</b></root>")
    ->>> print(objectify.dump(root))
    +>>> print(objectify.dump(root))
     root = None [ObjectifiedElement]
         a = 'test' [StringElement]
         b = 5 [IntElement]
     
     >>> objectify.annotate(root)
     
    ->>> print(objectify.dump(root))
    +>>> print(objectify.dump(root))
     root = None [ObjectifiedElement]
         a = 'test' [StringElement]
           * py:pytype = 'str'
    @@ -812,7 +812,7 @@ Python types:

    ... <s xsi:type="xsd:string">5</s> ... </root> ... ''') ->>> print(objectify.dump(root)) +>>> print(objectify.dump(root)) root = None [ObjectifiedElement] d = 5.0 [FloatElement] * xsi:type = 'xsd:double' @@ -826,7 +826,7 @@ generates the "xsi:type" attribute for the elements of a tree:

    >>> root = objectify.fromstring('''\
     ...    <root><a>test</a><b>5</b><c>true</c></root>
     ...    ''')
    ->>> print(objectify.dump(root))
    +>>> print(objectify.dump(root))
     root = None [ObjectifiedElement]
         a = 'test' [StringElement]
         b = 5 [IntElement]
    @@ -834,7 +834,7 @@ generates the "xsi:type" attribute for the elements of a tree:

    >>> objectify.xsiannotate(root) ->>> print(objectify.dump(root)) +>>> print(objectify.dump(root)) root = None [ObjectifiedElement] a = 'test' [StringElement] * xsi:type = 'xsd:string' @@ -856,7 +856,7 @@ and/or 'xsi:type' information:

    ... <s xsi:type="xsd:string">5</s> ... </root>''') >>> objectify.annotate(root) ->>> print(objectify.dump(root)) +>>> print(objectify.dump(root)) root = None [ObjectifiedElement] d = 5.0 [FloatElement] * py:pytype = 'float' @@ -868,7 +868,7 @@ and/or 'xsi:type' information:

    * py:pytype = 'str' * xsi:type = 'xsd:string' >>> objectify.deannotate(root) ->>> print(objectify.dump(root)) +>>> print(objectify.dump(root)) root = None [ObjectifiedElement] d = 5 [IntElement] i = 5 [IntElement] @@ -887,7 +887,7 @@ arguments 'pytype' (default: True) and 'xsi' (default: True). ... <n xsi:nil="true"/> ... </root>''') >>> objectify.annotate(root) ->>> print(objectify.dump(root)) +>>> print(objectify.dump(root)) root = None [ObjectifiedElement] d = 5.0 [FloatElement] * py:pytype = 'float' @@ -901,8 +901,8 @@ arguments 'pytype' (default: True) and 'xsi' (default: True). n = None [NoneElement] * py:pytype = 'NoneType' * xsi:nil = 'true' ->>> objectify.deannotate(root, xsi_nil=True) ->>> print(objectify.dump(root)) +>>> objectify.deannotate(root, xsi_nil=True) +>>> print(objectify.dump(root)) root = None [ObjectifiedElement] d = 5 [IntElement] i = 5 [IntElement] @@ -924,20 +924,20 @@ Python value in one step. You can pass the required Python type name or the XSI type name:

    >>> root = objectify.Element("root")
     >>> root.x = objectify.DataElement(5, _pytype="int")
    ->>> print(objectify.dump(root))
    +>>> print(objectify.dump(root))
     root = None [ObjectifiedElement]
         x = 5 [IntElement]
           * py:pytype = 'int'
     
     >>> root.x = objectify.DataElement(5, _pytype="str", myattr="someval")
    ->>> print(objectify.dump(root))
    +>>> print(objectify.dump(root))
     root = None [ObjectifiedElement]
         x = '5' [StringElement]
           * myattr = 'someval'
           * py:pytype = 'str'
     
     >>> root.x = objectify.DataElement(5, _xsi="integer")
    ->>> print(objectify.dump(root))
    +>>> print(objectify.dump(root))
     root = None [ObjectifiedElement]
         x = 5 [IntElement]
           * py:pytype = 'int'
    @@ -948,8 +948,8 @@ tries to correctly prefix the xsi:type attribute value for you:

    >>> root = objectify.Element("root")
     >>> root.s = objectify.DataElement(5, _xsi="string")
     
    ->>> objectify.deannotate(root, xsi=False)
    ->>> print(etree.tostring(root, pretty_print=True))
    +>>> objectify.deannotate(root, xsi=False)
    +>>> print(etree.tostring(root, pretty_print=True))
     <root xmlns:py="http://codespeak.net/lxml/objectify/pytype" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
       <s xsi:type="xsd:string">5</s>
     </root>
    @@ -959,12 +959,12 @@ tries to correctly prefix the xsi:type attribute value for you:

    >>> namespaces = list(el.nsmap.items()) >>> namespaces.sort() >>> for prefix, namespace in namespaces: -... print("%s - %s" % (prefix, namespace)) +... print("%s - %s" % (prefix, namespace)) py - http://codespeak.net/lxml/objectify/pytype xsd - http://www.w3.org/2001/XMLSchema xsi - http://www.w3.org/2001/XMLSchema-instance ->>> print(el.get("{http://www.w3.org/2001/XMLSchema-instance}type")) +>>> print(el.get("{http://www.w3.org/2001/XMLSchema-instance}type")) xsd:string

    While you can set custom namespace prefixes, it is necessary to provide valid @@ -974,12 +974,12 @@ namespace information if you choose to do so:

    >>> namespaces = list(el.nsmap.items()) >>> namespaces.sort() >>> for prefix, namespace in namespaces: -... print("%s - %s" % (prefix, namespace)) +... print("%s - %s" % (prefix, namespace)) foo - http://www.w3.org/2001/XMLSchema py - http://codespeak.net/lxml/objectify/pytype xsi - http://www.w3.org/2001/XMLSchema-instance ->>> print(el.get("{http://www.w3.org/2001/XMLSchema-instance}type")) +>>> print(el.get("{http://www.w3.org/2001/XMLSchema-instance}type")) foo:string

    Note how lxml chose a default prefix for the XML Schema Instance @@ -990,12 +990,12 @@ namespace. We can override it as in the following example:

    >>> namespaces = list(el.nsmap.items()) >>> namespaces.sort() >>> for prefix, namespace in namespaces: -... print("%s - %s" % (prefix, namespace)) +... print("%s - %s" % (prefix, namespace)) foo - http://www.w3.org/2001/XMLSchema myxsi - http://www.w3.org/2001/XMLSchema-instance py - http://codespeak.net/lxml/objectify/pytype ->>> print(el.get("{http://www.w3.org/2001/XMLSchema-instance}type")) +>>> print(el.get("{http://www.w3.org/2001/XMLSchema-instance}type")) foo:string

    Care must be taken if different namespace prefixes have been used for the same @@ -1003,15 +1003,15 @@ namespace. Namespace information gets merged to avoid duplicate definitions when adding a new sub-element to a tree, but this mechanism does not adapt the prefixes of attribute values:

    >>> root = objectify.fromstring("""<root xmlns:schema="http://www.w3.org/2001/XMLSchema"/>""")
    ->>> print(etree.tostring(root, pretty_print=True))
    +>>> print(etree.tostring(root, pretty_print=True))
     <root xmlns:schema="http://www.w3.org/2001/XMLSchema"/>
     
     >>> s = objectify.DataElement("17", _xsi="string")
    ->>> print(etree.tostring(s, pretty_print=True))
    +>>> print(etree.tostring(s, pretty_print=True))
     <value xmlns:py="http://codespeak.net/lxml/objectify/pytype" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" py:pytype="str" xsi:type="xsd:string">17</value>
     
     >>> root.s = s
    ->>> print(etree.tostring(root, pretty_print=True))
    +>>> print(etree.tostring(root, pretty_print=True))
     <root xmlns:schema="http://www.w3.org/2001/XMLSchema">
       <s xmlns:py="http://codespeak.net/lxml/objectify/pytype" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" py:pytype="str" xsi:type="xsd:string">17</s>
     </root>
    @@ -1020,7 +1020,7 @@ prefixes of attribute values:

    choose to deviate from the standard prefixes. A convenient way to do this for xsi:type attributes is to use the xsiannotate() utility:

    >>> objectify.xsiannotate(root)
    ->>> print(etree.tostring(root, pretty_print=True))
    +>>> print(etree.tostring(root, pretty_print=True))
     <root xmlns:schema="http://www.w3.org/2001/XMLSchema">
       <s xmlns:py="http://codespeak.net/lxml/objectify/pytype" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" py:pytype="str" xsi:type="schema:string">17</s>
     </root>
    @@ -1040,7 +1040,7 @@ call should be placed into the element _init()
     

    The registration of data classes uses the PyType class:

    >>> class ChristmasDate(objectify.ObjectifiedDataElement):
     ...     def call_santa(self):
    -...         print("Ho ho ho!")
    +...         print("Ho ho ho!")
     
     >>> def checkChristmasDate(date_string):
     ...     if not date_string.startswith('24.12.'):
    @@ -1088,7 +1088,7 @@ function defined above:

    ... <a xsi:type="date">12.24.2000</a> ... </root> ... ''') ->>> print(root.a) +>>> print(root.a) 12.24.2000 >>> root.a.call_santa() Ho ho ho! @@ -1122,10 +1122,10 @@ this alters the document infoset, so if you consider the removed spaces as data in your specific use case, you should go with a normal parser and just set the element class lookup. Most applications, however, will work fine with the following setup:

    -
    >>> parser = objectify.makeparser(remove_blank_text=True)
    +
    >>> parser = objectify.makeparser(remove_blank_text=True)
     

    What this does internally, is:

    -
    >>> parser = etree.XMLParser(remove_blank_text=True)
    +
    >>> parser = etree.XMLParser(remove_blank_text=True)
     
     >>> lookup = objectify.ObjectifyElementClassLookup()
     >>> parser.set_element_class_lookup(lookup)
    @@ -1165,7 +1165,7 @@ support any XPath expression.
     
    diff --git a/doc/html/parsing.html b/doc/html/parsing.html index b4600bb..8d49b2e 100644 --- a/doc/html/parsing.html +++ b/doc/html/parsing.html @@ -2,7 +2,7 @@ - + Parsing XML and HTML with lxml
    -

    Parsing XML and HTML with lxml

    +

    Parsing XML and HTML with lxml

    lxml provides a very simple and powerful API for parsing XML and HTML. It supports one-step parsing as well as step-by-step parsing using an @@ -100,7 +100,7 @@ keyword argument:

    Parser options

    The parsers accept a number of setup options as keyword arguments. The above example is easily extended to clean up namespaces during parsing:

    -
    >>> parser = etree.XMLParser(ns_clean=True)
    +
    >>> parser = etree.XMLParser(ns_clean=True)
     >>> tree   = etree.parse(StringIO(xml), parser)
     >>> etree.tostring(tree.getroot())
     b'<a xmlns="test"><b/></a>'
    @@ -147,7 +147,7 @@ different IDs if the hash lookup is not used afterwards.
     

    Parsers have an error_log property that lists the errors and warnings of the last parser run:

    >>> parser = etree.XMLParser()
    ->>> print(len(parser.error_log))
    +>>> print(len(parser.error_log))
     0
     
     >>> tree = etree.XML("<root>\n</b>", parser)  # doctest: +ELLIPSIS
    @@ -155,15 +155,15 @@ warnings of the last parser run:

    ... lxml.etree.XMLSyntaxError: Opening and ending tag mismatch: root line 1 and b, line 2, column 5... ->>> print(len(parser.error_log)) +>>> print(len(parser.error_log)) 1 >>> error = parser.error_log[0] ->>> print(error.message) +>>> print(error.message) Opening and ending tag mismatch: root line 1 and b ->>> print(error.line) +>>> print(error.line) 2 ->>> print(error.column) +>>> print(error.column) 5

    Each entry in the log has the following properties:

    @@ -201,8 +201,8 @@ this feature.

    >>> tree = etree.parse(StringIO(broken_html), parser) >>> result = etree.tostring(tree.getroot(), -... pretty_print=True, method="html") ->>> print(result) +... pretty_print=True, method="html") +>>> print(result) <html> <head> <title>test</title> @@ -215,8 +215,8 @@ this feature.

    Lxml has an HTML function, similar to the XML shortcut known from ElementTree:

    >>> html = etree.HTML(broken_html)
    ->>> result = etree.tostring(html, pretty_print=True, method="html")
    ->>> print(result)
    +>>> result = etree.tostring(html, pretty_print=True, method="html")
    +>>> print(result)
     <html>
       <head>
         <title>test</title>
    @@ -256,21 +256,21 @@ original encoding.  Since lxml 3.5, the doctype references are mutable.

    >>> tree = etree.parse(StringIO(xhtml)) >>> docinfo = tree.docinfo ->>> print(docinfo.public_id) +>>> print(docinfo.public_id) -//W3C//DTD XHTML 1.0 Transitional//EN ->>> print(docinfo.system_url) +>>> print(docinfo.system_url) http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd >>> docinfo.doctype == doctype_string True ->>> print(docinfo.xml_version) +>>> print(docinfo.xml_version) 1.0 ->>> print(docinfo.encoding) +>>> print(docinfo.encoding) ascii ->>> docinfo.system_url = None ->>> docinfo.public_id = None ->>> print(etree.tostring(tree)) +>>> docinfo.system_url = None +>>> docinfo.public_id = None +>>> print(etree.tostring(tree)) <!DOCTYPE html> <html><body/></html>
    @@ -282,15 +282,15 @@ original encoding. Since lxml 3.5, the doctype references are mutable.

    a target object to the parser:

    >>> class EchoTarget(object):
     ...     def start(self, tag, attrib):
    -...         print("start %s %r" % (tag, dict(attrib)))
    +...         print("start %s %r" % (tag, dict(attrib)))
     ...     def end(self, tag):
    -...         print("end %s" % tag)
    +...         print("end %s" % tag)
     ...     def data(self, data):
    -...         print("data %r" % data)
    +...         print("data %r" % data)
     ...     def comment(self, text):
    -...         print("comment %s" % text)
    +...         print("comment %s" % text)
     ...     def close(self):
    -...         print("close")
    +...         print("close")
     ...         return "closed!"
     
     >>> parser = etree.XMLParser(target = EchoTarget())
    @@ -304,7 +304,7 @@ a target object to the parser:

    end element close ->>> print(result) +>>> print(result) closed!

    It is important for the .close() method to reset the parser target @@ -319,7 +319,7 @@ like:

    end element close ->>> print(result) +>>> print(result) closed!

    Starting with lxml 2.3, the .close() method will also be called in @@ -350,7 +350,7 @@ that the parser can reuse them afterwards.

    lxml.etree.XMLSyntaxError: Opening and ending tag mismatch... >>> for event in parser.target.events: -... print(event) +... print(event) start element {} data u'some' close @@ -366,9 +366,9 @@ object. An example for a parser target that builds a tree is the >>> result = etree.XML("<element>some<!--comment-->text</element>", ... parser) ->>> print(result.tag) +>>> print(result.tag) element ->>> print(result[0].text) +>>> print(result[0].text) comment
    @@ -393,9 +393,9 @@ retrieve the root Element of the parse result document, and to unlock the parser:

    >>> root = parser.close()
     
    ->>> print(root.tag)
    +>>> print(root.tag)
     root
    ->>> print(root[0].tag)
    +>>> print(root[0].tag)
     a
     

    If you do not call close(), the parser will stay locked and @@ -422,7 +422,7 @@ normal error_log and vice versa.

    >>> result = parser.close() close ->>> print(result) +>>> print(result) closed!

    Again, this prevents the automatic creation of an XML tree and leaves @@ -444,7 +444,7 @@ processed as far as possible in each step.

    >>> def print_events(parser): ... for action, element in parser.read_events(): -... print('%s: %s' % (action, element.tag)) +... print('%s: %s' % (action, element.tag)) >>> parser.feed('<root>some text') >>> print_events(parser) @@ -498,11 +498,11 @@ stack and pop the last entry on the 'end-ns' event.

    >>> def print_events(events):
     ...     for action, obj in events:
     ...         if action in ('start', 'end'):
    -...             print("%s: %s" % (action, obj.tag))
    +...             print("%s: %s" % (action, obj.tag))
     ...         elif action == 'start-ns':
    -...             print("%s: %s" % (action, obj))
    +...             print("%s: %s" % (action, obj))
     ...         else:
    -...             print(action)
    +...             print(action)
     
     >>> event_types = ("start", "end", "start-ns", "end-ns")
     >>> parser = etree.XMLPullParser(event_types)
    @@ -539,15 +539,15 @@ that are no longer needed:

    >>> parser.feed('<root><element key="value">text</element>') >>> parser.feed('<element><child /></element>') >>> for action, elem in events: -... print('%s: %d' % (elem.tag, len(elem))) # processing -... elem.clear(keep_tail=True) # delete children +... print('%s: %d' % (elem.tag, len(elem))) # processing +... elem.clear(keep_tail=True) # delete children element: 0 child: 0 element: 1 >>> parser.feed('<empty-element xmlns="http://testns/" /></root>') >>> for action, elem in events: -... print('%s: %d' % (elem.tag, len(elem))) # processing -... elem.clear(keep_tail=True) # delete children +... print('%s: %d' % (elem.tag, len(elem))) # processing +... elem.clear(keep_tail=True) # delete children {http://testns/}empty-element: 0 root: 3 @@ -570,8 +570,8 @@ to save more memory during parsing, you can clean up the preceding siblings of the current element:

    >>> for event, element in parser.read_events():
     ...     # ... do something with the element
    -...     element.clear(keep_tail=True)   # clean up children
    -...     while element.getprevious() is not None:
    +...     element.clear(keep_tail=True)   # clean up children
    +...     while element.getprevious() is not None:
     ...         del element.getparent()[0]  # clean up preceding siblings
     

    The while loop deletes multiple siblings in a row. This is only necessary @@ -594,7 +594,7 @@ specific tag or namespace:

    >>> parser.feed('<empty-element xmlns="http://testns/" /></root>') >>> for action, elem in parser.read_events(): -... print("%s: %s" % (action, elem.tag)) +... print("%s: %s" % (action, elem.tag)) end: element end: element @@ -606,7 +606,7 @@ specific tag or namespace:

    >>> parser.feed('<empty-element xmlns="http://testns/" /></root>') >>> for action, elem in parser.read_events(): -... print("%s: %s" % (action, elem.tag)) +... print("%s: %s" % (action, elem.tag)) start: {http://testns/}empty-element end: {http://testns/}empty-element
    @@ -628,11 +628,11 @@ XML structures.

    >>> for action, elem in parser.read_events(): ... if action in ('start', 'end'): -... print("%s: %s" % (action, elem.tag)) +... print("%s: %s" % (action, elem.tag)) ... elif action == 'pi': -... print("%s: -%s=%s-" % (action, elem.target, elem.text)) +... print("%s: -%s=%s-" % (action, elem.target, elem.text)) ... else: # 'comment' -... print("%s: -%s-" % (action, elem.text)) +... print("%s: -%s-" % (action, elem.text)) pi: -some=pi - comment: - a comment - start: root @@ -646,7 +646,7 @@ XML structures.

    end: root >>> root = parser.close() ->>> print(root.tag) +>>> print(root.tag) root
    @@ -658,13 +658,13 @@ it returns from its .start() and
    >>> class Target(object):
     ...     def start(self, tag, attrib):
    -...         print('-> start(%s)' % tag)
    +...         print('-> start(%s)' % tag)
     ...         return '>>START: %s<<' % tag
     ...     def end(self, tag):
    -...         print('-> end(%s)' % tag)
    +...         print('-> end(%s)' % tag)
     ...         return '>>END: %s<<' % tag
     ...     def close(self):
    -...         print('-> close()')
    +...         print('-> close()')
     ...         return "CLOSED!"
     
     >>> event_types = ('start', 'end')
    @@ -679,7 +679,7 @@ by the pull parser as the second item of the parse events tuple.

    -> end(root) >>> for action, value in parser.read_events(): -... print('%s: %s' % (action, value)) +... print('%s: %s' % (action, value)) start: >>START: root<< start: >>START: child1<< end: >>END: child1<< @@ -687,7 +687,7 @@ by the pull parser as the second item of the parse events tuple.

    end: >>END: child2<< end: >>END: root<< ->>> print(parser.close()) +>>> print(parser.close()) -> close() CLOSED!
    @@ -711,7 +711,7 @@ filters attributes before they are being added to the tree:

    >>> parser.feed('<root><child1 test="123" /><child2 evil="YES" /></root>') >>> for action, element in parser.read_events(): -... print('%s: %s(%r)' % (action, element.tag, element.attrib)) +... print('%s: %s(%r)' % (action, element.tag, element.attrib)) end: child1({'test': '123'}) end: child2({}) end: root({}) @@ -738,7 +738,7 @@ single iterator for them:

    >>> context = etree.iterparse(StringIO(xml)) >>> for action, elem in context: -... print("%s: %s" % (action, elem.tag)) +... print("%s: %s" % (action, elem.tag)) end: element end: element end: {http://testns/}empty-element @@ -753,7 +753,7 @@ of the iterator:

    >>> events = ("start", "end")
     >>> context = etree.iterparse(StringIO(xml), events=events)
     >>> for action, elem in context:
    -...     print("%s: %s" % (action, elem.tag))
    +...     print("%s: %s" % (action, elem.tag))
     start: root
     start: element
     end: element
    @@ -777,7 +777,7 @@ ElementTrees.  Here is an example for a tree parsed by ...             f, events=("start", "end"), tag="element")
     
     >>> for action, elem in context:
    -...     print("%s: %s" % (action, elem.tag))
    +...     print("%s: %s" % (action, elem.tag))
     start: element
     end: element
     start: element
    @@ -792,7 +792,7 @@ input again:

    ... root, events=("start", "end"), tag="element") >>> for action, elem in context: -... print("%s: %s" % (action, elem.tag)) +... print("%s: %s" % (action, elem.tag)) start: element end: element start: element @@ -811,7 +811,7 @@ iterator can be instructed to skip over an entire subtree with its >>> context = etree.iterwalk(root, events=("start", "end")) >>> for action, elem in context: -... print("%s: %s" % (action, elem.tag)) +... print("%s: %s" % (action, elem.tag)) ... if action == 'start' and elem.tag == 'a': ... context.skip_subtree() # ignore <b> start: root @@ -854,7 +854,7 @@ number of other byte encodings if asked for:

    >>> etree.tostring(root)
     b'<test> &#63697; + &#63698; </test>'
     
    ->>> etree.tostring(root, encoding='UTF-8', xml_declaration=False)
    +>>> etree.tostring(root, encoding='UTF-8', xml_declaration=False)
     b'<test> \xef\xa3\x91 + \xef\xa3\x92 </test>'
     

    As an extension, lxml.etree recognises the name 'unicode' as an argument @@ -893,7 +893,7 @@ with UTF-8 is also considerably faster in most cases.

    diff --git a/doc/html/performance.html b/doc/html/performance.html index 28f5456..5b66f92 100644 --- a/doc/html/performance.html +++ b/doc/html/performance.html @@ -2,7 +2,7 @@ - + Benchmarks and Speed @@ -27,7 +27,7 @@ function hide_menu() {
    -

    Benchmarks and Speed

    +

    Benchmarks and Speed

    @@ -109,18 +109,11 @@ benchmarking suite for all ElementTree implementations. New benchmarks are very easy to add as tiny test methods, so if you write a performance test for a specific part of the API yourself, please consider sending it to the lxml mailing list.

    -

    The timings presented below compare lxml 3.1.1 (with libxml2 2.9.0) to the +

    The timings presented below compare lxml 4.6.3 (with libxml2 2.9.10) to the latest released versions of ElementTree (with cElementTree as accelerator -module) in the standard library of CPython 3.3.0. They were run -single-threaded on a 2.9GHz 64bit double core Intel i7 machine under -Ubuntu Linux 12.10 (Quantal). The C libraries were compiled with the -same platform specific optimisation flags. The Python interpreter was -also manually compiled for the platform. Note that many of the following -ElementTree timings are therefore better than what a normal Python -installation with the standard library (c)ElementTree modules would yield. -Note also that CPython 2.7 and 3.2+ come with a newer ElementTree version, -so older Python installations will not perform as good for (c)ElementTree, -and sometimes substantially worse.

    +module) in the standard library of CPython 3.8.10. They were run +single-threaded on a 2.3GHz 64bit double core Intel i5 machine under +Ubuntu Linux 20.04 (Focal).

    The scripts run a number of simple tests on the different libraries, using different XML tree configurations: different tree sizes (T1-4), with or without attributes (-/A), with or without ASCII string or unicode text @@ -153,50 +146,50 @@ is native to libxml2. While 20 to 40 times faster than (c)ElementTree lxml is still more than 10 times as fast as the much improved ElementTree 1.3 in recent Python versions:

    -lxe: tostring_utf16  (S-TR T1)    7.9958 msec/pass
    -cET: tostring_utf16  (S-TR T1)   83.1358 msec/pass
    +lxe: tostring_utf16  (S-TR T1)    5.9340 msec/pass
    +cET: tostring_utf16  (S-TR T1)   38.3270 msec/pass
     
    -lxe: tostring_utf16  (UATR T1)    8.3222 msec/pass
    -cET: tostring_utf16  (UATR T1)   84.4688 msec/pass
    +lxe: tostring_utf16  (UATR T1)    6.2032 msec/pass
    +cET: tostring_utf16  (UATR T1)   37.7944 msec/pass
     
    -lxe: tostring_utf16  (S-TR T2)    8.2297 msec/pass
    -cET: tostring_utf16  (S-TR T2)   87.3415 msec/pass
    +lxe: tostring_utf16  (S-TR T2)    6.1841 msec/pass
    +cET: tostring_utf16  (S-TR T2)   40.2577 msec/pass
     
    -lxe: tostring_utf8   (S-TR T2)    6.5677 msec/pass
    -cET: tostring_utf8   (S-TR T2)   76.2064 msec/pass
    +lxe: tostring_utf8   (S-TR T2)    4.6697 msec/pass
    +cET: tostring_utf8   (S-TR T2)   30.5173 msec/pass
     
    -lxe: tostring_utf8   (U-TR T3)    1.1952 msec/pass
    -cET: tostring_utf8   (U-TR T3)   22.0058 msec/pass
    +lxe: tostring_utf8   (U-TR T3)    1.2085 msec/pass
    +cET: tostring_utf8   (U-TR T3)   9.0246 msec/pass
     

    The difference is somewhat smaller for plain text serialisation:

    -lxe: tostring_text_ascii     (S-TR T1)    2.7738 msec/pass
    -cET: tostring_text_ascii     (S-TR T1)    4.7629 msec/pass
    +lxe: tostring_text_ascii     (S-TR T1)    2.6727 msec/pass
    +cET: tostring_text_ascii     (S-TR T1)    2.9683 msec/pass
     
    -lxe: tostring_text_ascii     (S-TR T3)    0.8273 msec/pass
    -cET: tostring_text_ascii     (S-TR T3)    1.5273 msec/pass
    +lxe: tostring_text_ascii     (S-TR T3)    0.6952 msec/pass
    +cET: tostring_text_ascii     (S-TR T3)    1.0073 msec/pass
     
    -lxe: tostring_text_utf16     (S-TR T1)    2.7659 msec/pass
    -cET: tostring_text_utf16     (S-TR T1)   10.5038 msec/pass
    +lxe: tostring_text_utf16     (S-TR T1)    2.7366 msec/pass
    +cET: tostring_text_utf16     (S-TR T1)   7.3647 msec/pass
     
    -lxe: tostring_text_utf16     (U-TR T1)    2.8017 msec/pass
    -cET: tostring_text_utf16     (U-TR T1)   10.5207 msec/pass
    +lxe: tostring_text_utf16     (U-TR T1)    3.0322 msec/pass
    +cET: tostring_text_utf16     (U-TR T1)   7.5922 msec/pass
     

    The tostring() function also supports serialisation to a Python unicode string object, which is currently faster in ElementTree -under CPython 3.3:

    +under CPython 3.8:

    -lxe: tostring_text_unicode   (S-TR T1)    2.6896 msec/pass
    -cET: tostring_text_unicode   (S-TR T1)    1.0056 msec/pass
    +lxe: tostring_text_unicode   (S-TR T1)    2.7645 msec/pass
    +cET: tostring_text_unicode   (S-TR T1)    1.1806 msec/pass
     
    -lxe: tostring_text_unicode   (U-TR T1)    2.7366 msec/pass
    -cET: tostring_text_unicode   (U-TR T1)    1.0154 msec/pass
    +lxe: tostring_text_unicode   (U-TR T1)    2.9871 msec/pass
    +cET: tostring_text_unicode   (U-TR T1)    1.1659 msec/pass
     
    -lxe: tostring_text_unicode   (S-TR T3)    0.7997 msec/pass
    -cET: tostring_text_unicode   (S-TR T3)    0.3154 msec/pass
    +lxe: tostring_text_unicode   (S-TR T3)    0.7446 msec/pass
    +cET: tostring_text_unicode   (S-TR T3)    0.4532 msec/pass
     
     lxe: tostring_text_unicode   (U-TR T4)    0.0048 msec/pass
    -cET: tostring_text_unicode   (U-TR T4)    0.0160 msec/pass
    +cET: tostring_text_unicode   (U-TR T4)    0.0134 msec/pass
     

    For parsing, lxml.etree and cElementTree compete for the medal. Depending on the input, either of the two can be faster. The (c)ET @@ -204,80 +197,79 @@ libraries use a very thin layer on top of the expat parser, which is known to be very fast. Here are some timings from the benchmarking suite:

    -lxe: parse_bytesIO   (SAXR T1)   13.0246 msec/pass
    -cET: parse_bytesIO   (SAXR T1)    8.2929 msec/pass
    +lxe: parse_bytesIO   (SAXR T1)   14.2074 msec/pass
    +cET: parse_bytesIO   (SAXR T1)    7.9336 msec/pass
     
    -lxe: parse_bytesIO   (S-XR T3)    1.3542 msec/pass
    -cET: parse_bytesIO   (S-XR T3)    2.4023 msec/pass
    +lxe: parse_bytesIO   (S-XR T3)    1.4477 msec/pass
    +cET: parse_bytesIO   (S-XR T3)    2.1925 msec/pass
     
    -lxe: parse_bytesIO   (UAXR T3)    7.5610 msec/pass
    -cET: parse_bytesIO   (UAXR T3)   11.2455 msec/pass
    +lxe: parse_bytesIO   (UAXR T3)    8.4128 msec/pass
    +cET: parse_bytesIO   (UAXR T3)   12.2926 msec/pass
     

    And another couple of timings from a benchmark that Fredrik Lundh used to promote cElementTree, comparing a number of different parsers. First, parsing a 274KB XML file containing Shakespeare's Hamlet:

    -xml.etree.ElementTree.parse done in 0.017 seconds
    +xml.etree.ElementTree.parse done in 0.006 seconds
     xml.etree.cElementTree.parse done in 0.007 seconds
    -xml.etree.cElementTree.XMLParser.feed(): 6636 nodes read in 0.007 seconds
    -lxml.etree.parse done in 0.003 seconds
    -drop_whitespace.parse done in 0.003 seconds
    +xml.etree.cElementTree.XMLParser.feed(): 6636 nodes read in 0.006 seconds
    +lxml.etree.parse done in 0.004 seconds
    +drop_whitespace.parse done in 0.004 seconds
     lxml.etree.XMLParser.feed(): 6636 nodes read in 0.004 seconds
    -minidom tree read in 0.080 seconds
    +minidom tree read in 0.066 seconds
     

    And a 3.4MB XML file containing the Old Testament:

    -xml.etree.ElementTree.parse done in 0.038 seconds
    -xml.etree.cElementTree.parse done in 0.030 seconds
    -xml.etree.cElementTree.XMLParser.feed(): 25317 nodes read in 0.030 seconds
    -lxml.etree.parse done in 0.016 seconds
    -drop_whitespace.parse done in 0.015 seconds
    -lxml.etree.XMLParser.feed(): 25317 nodes read in 0.022 seconds
    -minidom tree read in 0.288 seconds
    +xml.etree.ElementTree.parse done in 0.037 seconds
    +xml.etree.cElementTree.parse done in 0.036 seconds
    +xml.etree.cElementTree.XMLParser.feed(): 25317 nodes read in 0.036 seconds
    +lxml.etree.parse done in 0.025 seconds
    +drop_whitespace.parse done in 0.022 seconds
    +lxml.etree.XMLParser.feed(): 25317 nodes read in 0.026 seconds
    +minidom tree read in 0.194 seconds
     

    Here are the same benchmarks again, but including the memory usage of the process in KB before and after parsing (using os.fork() to make sure we start from a clean state each time). For the 274KB hamlet.xml file:

    -Memory usage: 7284
    -xml.etree.ElementTree.parse done in 0.017 seconds
    -Memory usage: 9432 (+2148)
    +Memory usage: 9256
    +xml.etree.ElementTree.parse done in 0.006 seconds
    +Memory usage: 12764 (+3508)
     xml.etree.cElementTree.parse done in 0.007 seconds
    -Memory usage: 9432 (+2152)
    -xml.etree.cElementTree.XMLParser.feed(): 6636 nodes read in 0.007 seconds
    -Memory usage: 9448 (+2164)
    -lxml.etree.parse done in 0.003 seconds
    -Memory usage: 11032 (+3748)
    -drop_whitespace.parse done in 0.003 seconds
    -Memory usage: 10224 (+2940)
    +Memory usage: 12764 (+3508)
    +xml.etree.cElementTree.XMLParser.feed(): 6636 nodes read in 0.006 seconds
    +Memory usage: 12720 (+3464)
    +lxml.etree.parse done in 0.004 seconds
    +Memory usage: 15052 (+5796)
    +drop_whitespace.parse done in 0.004 seconds
    +Memory usage: 14040 (+4784)
     lxml.etree.XMLParser.feed(): 6636 nodes read in 0.004 seconds
    -Memory usage: 11804 (+4520)
    -minidom tree read in 0.080 seconds
    -Memory usage: 12324 (+5040)
    +Memory usage: 15812 (+6556)
    +minidom tree read in 0.066 seconds
    +Memory usage: 15332 (+6076)
     

    And for the 3.4MB Old Testament XML file:

    -Memory usage: 10420
    -xml.etree.ElementTree.parse done in 0.038 seconds
    -Memory usage: 20660 (+10240)
    -xml.etree.cElementTree.parse done in 0.030 seconds
    -Memory usage: 20660 (+10240)
    -xml.etree.cElementTree.XMLParser.feed(): 25317 nodes read in 0.030 seconds
    -Memory usage: 20844 (+10424)
    -lxml.etree.parse done in 0.016 seconds
    -Memory usage: 27624 (+17204)
    -drop_whitespace.parse done in 0.015 seconds
    -Memory usage: 24468 (+14052)
    -lxml.etree.XMLParser.feed(): 25317 nodes read in 0.022 seconds
    -Memory usage: 29844 (+19424)
    -minidom tree read in 0.288 seconds
    -Memory usage: 28788 (+18368)
    +Memory usage: 12456
    +xml.etree.ElementTree.parse done in 0.037 seconds
    +Memory usage: 23288 (+10832)
    +xml.etree.cElementTree.parse done in 0.036 seconds
    +Memory usage: 23288 (+10832)
    +xml.etree.cElementTree.XMLParser.feed(): 25317 nodes read in 0.036 seconds
    +Memory usage: 23644 (+11220)
    +lxml.etree.parse done in 0.025 seconds
    +Memory usage: 31404 (+18948)
    +drop_whitespace.parse done in 0.022 seconds
    +Memory usage: 28752 (+16296)
    +lxml.etree.XMLParser.feed(): 25317 nodes read in 0.026 seconds
    +Memory usage: 33924 (+21500)
    +minidom tree read in 0.194 seconds
    +Memory usage: 31284 (+18828)
     

    As can be seen from the sizes, both lxml.etree and cElementTree are -rather memory friendly compared to the pure Python libraries -ElementTree and (especially) minidom. Comparing to older CPython +rather memory friendly and fast. Comparing to older CPython versions, the memory footprint of the minidom library was considerably reduced in CPython 3.3, by about a factor of 4 in this case.

    For plain parser performance, lxml.etree and cElementTree tend to stay @@ -285,26 +277,26 @@ rather close to each other, usually within a factor of two, with winners well distributed over both sides. Similar timings can be observed for the iterparse() function:

    -lxe: iterparse_bytesIO   (SAXR T1)   17.9198 msec/pass
    -cET: iterparse_bytesIO   (SAXR T1)   14.4982 msec/pass
    +lxe: iterparse_bytesIO   (SAXR T1)   20.3598 msec/pass
    +cET: iterparse_bytesIO   (SAXR T1)   10.8948 msec/pass
     
    -lxe: iterparse_bytesIO   (UAXR T3)    8.8522 msec/pass
    -cET: iterparse_bytesIO   (UAXR T3)   12.9857 msec/pass
    +lxe: iterparse_bytesIO   (UAXR T3)    10.1640 msec/pass
    +cET: iterparse_bytesIO   (UAXR T3)   12.9926 msec/pass
     

    However, if you benchmark the complete round-trip of a serialise-parse cycle, the numbers will look similar to these:

    -lxe: write_utf8_parse_bytesIO   (S-TR T1)   19.8867 msec/pass
    -cET: write_utf8_parse_bytesIO   (S-TR T1)   80.7259 msec/pass
    +lxe: write_utf8_parse_bytesIO   (S-TR T1)   18.9857 msec/pass
    +cET: write_utf8_parse_bytesIO   (S-TR T1)   35.7475 msec/pass
     
    -lxe: write_utf8_parse_bytesIO   (UATR T2)   23.7896 msec/pass
    -cET: write_utf8_parse_bytesIO   (UATR T2)   98.0766 msec/pass
    +lxe: write_utf8_parse_bytesIO   (UATR T2)   22.4853 msec/pass
    +cET: write_utf8_parse_bytesIO   (UATR T2)   42.6254 msec/pass
     
    -lxe: write_utf8_parse_bytesIO   (S-TR T3)    3.0684 msec/pass
    -cET: write_utf8_parse_bytesIO   (S-TR T3)   24.6122 msec/pass
    +lxe: write_utf8_parse_bytesIO   (S-TR T3)    3.3801 msec/pass
    +cET: write_utf8_parse_bytesIO   (S-TR T3)   11.2493 msec/pass
     
    -lxe: write_utf8_parse_bytesIO   (SATR T4)    0.3495 msec/pass
    -cET: write_utf8_parse_bytesIO   (SATR T4)    1.9610 msec/pass
    +lxe: write_utf8_parse_bytesIO   (SATR T4)    0.4263 msec/pass
    +cET: write_utf8_parse_bytesIO   (SATR T4)    1.0326 msec/pass
     

    For applications that require a high parser throughput of large files, and that do little to no serialization, both cET and lxml.etree are a @@ -346,14 +338,14 @@ restructuring. This can be seen from the tree setup times of the benchmark (given in seconds):

     lxe:       --     S-     U-     -A     SA     UA
    -     T1: 0.0299 0.0343 0.0344 0.0293 0.0345 0.0342
    -     T2: 0.0368 0.0423 0.0418 0.0427 0.0474 0.0459
    -     T3: 0.0088 0.0084 0.0086 0.0251 0.0258 0.0261
    -     T4: 0.0002 0.0002 0.0002 0.0005 0.0006 0.0006
    +     T1: 0.0219 0.0254 0.0257 0.0216 0.0259 0.0259
    +     T2: 0.0234 0.0279 0.0283 0.0271 0.0318 0.0307
    +     T3: 0.0051 0.0050 0.0058 0.0218 0.0233 0.0231
    +     T4: 0.0001 0.0001 0.0001 0.0004 0.0004 0.0004
     cET:       --     S-     U-     -A     SA     UA
    -     T1: 0.0050 0.0045 0.0093 0.0044 0.0043 0.0043
    -     T2: 0.0073 0.0075 0.0074 0.0201 0.0075 0.0074
    -     T3: 0.0033 0.0213 0.0032 0.0034 0.0033 0.0035
    +     T1: 0.0035 0.0029 0.0078 0.0031 0.0031 0.0029
    +     T2: 0.0047 0.0051 0.0053 0.0046 0.0055 0.0048
    +     T3: 0.0016 0.0216 0.0027 0.0021 0.0023 0.0026
          T4: 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000
     

    The timings are somewhat close to each other, although cET can be @@ -370,30 +362,30 @@ the overhead in creating them.

    a shallow copy of their list of children, lxml has to create a Python object for each child and collect them in a list:

    -lxe: root_list_children        (--TR T1)    0.0038 msec/pass
    -cET: root_list_children        (--TR T1)    0.0010 msec/pass
    +lxe: root_list_children        (--TR T1)    0.0036 msec/pass
    +cET: root_list_children        (--TR T1)    0.0005 msec/pass
     
    -lxe: root_list_children        (--TR T2)    0.0455 msec/pass
    -cET: root_list_children        (--TR T2)    0.0050 msec/pass
    +lxe: root_list_children        (--TR T2)    0.0634 msec/pass
    +cET: root_list_children        (--TR T2)    0.0086 msec/pass
     

    This handicap is also visible when accessing single children:

    -lxe: first_child               (--TR T2)    0.0424 msec/pass
    -cET: first_child               (--TR T2)    0.0384 msec/pass
    +lxe: first_child               (--TR T2)    0.0601 msec/pass
    +cET: first_child               (--TR T2)    0.0548 msec/pass
     
    -lxe: last_child                (--TR T1)    0.0477 msec/pass
    -cET: last_child                (--TR T1)    0.0467 msec/pass
    +lxe: last_child                (--TR T1)    0.0570 msec/pass
    +cET: last_child                (--TR T1)    0.0534 msec/pass
     

    ... unless you also add the time to find a child index in a bigger list. ET and cET use Python lists here, which are based on arrays. The data structure used by libxml2 is a linked tree, and thus, a linked list of children:

    -lxe: middle_child              (--TR T1)    0.0710 msec/pass
    -cET: middle_child              (--TR T1)    0.0420 msec/pass
    +lxe: middle_child              (--TR T1)    0.0892 msec/pass
    +cET: middle_child              (--TR T1)    0.0510 msec/pass
     
    -lxe: middle_child              (--TR T2)    1.7393 msec/pass
    -cET: middle_child              (--TR T2)    0.0396 msec/pass
    +lxe: middle_child              (--TR T2)    2.3038 msec/pass
    +cET: middle_child              (--TR T2)    0.0508 msec/pass
     
    @@ -402,18 +394,18 @@ cET: middle_child (--TR T2) 0.0396 msec/pass in. This results in a major performance difference for creating independent Elements that end up in independently created documents:

    -lxe: create_elements           (--TC T2)    1.0045 msec/pass
    -cET: create_elements           (--TC T2)    0.0753 msec/pass
    +lxe: create_elements           (--TC T2)    0.8032 msec/pass
    +cET: create_elements           (--TC T2)    0.0675 msec/pass
     

    Therefore, it is always preferable to create Elements for the document they are supposed to end up in, either as SubElements of an Element or using the explicit Element.makeelement() call:

    -lxe: makeelement               (--TC T2)    1.0586 msec/pass
    -cET: makeelement               (--TC T2)    0.1483 msec/pass
    +lxe: makeelement               (--TC T2)    0.8030 msec/pass
    +cET: makeelement               (--TC T2)    0.0625 msec/pass
     
    -lxe: create_subelements        (--TC T2)    0.8826 msec/pass
    -cET: create_subelements        (--TC T2)    0.0827 msec/pass
    +lxe: create_subelements        (--TC T2)    0.8621 msec/pass
    +cET: create_subelements        (--TC T2)    0.0923 msec/pass
     

    So, if the main performance bottleneck of an application is creating large XML trees in memory through calls to Element and SubElement, cET is the best @@ -427,11 +419,11 @@ requires lxml to do recursive adaptations throughout the moved tree structure.The following benchmark appends all root children of the second tree to the root of the first tree:

    -lxe: append_from_document      (--TR T1,T2)    1.0812 msec/pass
    -cET: append_from_document      (--TR T1,T2)    0.1104 msec/pass
    +lxe: append_from_document      (--TR T1,T2)    1.3800 msec/pass
    +cET: append_from_document      (--TR T1,T2)    0.0513 msec/pass
     
    -lxe: append_from_document      (--TR T3,T4)    0.0155 msec/pass
    -cET: append_from_document      (--TR T3,T4)    0.0060 msec/pass
    +lxe: append_from_document      (--TR T3,T4)    0.0150 msec/pass
    +cET: append_from_document      (--TR T3,T4)    0.0026 msec/pass
     

    Although these are fairly small numbers compared to parsing, this easily shows the different performance classes for lxml and (c)ET. Where the latter do not @@ -441,19 +433,19 @@ with the size of the tree that is moved.

    This difference is not always as visible, but applies to most parts of the API, like inserting newly created elements:

    -lxe: insert_from_document         (--TR T1,T2)    3.9763 msec/pass
    -cET: insert_from_document         (--TR T1,T2)    0.1459 msec/pass
    +lxe: insert_from_document         (--TR T1,T2)    5.2345 msec/pass
    +cET: insert_from_document         (--TR T1,T2)    0.0732 msec/pass
     

    or replacing the child slice by a newly created element:

    -lxe: replace_children_element   (--TC T1)    0.0749 msec/pass
    -cET: replace_children_element   (--TC T1)    0.0081 msec/pass
    +lxe: replace_children_element   (--TC T1)    0.0720 msec/pass
    +cET: replace_children_element   (--TC T1)    0.0105 msec/pass
     

    as opposed to replacing the slice with an existing element from the same document:

    -lxe: replace_children           (--TC T1)    0.0052 msec/pass
    -cET: replace_children           (--TC T1)    0.0036 msec/pass
    +lxe: replace_children           (--TC T1)    0.0060 msec/pass
    +cET: replace_children           (--TC T1)    0.0050 msec/pass
     

    While these numbers are too small to provide a major performance impact in practice, you should keep this difference in mind when you @@ -465,14 +457,14 @@ thus avoiding the merge overhead when inserting it into that tree.

    deepcopy

    Deep copying a tree is fast in lxml:

    -lxe: deepcopy_all              (--TR T1)    3.1650 msec/pass
    -cET: deepcopy_all              (--TR T1)   53.9973 msec/pass
    +lxe: deepcopy_all              (--TR T1)    4.1246 msec/pass
    +cET: deepcopy_all              (--TR T1)   2.5451 msec/pass
     
    -lxe: deepcopy_all              (-ATR T2)    3.7365 msec/pass
    -cET: deepcopy_all              (-ATR T2)   61.6267 msec/pass
    +lxe: deepcopy_all              (-ATR T2)    4.7867 msec/pass
    +cET: deepcopy_all              (-ATR T2)   2.7504 msec/pass
     
    -lxe: deepcopy_all              (S-TR T3)    0.7913 msec/pass
    -cET: deepcopy_all              (S-TR T3)   13.6220 msec/pass
    +lxe: deepcopy_all              (S-TR T3)    1.0097 msec/pass
    +cET: deepcopy_all              (S-TR T3)   0.6278 msec/pass
     

    So, for example, if you have a database-like scenario where you parse in a large tree and then search and copy independent subtrees from it for further @@ -486,31 +478,31 @@ traversal of the XML tree and especially if few elements are of interest or the target element tag name is known, the .iter() method is a good choice:

    -lxe: iter_all             (--TR T1)    1.0529 msec/pass
    -cET: iter_all             (--TR T1)    0.2635 msec/pass
    +lxe: iter_all             (--TR T1)    1.3661 msec/pass
    +cET: iter_all             (--TR T1)    0.2670 msec/pass
     
    -lxe: iter_islice          (--TR T2)    0.0110 msec/pass
    -cET: iter_islice          (--TR T2)    0.0050 msec/pass
    +lxe: iter_islice          (--TR T2)    0.0122 msec/pass
    +cET: iter_islice          (--TR T2)    0.0033 msec/pass
     
    -lxe: iter_tag             (--TR T2)    0.0079 msec/pass
    -cET: iter_tag             (--TR T2)    0.0112 msec/pass
    +lxe: iter_tag             (--TR T2)    0.0098 msec/pass
    +cET: iter_tag             (--TR T2)    0.0086 msec/pass
     
    -lxe: iter_tag_all         (--TR T2)    0.1822 msec/pass
    -cET: iter_tag_all         (--TR T2)    0.5343 msec/pass
    +lxe: iter_tag_all         (--TR T2)    0.6840 msec/pass
    +cET: iter_tag_all         (--TR T2)    0.4323 msec/pass
     

    This translates directly into similar timings for Element.findall():

    -lxe: findall              (--TR T2)    1.7176 msec/pass
    -cET: findall              (--TR T2)    0.9973 msec/pass
    +lxe: findall              (--TR T2)    3.9611 msec/pass
    +cET: findall              (--TR T2)    0.9227 msec/pass
     
    -lxe: findall              (--TR T3)    0.3967 msec/pass
    -cET: findall              (--TR T3)    0.2525 msec/pass
    +lxe: findall              (--TR T3)    0.3989 msec/pass
    +cET: findall              (--TR T3)    0.2670 msec/pass
     
    -lxe: findall_tag          (--TR T2)    0.2258 msec/pass
    -cET: findall_tag          (--TR T2)    0.5770 msec/pass
    +lxe: findall_tag          (--TR T2)    0.7420 msec/pass
    +cET: findall_tag          (--TR T2)    0.4942 msec/pass
     
    -lxe: findall_tag          (--TR T3)    0.1085 msec/pass
    -cET: findall_tag          (--TR T3)    0.1919 msec/pass
    +lxe: findall_tag          (--TR T3)    0.1099 msec/pass
    +cET: findall_tag          (--TR T3)    0.1748 msec/pass
     

    Note that all three libraries currently use the same Python implementation for .findall(), except for their native tree @@ -528,38 +520,38 @@ provides more than one way of accessing it and you should take care which part of the lxml API you use. The most straight forward way is to call the xpath() method on an Element or ElementTree:

    -lxe: xpath_method         (--TC T1)    0.3982 msec/pass
    -lxe: xpath_method         (--TC T2)    7.8895 msec/pass
    -lxe: xpath_method         (--TC T3)    0.0477 msec/pass
    -lxe: xpath_method         (--TC T4)    0.3982 msec/pass
    +lxe: xpath_method         (--TC T1)    0.2828 msec/pass
    +lxe: xpath_method         (--TC T2)    5.4705 msec/pass
    +lxe: xpath_method         (--TC T3)    0.0324 msec/pass
    +lxe: xpath_method         (--TC T4)    0.2804 msec/pass
     

    This is well suited for testing and when the XPath expressions are as diverse as the trees they are called on. However, if you have a single XPath expression that you want to apply to a larger number of different elements, the XPath class is the most efficient way to do it:

    -lxe: xpath_class          (--TC T1)    0.0713 msec/pass
    -lxe: xpath_class          (--TC T2)    1.1325 msec/pass
    -lxe: xpath_class          (--TC T3)    0.0215 msec/pass
    -lxe: xpath_class          (--TC T4)    0.0722 msec/pass
    +lxe: xpath_class          (--TC T1)    0.0570 msec/pass
    +lxe: xpath_class          (--TC T2)    0.6924 msec/pass
    +lxe: xpath_class          (--TC T3)    0.0148 msec/pass
    +lxe: xpath_class          (--TC T4)    0.0446 msec/pass
     

    Note that this still allows you to use variables in the expression, so you can parse it once and then adapt it through variables at call time. In other cases, where you have a fixed Element or ElementTree and want to run different expressions on it, you should consider the XPathEvaluator:

    -lxe: xpath_element        (--TR T1)    0.1101 msec/pass
    -lxe: xpath_element        (--TR T2)    2.0473 msec/pass
    -lxe: xpath_element        (--TR T3)    0.0267 msec/pass
    -lxe: xpath_element        (--TR T4)    0.1087 msec/pass
    +lxe: xpath_element        (--TR T1)    0.0684 msec/pass
    +lxe: xpath_element        (--TR T2)    1.0865 msec/pass
    +lxe: xpath_element        (--TR T3)    0.0174 msec/pass
    +lxe: xpath_element        (--TR T4)    0.0665 msec/pass
     

    While it looks slightly slower, creating an XPath object for each of the expressions generates a much higher overhead here:

    -lxe: xpath_class_repeat           (--TC T1   )    0.3884 msec/pass
    -lxe: xpath_class_repeat           (--TC T2   )    7.6182 msec/pass
    -lxe: xpath_class_repeat           (--TC T3   )    0.0465 msec/pass
    -lxe: xpath_class_repeat           (--TC T4   )    0.3877 msec/pass
    +lxe: xpath_class_repeat           (--TC T1   )    0.2813 msec/pass
    +lxe: xpath_class_repeat           (--TC T2   )    5.4042 msec/pass
    +lxe: xpath_class_repeat           (--TC T3   )    0.0339 msec/pass
    +lxe: xpath_class_repeat           (--TC T4   )    0.2706 msec/pass
     

    Note that tree iteration can be substantially faster than XPath if your code short-circuits after the first couple of elements were @@ -568,25 +560,25 @@ regardless of how much of it will actually be used.

    Here is an example where only the first matching element is being searched, a case for which XPath has syntax support as well:

    -lxe: find_single                (--TR T2)    0.0184 msec/pass
    -cET: find_single                (--TR T2)    0.0052 msec/pass
    +lxe: find_single                (--TR T2)    0.0031 msec/pass
    +cET: find_single                (--TR T2)    0.0026 msec/pass
     
    -lxe: iter_single                (--TR T2)    0.0024 msec/pass
    -cET: iter_single                (--TR T2)    0.0007 msec/pass
    +lxe: iter_single                (--TR T2)    0.0019 msec/pass
    +cET: iter_single                (--TR T2)    0.0002 msec/pass
     
    -lxe: xpath_single               (--TR T2)    0.0033 msec/pass
    +lxe: xpath_single               (--TR T2)    0.0861 msec/pass
     

    When looking for the first two elements out of many, the numbers explode for XPath, as restricting the result subset requires a more complex expression:

    -lxe: iterfind_two               (--TR T2)    0.0184 msec/pass
    -cET: iterfind_two               (--TR T2)    0.0062 msec/pass
    +lxe: iterfind_two               (--TR T2)    0.0050 msec/pass
    +cET: iterfind_two               (--TR T2)    0.0036 msec/pass
     
    -lxe: iter_two                   (--TR T2)    0.0029 msec/pass
    -cET: iter_two                   (--TR T2)    0.0017 msec/pass
    +lxe: iter_two                   (--TR T2)    0.0021 msec/pass
    +cET: iter_two                   (--TR T2)    0.0014 msec/pass
     
    -lxe: xpath_two                  (--TR T2)    0.2768 msec/pass
    +lxe: xpath_two                  (--TR T2)    0.0916 msec/pass
     
    @@ -718,21 +710,21 @@ instantiated over and over again.

    tree. It avoids step-by-step Python element instantiations along the path, which can substantially improve the access time:

    -lxe: attribute                  (--TR T1)    4.1828 msec/pass
    -lxe: attribute                  (--TR T2)   17.3802 msec/pass
    -lxe: attribute                  (--TR T4)    3.8657 msec/pass
    +lxe: attribute                  (--TR T1)    2.4018 msec/pass
    +lxe: attribute                  (--TR T2)   16.3755 msec/pass
    +lxe: attribute                  (--TR T4)    2.3725 msec/pass
     
    -lxe: objectpath                 (--TR T1)    0.9289 msec/pass
    -lxe: objectpath                 (--TR T2)   13.3109 msec/pass
    -lxe: objectpath                 (--TR T4)    0.9289 msec/pass
    +lxe: objectpath                 (--TR T1)    1.1816 msec/pass
    +lxe: objectpath                 (--TR T2)   14.4675 msec/pass
    +lxe: objectpath                 (--TR T4)    1.2276 msec/pass
     
    -lxe: attributes_deep            (--TR T1)    6.2900 msec/pass
    -lxe: attributes_deep            (--TR T2)   20.4713 msec/pass
    -lxe: attributes_deep            (--TR T4)    6.1679 msec/pass
    +lxe: attributes_deep            (--TR T1)    3.7086 msec/pass
    +lxe: attributes_deep            (--TR T2)   17.5436 msec/pass
    +lxe: attributes_deep            (--TR T4)    3.8407 msec/pass
     
    -lxe: objectpath_deep            (--TR T1)    1.3049 msec/pass
    -lxe: objectpath_deep            (--TR T2)   14.0815 msec/pass
    -lxe: objectpath_deep            (--TR T4)    1.3051 msec/pass
    +lxe: objectpath_deep            (--TR T1)    1.4980 msec/pass
    +lxe: objectpath_deep            (--TR T2)   14.7266 msec/pass
    +lxe: objectpath_deep            (--TR T4)    1.4834 msec/pass
     

    Note, however, that parsing ObjectPath expressions is not for free either, so this is most effective for frequently accessing the same element.

    @@ -754,17 +746,17 @@ expressions to be more selective. By choosing the right trees (or even subtrees and elements) to cache, you can trade memory usage against access speed:

    -lxe: attribute_cached           (--TR T1)    3.1357 msec/pass
    -lxe: attribute_cached           (--TR T2)   15.8911 msec/pass
    -lxe: attribute_cached           (--TR T4)    2.9194 msec/pass
    +lxe: attribute_cached           (--TR T1)    1.9207 msec/pass
    +lxe: attribute_cached           (--TR T2)   15.6903 msec/pass
    +lxe: attribute_cached           (--TR T4)    1.8718 msec/pass
     
    -lxe: attributes_deep_cached     (--TR T1)    3.8984 msec/pass
    -lxe: attributes_deep_cached     (--TR T2)   16.8300 msec/pass
    -lxe: attributes_deep_cached     (--TR T4)    3.6936 msec/pass
    +lxe: attributes_deep_cached     (--TR T1)    2.6512 msec/pass
    +lxe: attributes_deep_cached     (--TR T2)   16.7937 msec/pass
    +lxe: attributes_deep_cached     (--TR T4)    2.5539 msec/pass
     
    -lxe: objectpath_deep_cached     (--TR T1)    0.7496 msec/pass
    -lxe: objectpath_deep_cached     (--TR T2)   12.3763 msec/pass
    -lxe: objectpath_deep_cached     (--TR T4)    0.7427 msec/pass
    +lxe: objectpath_deep_cached     (--TR T1)    0.8519 msec/pass
    +lxe: objectpath_deep_cached     (--TR T2)   13.9337 msec/pass
    +lxe: objectpath_deep_cached     (--TR T4)    0.8645 msec/pass
     

    Things to note: you cannot currently use weakref.WeakKeyDictionary objects for this as lxml's element objects do not support weak references (which are @@ -798,7 +790,7 @@ random.

    diff --git a/doc/html/resolvers.html b/doc/html/resolvers.html index 5fa07be..64d7b61 100644 --- a/doc/html/resolvers.html +++ b/doc/html/resolvers.html @@ -2,7 +2,7 @@ - + Document loading and URL resolving
    -

    Document loading and URL resolving

    +

    Document loading and URL resolving

    @@ -83,7 +83,7 @@ registered resolver (or the default resolver) is consulted. Resolving always terminates if resolve() returns the result of any of the above resolve_*() methods.

    Resolvers are registered local to a parser:

    -
    >>> parser = etree.XMLParser(load_dtd=True)
    +
    >>> parser = etree.XMLParser(load_dtd=True)
     >>> parser.resolvers.add( DTDResolver() )
     

    Note that we instantiate a parser that loads the DTD. This is not done by the @@ -93,7 +93,7 @@ document that requires resolving a URL, it will call our custom resolver:

    >>> tree = etree.parse(StringIO(xml), parser) Resolving URL 'MissingDTD.dtd' >>> root = tree.getroot() ->>> print(root.text) +>>> print(root.text) [resolved text: MissingDTD.dtd]

    The entity in the document was correctly resolved by the generated DTD @@ -116,7 +116,7 @@ resolver that only responds to a specific prefix:

    ... ''' % prefix ... def resolve(self, url, pubid, context): ... if url.startswith(self.prefix): -... print("Resolved url %s as prefix %s" % (url, self.prefix)) +... print("Resolved url %s as prefix %s" % (url, self.prefix)) ... return self.resolve_string(self.result_xml, context)

    We demonstrate this in XSLT and use the following stylesheet as an example:

    @@ -189,7 +189,7 @@ needs to resolve the hoi URI in the call to th
    >>> honk_parser.resolvers.add( PrefixResolver("hoi") )
     >>> result = transform(honk_doc)
     Resolved url hoi:test as prefix hoi
    ->>> print(str(result)[:-1])
    +>>> print(str(result)[:-1])
     <?xml version="1.0"?>
     <test>hoi-TEST</test>
     
    @@ -199,7 +199,7 @@ that this is completely independent of the XML file you transform, as the URI is resolved from within the stylesheet context:

    >>> result = transform(normal_doc)
     Resolved url hoi:test as prefix hoi
    ->>> print(str(result)[:-1])
    +>>> print(str(result)[:-1])
     <?xml version="1.0"?>
     <test>hoi-TEST</test>
     
    @@ -227,7 +227,7 @@ operations:

    >>> result = transform(normal_doc) Resolved url hoi:test as prefix hoi ->>> ac = etree.XSLTAccessControl(read_network=False) +>>> ac = etree.XSLTAccessControl(read_network=False) >>> transform = etree.XSLT(honk_doc, access_control=ac) Resolved url honk:test as prefix honk >>> result = transform(normal_doc) @@ -250,7 +250,7 @@ documents or raises exceptions if access is denied. diff --git a/doc/html/sax.html b/doc/html/sax.html index 4103192..b0c1b82 100644 --- a/doc/html/sax.html +++ b/doc/html/sax.html @@ -2,7 +2,7 @@ - + Sax support
    -

    Sax support

    +

    Sax support

    In this document we'll describe lxml's SAX support. lxml has support for producing SAX events for an ElementTree or Element. lxml can also turn SAX @@ -48,11 +48,11 @@ do this, we use the special SAX content handler defined by lxml named >>> handler = lxml.sax.ElementTreeContentHandler()

    Now let's fire some SAX events at it:

    -
    >>> handler.startElementNS((None, 'a'), 'a', {})
    ->>> handler.startElementNS((None, 'b'), 'b', {(None, 'foo'): 'bar'})
    +
    >>> handler.startElementNS((None, 'a'), 'a', {})
    +>>> handler.startElementNS((None, 'b'), 'b', {(None, 'foo'): 'bar'})
     >>> handler.characters('Hello world')
    ->>> handler.endElementNS((None, 'b'), 'b')
    ->>> handler.endElementNS((None, 'a'), 'a')
    +>>> handler.endElementNS((None, 'b'), 'b')
    +>>> handler.endElementNS((None, 'a'), 'a')
     

    This constructs an equivalent tree. You can access it through the etree property of the handler:

    @@ -77,7 +77,7 @@ content handler.:

    ... def __init__(self): ... self.a_amount = 0 ... self.b_amount = 0 -... self.text = None +... self.text = None ... ... def startElementNS(self, name, qname, attributes): ... uri, localname = name @@ -117,14 +117,14 @@ DOM implementation cannot generate SAX events from a DOM tree.

    PullDOM makes the result available through the document attribute:

    >>> dom = handler.document
    ->>> print(dom.firstChild.localName)
    +>>> print(dom.firstChild.localName)
     a
     
    diff --git a/doc/html/sitemap.html b/doc/html/sitemap.html index 88cc342..13c1125 100644 --- a/doc/html/sitemap.html +++ b/doc/html/sitemap.html @@ -8,5 +8,5 @@

    Sitemap of lxml.de - Processing XML and HTML with Python

    -
    +
    \ No newline at end of file diff --git a/doc/html/style.css b/doc/html/style.css index 4cc454a..7d1b0e6 100644 --- a/doc/html/style.css +++ b/doc/html/style.css @@ -164,7 +164,7 @@ div.banner { border: 2px solid darkred; color: darkgreen; line-height: 1em; - margin: 1ex; + margin: 3ex 1ex 1ex; padding: 3pt; } @@ -321,6 +321,18 @@ html > .pagequote { position: fixed; } +div.admonition { + border: solid 1px; + border-radius: 1ex; + margin: 0.5ex; + padding: 0.5ex 1.5ex 0.5ex 1.5ex; + background: lightyellow; +} + +div.admonition > .admonition-title { + background: yellow; +} + code { color: Black; background-color: #f0f0f0; diff --git a/doc/html/tutorial.html b/doc/html/tutorial.html index 0be5f45..f659e40 100644 --- a/doc/html/tutorial.html +++ b/doc/html/tutorial.html @@ -2,7 +2,7 @@ - + The lxml.etree Tutorial @@ -27,7 +27,7 @@ function hide_menu() {
    -

    The lxml.etree Tutorial

    +

    The lxml.etree Tutorial

    @@ -76,29 +76,29 @@ functionality that is specific to lxml.etree, of) the following import chain as a fall-back to the original ElementTree:

    try:
       from lxml import etree
    -  print("running with lxml.etree")
    +  print("running with lxml.etree")
     except ImportError:
       try:
         # Python 2.5
    -    import xml.etree.cElementTree as etree
    -    print("running with cElementTree on Python 2.5+")
    +    import xml.etree.cElementTree as etree
    +    print("running with cElementTree on Python 2.5+")
       except ImportError:
         try:
           # Python 2.5
    -      import xml.etree.ElementTree as etree
    -      print("running with ElementTree on Python 2.5+")
    +      import xml.etree.ElementTree as etree
    +      print("running with ElementTree on Python 2.5+")
         except ImportError:
           try:
             # normal cElementTree install
    -        import cElementTree as etree
    -        print("running with cElementTree")
    +        import cElementTree as etree
    +        print("running with cElementTree")
           except ImportError:
             try:
               # normal ElementTree install
    -          import elementtree.ElementTree as etree
    -          print("running with ElementTree")
    +          import elementtree.ElementTree as etree
    +          print("running with ElementTree")
             except ImportError:
    -          print("Failed to import ElementTree from any known place")
    +          print("Failed to import ElementTree from any known place")
     

    To aid in writing portable code, this tutorial makes it clear in the examples which part of the presented API is an extension of lxml.etree over the @@ -112,7 +112,7 @@ easily created through the Element factory:

    >>> root = etree.Element("root")
     

    The XML tag name of elements is accessed through the tag property:

    -
    >>> print(root.tag)
    +
    >>> print(root.tag)
     root
     

    Elements are organised in an XML tree structure. To create child elements and @@ -126,7 +126,7 @@ to do this: the SubElement factory. It accept >>> child3 = etree.SubElement(root, "child3")

    To see that this is really XML, you can serialise the tree you have created:

    -
    >>> print(etree.tostring(root, pretty_print=True))
    +
    >>> print(etree.tostring(root, pretty_print=True))
     <root>
       <child1/>
       <child2/>
    @@ -139,10 +139,10 @@ to do this: the SubElement factory.  It accept
     elements mimic the behaviour of normal Python lists as closely as
     possible:

    >>> child = root[0]
    ->>> print(child.tag)
    +>>> print(child.tag)
     child1
     
    ->>> print(len(root))
    +>>> print(len(root))
     3
     
     >>> root.index(root[1]) # lxml.etree only!
    @@ -151,7 +151,7 @@ possible:

    >>> children = list(root) >>> for child in root: -... print(child.tag) +... print(child.tag) child1 child2 child3 @@ -160,39 +160,39 @@ possible:

    >>> start = root[:1] >>> end = root[-1:] ->>> print(start[0].tag) +>>> print(start[0].tag) child0 ->>> print(end[0].tag) +>>> print(end[0].tag) child3

    Prior to ElementTree 1.3 and lxml 2.0, you could also check the truth value of an Element to see if it has children, i.e. if the list of children is empty:

    if root:   # this no longer works!
    -    print("The root element has children")
    +    print("The root element has children")
     

    This is no longer supported as people tend to expect that a "something" evaluates to True and expect Elements to be "something", may they have children or not. So, many users find it surprising that any Element would evaluate to False in an if-statement like the above. Instead, use len(element), which is both more explicit and less error prone.

    -
    >>> print(etree.iselement(root))  # test if it's some kind of Element
    +
    >>> print(etree.iselement(root))  # test if it's some kind of Element
     True
     >>> if len(root):                 # test if it has children
    -...     print("The root element has children")
    +...     print("The root element has children")
     The root element has children
     

    There is another important case where the behaviour of Elements in lxml (in 2.0 and later) deviates from that of lists and from that of the original ElementTree (prior to version 1.3 or Python 2.7/3.2):

    >>> for child in root:
    -...     print(child.tag)
    +...     print(child.tag)
     child0
     child1
     child2
     child3
     >>> root[0] = root[-1]  # this moves the element in lxml.etree!
     >>> for child in root:
    -...     print(child.tag)
    +...     print(child.tag)
     child3
     child1
     child2
    @@ -227,9 +227,9 @@ from Python's standard library:

    >>> element = etree.Element("neu") >>> element.append( deepcopy(root[1]) ) ->>> print(element[0].tag) +>>> print(element[0].tag) child1 ->>> print([ c.tag for c in root ]) +>>> print([ c.tag for c in root ]) ['child3', 'child1', 'child2']

    The siblings (or neighbours) of an element are accessed as next and previous @@ -250,13 +250,13 @@ factory:

    Attributes are just unordered name-value pairs, so a very convenient way of dealing with them is through the dictionary-like interface of Elements:

    -
    >>> print(root.get("interesting"))
    +
    >>> print(root.get("interesting"))
     totally
     
    ->>> print(root.get("hello"))
    +>>> print(root.get("hello"))
     None
     >>> root.set("hello", "Huhu")
    ->>> print(root.get("hello"))
    +>>> print(root.get("hello"))
     Huhu
     
     >>> etree.tostring(root)
    @@ -266,7 +266,7 @@ of dealing with them is through the dictionary-like interface of Elements:

    ['hello', 'interesting'] >>> for name, value in sorted(root.items()): -... print('%s = %r' % (name, value)) +... print('%s = %r' % (name, value)) hello = 'Huhu' interesting = 'totally'
    @@ -275,15 +275,15 @@ getting a 'real' dictionary-like object, e.g. for passing it around, you can use the attrib property:

    >>> attributes = root.attrib
     
    ->>> print(attributes["interesting"])
    +>>> print(attributes["interesting"])
     totally
    ->>> print(attributes.get("no-such-attribute"))
    +>>> print(attributes.get("no-such-attribute"))
     None
     
     >>> attributes["hello"] = "Guten Tag"
    ->>> print(attributes["hello"])
    +>>> print(attributes["hello"])
     Guten Tag
    ->>> print(root.get("hello"))
    +>>> print(root.get("hello"))
     Guten Tag
     

    Note that attrib is a dict-like object backed by the Element itself. @@ -303,7 +303,7 @@ tree, copy it into a dict:

    >>> root = etree.Element("root")
     >>> root.text = "TEXT"
     
    ->>> print(root.text)
    +>>> print(root.text)
     TEXT
     
     >>> etree.tostring(root)
    @@ -347,7 +347,7 @@ still want the tail text of its children).  For this purpose, the
     tostring() function accepts the keyword argument with_tail:

    >>> etree.tostring(br)
     b'<br/>TAIL'
    ->>> etree.tostring(br, with_tail=False) # lxml.etree only!
    +>>> etree.tostring(br, with_tail=False) # lxml.etree only!
     b'<br/>'
     

    If you want to read only the text, i.e. without any intermediate @@ -362,14 +362,14 @@ comes to the rescue, this time using the methodUsing XPath to find text

    Another way to extract the text content of a tree is XPath, which also allows you to extract the separate text chunks into a list:

    -
    >>> print(html.xpath("string()")) # lxml.etree only!
    +
    >>> print(html.xpath("string()")) # lxml.etree only!
     TEXTTAIL
    ->>> print(html.xpath("//text()")) # lxml.etree only!
    +>>> print(html.xpath("//text()")) # lxml.etree only!
     ['TEXT', 'TAIL']
     

    If you want to use this more often, you can wrap it in a function:

    >>> build_text_list = etree.XPath("//text()") # lxml.etree only!
    ->>> print(build_text_list(html))
    +>>> print(build_text_list(html))
     ['TEXT', 'TAIL']
     

    Note that a string result returned by XPath is a special 'smart' @@ -377,32 +377,32 @@ object that knows about its origins. You can ask it where it came from through its getparent() method, just as you would with Elements:

    >>> texts = build_text_list(html)
    ->>> print(texts[0])
    +>>> print(texts[0])
     TEXT
     >>> parent = texts[0].getparent()
    ->>> print(parent.tag)
    +>>> print(parent.tag)
     body
     
    ->>> print(texts[1])
    +>>> print(texts[1])
     TAIL
    ->>> print(texts[1].getparent().tag)
    +>>> print(texts[1].getparent().tag)
     br
     

    You can also find out if it's normal text content or tail text:

    -
    >>> print(texts[0].is_text)
    +
    >>> print(texts[0].is_text)
     True
    ->>> print(texts[1].is_text)
    +>>> print(texts[1].is_text)
     False
    ->>> print(texts[1].is_tail)
    +>>> print(texts[1].is_tail)
     True
     

    While this works for the results of the text() function, lxml will not tell you the origin of a string value that was constructed by the XPath functions string() or concat():

    >>> stringify = etree.XPath("string()")
    ->>> print(stringify(html))
    +>>> print(stringify(html))
     TEXTTAIL
    ->>> print(stringify(html).getparent())
    +>>> print(stringify(html).getparent())
     None
     
    @@ -418,7 +418,7 @@ serialised the tree to XML:

    >>> etree.SubElement(root, "child").text = "Child 2" >>> etree.SubElement(root, "another").text = "Child 3" ->>> print(etree.tostring(root, pretty_print=True)) +>>> print(etree.tostring(root, pretty_print=True)) <root> <child>Child 1</child> <child>Child 2</child> @@ -426,7 +426,7 @@ serialised the tree to XML:

    </root> >>> for element in root.iter(): -... print("%s - %s" % (element.tag, element.text)) +... print("%s - %s" % (element.tag, element.text)) root - None child - Child 1 child - Child 2 @@ -436,12 +436,12 @@ serialised the tree to XML:

    iter() to have it filter for you. Starting with lxml 3.0, you can also pass more than one tag to intercept on multiple tags during iteration.

    >>> for element in root.iter("child"):
    -...     print("%s - %s" % (element.tag, element.text))
    +...     print("%s - %s" % (element.tag, element.text))
     child - Child 1
     child - Child 2
     
     >>> for element in root.iter("another", "child"):
    -...     print("%s - %s" % (element.tag, element.text))
    +...     print("%s - %s" % (element.tag, element.text))
     child - Child 1
     child - Child 2
     another - Child 3
    @@ -454,10 +454,10 @@ make sure only Element objects are returned, you can pass the
     >>> root.append(etree.Comment("some comment"))
     
     >>> for element in root.iter():
    -...     if isinstance(element.tag, basestring):  # or 'str' in Python 3
    -...         print("%s - %s" % (element.tag, element.text))
    +...     if isinstance(element.tag, basestring):  # or 'str' in Python 3
    +...         print("%s - %s" % (element.tag, element.text))
     ...     else:
    -...         print("SPECIAL: %s - %s" % (element, element.text))
    +...         print("SPECIAL: %s - %s" % (element, element.text))
     root - None
     child - Child 1
     child - Child 2
    @@ -466,14 +466,14 @@ make sure only Element objects are returned, you can pass the
     SPECIAL: <!--some comment--> - some comment
     
     >>> for element in root.iter(tag=etree.Element):
    -...     print("%s - %s" % (element.tag, element.text))
    +...     print("%s - %s" % (element.tag, element.text))
     root - None
     child - Child 1
     child - Child 2
     another - Child 3
     
     >>> for element in root.iter(tag=etree.Entity):
    -...     print(element.text)
    +...     print(element.text)
     &#234;
     

    Note that passing a wildcard "*" tag name will also yield all @@ -494,15 +494,15 @@ ASCII:

    >>> etree.tostring(root) b'<root><a><b/></a></root>' ->>> print(etree.tostring(root, xml_declaration=True)) +>>> print(etree.tostring(root, xml_declaration=True)) <?xml version='1.0' encoding='ASCII'?> <root><a><b/></a></root> ->>> print(etree.tostring(root, encoding='iso-8859-1')) +>>> print(etree.tostring(root, encoding='iso-8859-1')) <?xml version='1.0' encoding='iso-8859-1'?> <root><a><b/></a></root> ->>> print(etree.tostring(root, pretty_print=True)) +>>> print(etree.tostring(root, pretty_print=True)) <root> <a> <b/> @@ -514,12 +514,12 @@ ASCII:

    whitespace indentation to the tree before serialising it, using the indent() function (added in lxml 4.5):

    >>> root = etree.XML('<root><a><b/>\n</a></root>')
    ->>> print(etree.tostring(root))
    +>>> print(etree.tostring(root))
     <root><a><b/>
     </a></root>
     
     >>> etree.indent(root)
    ->>> print(etree.tostring(root))
    +>>> print(etree.tostring(root))
     <root>
       <a>
         <b/>
    @@ -532,7 +532,7 @@ whitespace indentation to the tree before serialising it, using the
     '\n    '
     
     >>> etree.indent(root, space="    ")
    ->>> print(etree.tostring(root))
    +>>> print(etree.tostring(root))
     <root>
         <a>
             <b/>
    @@ -558,7 +558,7 @@ HTML or extract the text content by passing the met
     >>> etree.tostring(root, method='html')
     b'<html><head></head><body><p>Hello<br>World</p></body></html>'
     
    ->>> print(etree.tostring(root, method='html', pretty_print=True))
    +>>> print(etree.tostring(root, method='html', pretty_print=True))
     <html>
     <head></head>
     <body><p>Hello<br>World</p></body>
    @@ -603,14 +603,14 @@ general document handling.

    ... ''') >>> tree = etree.ElementTree(root) ->>> print(tree.docinfo.xml_version) +>>> print(tree.docinfo.xml_version) 1.0 ->>> print(tree.docinfo.doctype) +>>> print(tree.docinfo.doctype) <!DOCTYPE root SYSTEM "test"> >>> tree.docinfo.public_id = '-//W3C//DTD XHTML 1.0 Transitional//EN' >>> tree.docinfo.system_url = 'file://local.dtd' ->>> print(tree.docinfo.doctype) +>>> print(tree.docinfo.doctype) <!DOCTYPE root PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "file://local.dtd">

    An ElementTree is also what you get back when you call the @@ -620,7 +620,7 @@ parsing section below).

    serialises as a complete document, as opposed to a single Element. This includes top-level processing instructions and comments, as well as a DOCTYPE and other DTD content in the document:

    -
    >>> print(etree.tostring(tree))  # lxml 1.3.4 and later
    +
    >>> print(etree.tostring(tree))  # lxml 1.3.4 and later
     <!DOCTYPE root PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "file://local.dtd" [
     <!ENTITY tasty "parsnips">
     ]>
    @@ -631,7 +631,7 @@ as a DOCTYPE and other DTD content in the document:

    In the original xml.etree.ElementTree implementation and in lxml up to 1.3.3, the output looks the same as when serialising only the root Element:

    -
    >>> print(etree.tostring(tree.getroot()))
    +
    >>> print(etree.tostring(tree.getroot()))
     <root>
       <a>parsnips</a>
     </root>
    @@ -654,7 +654,7 @@ different parser as second argument.

    >>> some_xml_data = "<root>data</root>"
     
     >>> root = etree.fromstring(some_xml_data)
    ->>> print(root.tag)
    +>>> print(root.tag)
     root
     >>> etree.tostring(root)
     b'<root>data</root>'
    @@ -665,7 +665,7 @@ different parser as second argument.

    The XML() function behaves like the fromstring() function, but is commonly used to write XML literals right into the source:

    >>> root = etree.XML("<root>data</root>")
    ->>> print(root.tag)
    +>>> print(root.tag)
     root
     >>> etree.tostring(root)
     b'<root>data</root>'
    @@ -696,7 +696,7 @@ doing this all together and use the string parsing functions above.

    Note that parse() returns an ElementTree object, not an Element object as the string parser functions:

    >>> root = tree.getroot()
    ->>> print(root.tag)
    +>>> print(root.tag)
     root
     >>> etree.tostring(root)
     b'<root>data</root>'
    @@ -723,7 +723,7 @@ from while the response is streaming in.

    Parser objects

    By default, lxml.etree uses a standard parser with a default setup. If you want to configure the parser, you can create a new instance:

    -
    >>> parser = etree.XMLParser(remove_blank_text=True) # lxml.etree only!
    +
    >>> parser = etree.XMLParser(remove_blank_text=True) # lxml.etree only!
     

    This creates a parser that removes empty text between tags while parsing, which can reduce the size of the tree and avoid dangling tail text if you know @@ -737,8 +737,8 @@ that whitespace-only content is not meaningful for your data. An example:

    content at leaf elements tends to be data content (even if blank). You can easily remove it in an additional step by traversing the tree:

    >>> for element in root.iter("*"):
    -...     if element.text is not None and not element.text.strip():
    -...         element.text = None
    +...     if element.text is not None and not element.text.strip():
    +...         element.text = None
     
     >>> etree.tostring(root)
     b'<root><a/><b/></root>'
    @@ -807,7 +807,7 @@ fashion.

    >>> some_file_like = BytesIO(b"<root><a>data</a></root>")
     
     >>> for event, element in etree.iterparse(some_file_like):
    -...     print("%s, %4s, %s" % (event, element.tag, element.text))
    +...     print("%s, %4s, %s" % (event, element.tag, element.text))
     end,    a, data
     end, root, None
     
    @@ -817,7 +817,7 @@ element, but you can control this through the event >>> for event, element in etree.iterparse(some_file_like, ... events=("start", "end")): -... print("%5s, %4s, %s" % (event, element.tag, element.text)) +... print("%5s, %4s, %s" % (event, element.tag, element.text)) start, root, None start, a, data end, a, data @@ -838,10 +838,10 @@ have completely read through yet.

    >>> for event, element in etree.iterparse(some_file_like): ... if element.tag == 'b': -... print(element.text) +... print(element.text) ... elif element.tag == 'a': -... print("** cleaning up the subtree") -... element.clear(keep_tail=True) +... print("** cleaning up the subtree") +... element.clear(keep_tail=True) data ** cleaning up the subtree None @@ -862,8 +862,8 @@ for data extraction.

    ... </root>''') >>> for _, element in etree.iterparse(xml_file, tag='a'): -... print('%s -- %s' % (element.findtext('b'), element[1].text)) -... element.clear(keep_tail=True) +... print('%s -- %s' % (element.findtext('b'), element[1].text)) +... element.clear(keep_tail=True) ABC -- abc MORE DATA -- more data XYZ -- xyz @@ -888,13 +888,13 @@ events are generated:

    >>> parser = etree.XMLParser(target=parser_target) >>> events = etree.fromstring('<root test="true"/>', parser) ->>> print(parser_target.close_count) +>>> print(parser_target.close_count) 1 >>> for event in events: -... print('event: %s - tag: %s' % (event[0], event[1])) +... print('event: %s - tag: %s' % (event[0], event[1])) ... for attr, value in event[2].items(): -... print(' * %s = %s' % (attr, value)) +... print(' * %s = %s' % (attr, value)) event: start - tag: root * test = true
    @@ -902,19 +902,19 @@ events are generated:

    should take care that the .close() method really resets the target to a usable state (also in the case of an error!).

    >>> events = etree.fromstring('<root test="true"/>', parser)
    ->>> print(parser_target.close_count)
    +>>> print(parser_target.close_count)
     2
     >>> events = etree.fromstring('<root test="true"/>', parser)
    ->>> print(parser_target.close_count)
    +>>> print(parser_target.close_count)
     3
     >>> events = etree.fromstring('<root test="true"/>', parser)
    ->>> print(parser_target.close_count)
    +>>> print(parser_target.close_count)
     4
     
     >>> for event in events:
    -...     print('event: %s - tag: %s' % (event[0], event[1]))
    +...     print('event: %s - tag: %s' % (event[0], event[1]))
     ...     for attr, value in event[2].items():
    -...         print(' * %s = %s' % (attr, value))
    +...         print(' * %s = %s' % (attr, value))
     event: start - tag: root
      * test = true
     
    @@ -929,7 +929,7 @@ wherever possible and deploys the real namespace (the URI) instead:

    >>> body = etree.SubElement(xhtml, "{http://www.w3.org/1999/xhtml}body") >>> body.text = "Hello World" ->>> print(etree.tostring(xhtml, pretty_print=True)) +>>> print(etree.tostring(xhtml, pretty_print=True)) <html:html xmlns:html="http://www.w3.org/1999/xhtml"> <html:body>Hello World</html:body> </html:html> @@ -950,13 +950,13 @@ the Element factory function, e.g. to define the default namespace:

    >>> XHTML_NAMESPACE = "http://www.w3.org/1999/xhtml"
     >>> XHTML = "{%s}" % XHTML_NAMESPACE
     
    ->>> NSMAP = {None : XHTML_NAMESPACE} # the default namespace (no prefix)
    +>>> NSMAP = {None : XHTML_NAMESPACE} # the default namespace (no prefix)
     
     >>> xhtml = etree.Element(XHTML + "html", nsmap=NSMAP) # lxml only!
     >>> body = etree.SubElement(xhtml, XHTML + "body")
     >>> body.text = "Hello World"
     
    ->>> print(etree.tostring(xhtml, pretty_print=True))
    +>>> print(etree.tostring(xhtml, pretty_print=True))
     <html xmlns="http://www.w3.org/1999/xhtml">
       <body>Hello World</body>
     </html>
    @@ -964,29 +964,29 @@ the Element factory function, e.g. to define the default namespace:

    You can also use the QName helper class to build or split qualified tag names:

    >>> tag = etree.QName('http://www.w3.org/1999/xhtml', 'html')
    ->>> print(tag.localname)
    +>>> print(tag.localname)
     html
    ->>> print(tag.namespace)
    +>>> print(tag.namespace)
     http://www.w3.org/1999/xhtml
    ->>> print(tag.text)
    +>>> print(tag.text)
     {http://www.w3.org/1999/xhtml}html
     
     >>> tag = etree.QName('{http://www.w3.org/1999/xhtml}html')
    ->>> print(tag.localname)
    +>>> print(tag.localname)
     html
    ->>> print(tag.namespace)
    +>>> print(tag.namespace)
     http://www.w3.org/1999/xhtml
     
     >>> root = etree.Element('{http://www.w3.org/1999/xhtml}html')
     >>> tag = etree.QName(root)
    ->>> print(tag.localname)
    +>>> print(tag.localname)
     html
     
     >>> tag = etree.QName(root, 'script')
    ->>> print(tag.text)
    +>>> print(tag.text)
     {http://www.w3.org/1999/xhtml}script
     >>> tag = etree.QName('{http://www.w3.org/1999/xhtml}html', 'script')
    ->>> print(tag.text)
    +>>> print(tag.text)
     {http://www.w3.org/1999/xhtml}script
     

    lxml.etree allows you to look up the current namespaces defined for a @@ -1019,12 +1019,12 @@ serialise-parse roundtrip, even if they appear in a namespaced element.

    >>> body.set(XHTML + "bgcolor", "#CCFFAA")
     
    ->>> print(etree.tostring(xhtml, pretty_print=True))
    +>>> print(etree.tostring(xhtml, pretty_print=True))
     <html xmlns="http://www.w3.org/1999/xhtml">
       <body xmlns:html="http://www.w3.org/1999/xhtml" html:bgcolor="#CCFFAA">Hello World</body>
     </html>
     
    ->>> print(body.get("bgcolor"))
    +>>> print(body.get("bgcolor"))
     None
     >>> body.get(XHTML + "bgcolor")
     '#CCFFAA'
    @@ -1034,18 +1034,18 @@ element.

    ... "//{%s}body" % XHTML_NAMESPACE) >>> results = find_xhtml_body(xhtml) ->>> print(results[0].tag) +>>> print(results[0].tag) {http://www.w3.org/1999/xhtml}body

    For convenience, you can use "*" wildcards in all iterators of lxml.etree, both for tag names and namespaces:

    -
    >>> for el in xhtml.iter('*'): print(el.tag)   # any element
    +
    >>> for el in xhtml.iter('*'): print(el.tag)   # any element
     {http://www.w3.org/1999/xhtml}html
     {http://www.w3.org/1999/xhtml}body
    ->>> for el in xhtml.iter('{http://www.w3.org/1999/xhtml}*'): print(el.tag)
    +>>> for el in xhtml.iter('{http://www.w3.org/1999/xhtml}*'): print(el.tag)
     {http://www.w3.org/1999/xhtml}html
     {http://www.w3.org/1999/xhtml}body
    ->>> for el in xhtml.iter('{*}body'): print(el.tag)
    +>>> for el in xhtml.iter('{*}body'): print(el.tag)
     {http://www.w3.org/1999/xhtml}body
     

    To look for elements that do not have a namespace, either use the @@ -1054,9 +1054,9 @@ plain tag name or provide the empty namespace explicitly:

    ['{http://www.w3.org/1999/xhtml}body'] >>> [ el.tag for el in xhtml.iter('body') ] [] ->>> [ el.tag for el in xhtml.iter('{}body') ] +>>> [ el.tag for el in xhtml.iter('{}body') ] [] ->>> [ el.tag for el in xhtml.iter('{}*') ] +>>> [ el.tag for el in xhtml.iter('{}*') ] []
    @@ -1085,7 +1085,7 @@ HTML:

    ... ) ... ) ->>> print(etree.tostring(page, pretty_print=True)) +>>> print(etree.tostring(page, pretty_print=True)) <html> <head> <title>This is a sample document</title> @@ -1125,7 +1125,7 @@ simple vocabulary for an XML language:

    ... ) ... ) ->>> print(etree.tostring(my_doc, pretty_print=True)) +>>> print(etree.tostring(my_doc, pretty_print=True)) <p:doc xmlns:p="http://my.de/fault/namespace"> <p:title>The dog and the hog</p:title> <p:section> @@ -1170,32 +1170,32 @@ expression
    >>> root = etree.XML("<root><a x='123'>aText<b/><c/><b/></a></root>")
     

    Find a child of an Element:

    -
    >>> print(root.find("b"))
    +
    >>> print(root.find("b"))
     None
    ->>> print(root.find("a").tag)
    +>>> print(root.find("a").tag)
     a
     

    Find an Element anywhere in the tree:

    -
    >>> print(root.find(".//b").tag)
    +
    >>> print(root.find(".//b").tag)
     b
     >>> [ b.tag for b in root.iterfind(".//b") ]
     ['b', 'b']
     

    Find Elements with a certain attribute:

    -
    >>> print(root.findall(".//a[@x]")[0].tag)
    +
    >>> print(root.findall(".//a[@x]")[0].tag)
     a
    ->>> print(root.findall(".//a[@y]"))
    +>>> print(root.findall(".//a[@y]"))
     []
     

    In lxml 3.4, there is a new helper to generate a structural ElementPath expression for an Element:

    >>> tree = etree.ElementTree(root)
     >>> a = root[0]
    ->>> print(tree.getelementpath(a[0]))
    +>>> print(tree.getelementpath(a[0]))
     a/b[1]
    ->>> print(tree.getelementpath(a[1]))
    +>>> print(tree.getelementpath(a[1]))
     a/c
    ->>> print(tree.getelementpath(a[2]))
    +>>> print(tree.getelementpath(a[2]))
     a/b[2]
     >>> tree.find(tree.getelementpath(a[2])) == a[2]
     True
    @@ -1207,11 +1207,11 @@ of being self-contained even for documents that use namespaces.

    The .iter() method is a special case that only finds specific tags in the tree by their name, not based on a path. That means that the following commands are equivalent in the success case:

    -
    >>> print(root.find(".//b").tag)
    +
    >>> print(root.find(".//b").tag)
     b
    ->>> print(next(root.iterfind(".//b")).tag)
    +>>> print(next(root.iterfind(".//b")).tag)
     b
    ->>> print(next(root.iter("b")).tag)
    +>>> print(next(root.iter("b")).tag)
     b
     

    Note that the .find() method simply returns None if no match is found, @@ -1220,7 +1220,7 @@ whereas the other two examples would raise a StopIt

    diff --git a/doc/html/validation.html b/doc/html/validation.html index a89fb13..3562445 100644 --- a/doc/html/validation.html +++ b/doc/html/validation.html @@ -2,7 +2,7 @@ - + Validation with lxml
    -

    Validation with lxml

    +

    Validation with lxml

    Apart from the built-in DTD support in parsers, lxml currently supports three schema languages: DTD, Relax NG and XML Schema. All three provide @@ -56,7 +56,7 @@ libxml2 2.6.30.

    a DTD or an XML schema. The DTD is retrieved automatically based on the DOCTYPE of the parsed document. All you have to do is use a parser that has DTD validation enabled:

    -
    >>> parser = etree.XMLParser(dtd_validation=True)
    +
    >>> parser = etree.XMLParser(dtd_validation=True)
     

    Obviously, a request for validation enables the DTD loading feature. There are two other options that enable loading the DTD, but that do @@ -106,15 +106,15 @@ into the constructor to parse a DTD:

    Now you can use it to validate documents:

    >>> root = etree.XML("<b/>")
    ->>> print(dtd.validate(root))
    +>>> print(dtd.validate(root))
     True
     
     >>> root = etree.XML("<b><a/></b>")
    ->>> print(dtd.validate(root))
    +>>> print(dtd.validate(root))
     False
     

    The reason for the validation failure can be found in the error log:

    -
    >>> print(dtd.error_log.filter_from_errors()[0])
    +
    >>> print(dtd.error_log.filter_from_errors()[0])
     <string>:1:0:ERROR:VALID:DTD_NOT_EMPTY: Element b was declared EMPTY this one has content
     

    As an alternative to parsing from a file, you can use the @@ -127,7 +127,7 @@ in the system catalog:

    iterelements provides an iterator over the element declarations:

    >>> dtd = etree.DTD(StringIO('<!ELEMENT a EMPTY><!ELEMENT b EMPTY>'))
     >>> for el in dtd.iterelements():
    -...     print(el.name)
    +...     print(el.name)
     a
     b
     
    @@ -236,7 +236,7 @@ method. This is sometimes used in conditional statements:

    >>> invalid = StringIO('<a><c></c></a>')
     >>> doc2 = etree.parse(invalid)
     >>> if not relaxng(doc2):
    -...     print("invalid!")
    +...     print("invalid!")
     invalid!
     

    If you prefer getting an exception when validating, you can use the @@ -255,16 +255,16 @@ method. This is sometimes used in conditional statements:

    look up the error log of the validation process and check it for relevant messages:

    >>> log = relaxng.error_log
    ->>> print(log.last_error)
    +>>> print(log.last_error)
     <string>:1:0:ERROR:RELAXNGV:RELAXNG_ERR_ELEMWRONG: Did not expect element c there
     

    You can see that the error (ERROR) happened during RelaxNG validation (RELAXNGV). The message then tells you what went wrong. You can also look at the error domain and its type directly:

    >>> error = log.last_error
    ->>> print(error.domain_name)
    +>>> print(error.domain_name)
     RELAXNGV
    ->>> print(error.type_name)
    +>>> print(error.type_name)
     RELAXNG_ERR_ELEMWRONG
     

    Note that this error log is local to the RelaxNG object. It will only @@ -320,7 +320,7 @@ This is sometimes used in conditional statements:

    >>> invalid = StringIO('<a><c></c></a>')
     >>> doc2 = etree.parse(invalid)
     >>> if not xmlschema(doc2):
    -...     print("invalid!")
    +...     print("invalid!")
     invalid!
     

    If you prefer getting an exception when validating, you can use the @@ -338,9 +338,9 @@ This is sometimes used in conditional statements:

    Error reporting works as for the RelaxNG class:

    >>> log = xmlschema.error_log
     >>> error = log.last_error
    ->>> print(error.domain_name)
    +>>> print(error.domain_name)
     SCHEMASV
    ->>> print(error.type_name)
    +>>> print(error.type_name)
     SCHEMAV_ELEMENT_CONTENT
     

    If you were to print this log entry, you would get something like the @@ -405,7 +405,7 @@ This can be useful for conditional statements:

    >>> is_valid = isoschematron.Schematron(sct_doc)
     
     >>> if not is_valid(doc):
    -...     print("invalid!")
    +...     print("invalid!")
     invalid!
     

    Built on a pure-xslt implementation, the actual validator is created as an @@ -546,7 +546,7 @@ This is sometimes used in conditional statements:

    >>> is_valid = etree.Schematron(sct_doc)
     
     >>> if not is_valid(doc):
    -...     print("invalid!")
    +...     print("invalid!")
     invalid!
     

    Note that libxml2 restricts error reporting to the parsing step (when creating @@ -556,7 +556,7 @@ reporting during validation.

    diff --git a/doc/html/xpathxslt.html b/doc/html/xpathxslt.html index 89d3455..9fb005a 100644 --- a/doc/html/xpathxslt.html +++ b/doc/html/xpathxslt.html @@ -2,7 +2,7 @@ - + XPath and XSLT with lxml
    -

    XPath and XSLT with lxml

    +

    XPath and XSLT with lxml

    lxml supports XPath 1.0, XSLT 1.0 and the EXSLT extensions through libxml2 and libxslt in a standards compliant way.

    @@ -69,9 +69,15 @@ frequent evaluation: XPath and xpath() method described here.

    -

    Note that the .find*() methods are usually faster than the full-blown XPath -support. They also support incremental tree processing through the .iterfind() -method, whereas XPath always collects all results before returning them.

    +
    +

    Note

    +

    The .find*() methods are usually faster than the full-blown XPath +support. They also support incremental tree processing through the +.iterfind() method, whereas XPath always collects all results before +returning them. They are therefore recommended over XPath for both speed +and memory reasons, whenever there is no need for highly selective XPath +queries.

    +

    The xpath() method

    For ElementTree, the xpath method performs a global XPath query against the @@ -109,13 +115,13 @@ against the element (if relative) or against the root tree (if absolute):

    The xpath() method has support for XPath variables:

    >>> expr = "//*[local-name() = $name]"
     
    ->>> print(root.xpath(expr, name = "foo")[0].tag)
    +>>> print(root.xpath(expr, name = "foo")[0].tag)
     foo
     
    ->>> print(root.xpath(expr, name = "bar")[0].tag)
    +>>> print(root.xpath(expr, name = "bar")[0].tag)
     bar
     
    ->>> print(root.xpath("$text", text = "Hello World!"))
    +>>> print(root.xpath("$text", text = "Hello World!"))
     Hello World!
     
    @@ -194,14 +200,14 @@ relationship using the keyword argument smart_strin >>> find_text = etree.XPath("//text()") >>> text = find_text(root)[0] ->>> print(text) +>>> print(text) TEXT ->>> print(text.getparent().text) +>>> print(text.getparent().text) TEXT ->>> find_text = etree.XPath("//text()", smart_strings=False) +>>> find_text = etree.XPath("//text()", smart_strings=False) >>> text = find_text(root)[0] ->>> print(text) +>>> print(text) TEXT >>> hasattr(text, 'getparent') False @@ -218,7 +224,7 @@ structural, absolute XPath expression to find that element:

    >>> d2 = etree.SubElement(c, "d") >>> tree = etree.ElementTree(c) ->>> print(tree.getpath(d2)) +>>> print(tree.getpath(d2)) /c/d[2] >>> tree.xpath(tree.getpath(d2)) == [d2] True @@ -230,7 +236,7 @@ structural, absolute XPath expression to find that element:

    >>> root = etree.XML("<root><a><b/></a><b/></root>")
     
     >>> find = etree.XPath("//b")
    ->>> print(find(root)[0].tag)
    +>>> print(find(root)[0].tag)
     b
     

    The compilation takes as much time as in the xpath() method, but it is @@ -240,9 +246,9 @@ for repeated evaluation of the same XPath expression.

    variables:

    >>> count_elements = etree.XPath("count(//*[local-name() = $name])")
     
    ->>> print(count_elements(root, name = "a"))
    +>>> print(count_elements(root, name = "a"))
     1.0
    ->>> print(count_elements(root, name = "b"))
    +>>> print(count_elements(root, name = "b"))
     2.0
     

    This supports very efficient evaluation of modified versions of an XPath @@ -251,7 +257,7 @@ expression, as compilation is still only required once.

    >>> root = etree.XML("<root xmlns='NS'><a><b/></a><b/></root>")
     
     >>> find = etree.XPath("//n:b", namespaces={'n':'NS'})
    ->>> print(find(root)[0].tag)
    +>>> print(find(root)[0].tag)
     {NS}b
     
    @@ -263,7 +269,7 @@ expression, as compilation is still only required once.

    ... namespaces={'re':regexpNS}) >>> root = etree.XML("<root><a>aB</a><b>aBc</b></root>") ->>> print(find(root)[0].text) +>>> print(find(root)[0].text) aBc

    You can disable this with the boolean keyword argument regexp which @@ -278,10 +284,10 @@ XPathEvaluator helper for instantiation:

    >>> root = etree.XML("<root><a><b/></a><b/></root>")
     >>> xpatheval = etree.XPathEvaluator(root)
     
    ->>> print(isinstance(xpatheval, etree.XPathElementEvaluator))
    +>>> print(isinstance(xpatheval, etree.XPathElementEvaluator))
     True
     
    ->>> print(xpatheval("//b")[0].tag)
    +>>> print(xpatheval("//b")[0].tag)
     b
     

    This class provides efficient support for evaluating different XPath @@ -306,12 +312,12 @@ write:

    >>> root = etree.XML("<root xmlns='ns'><a><b/></a><b/></root>")
     
     >>> find = etree.XPath("//p:b", namespaces={'p' : 'ns'})
    ->>> print(find(root)[0].tag)
    +>>> print(find(root)[0].tag)
     {ns}b
     

    ETXPath allows you to change this to:

    -
    >>> find = etree.ETXPath("//{ns}b")
    ->>> print(find(root)[0].tag)
    +
    >>> find = etree.ETXPath("//{ns}b")
    +>>> print(find(root)[0].tag)
     {ns}b
     
    @@ -541,17 +547,17 @@ error log.

    >>> bytes(result) b'<?xml version="1.0"?>\n<foo>Text</foo>\n' ->>> print(transform.error_log) +>>> print(transform.error_log) <string>:0:0:ERROR:XSLT:ERR_OK: STARTING <string>:0:0:ERROR:XSLT:ERR_OK: DONE >>> for entry in transform.error_log: -... print('message from line %s, col %s: %s' % ( +... print('message from line %s, col %s: %s' % ( ... entry.line, entry.column, entry.message)) -... print('domain: %s (%d)' % (entry.domain_name, entry.domain)) -... print('type: %s (%d)' % (entry.type_name, entry.type)) -... print('level: %s (%d)' % (entry.level_name, entry.level)) -... print('filename: %s' % entry.filename) +... print('domain: %s (%d)' % (entry.domain_name, entry.domain)) +... print('type: %s (%d)' % (entry.type_name, entry.type)) +... print('level: %s (%d)' % (entry.level_name, entry.level)) +... print('filename: %s' % entry.filename) message from line 0, col 0: STARTING domain: XSLT (22) type: ERR_OK (0) @@ -616,7 +622,7 @@ maintainable.

    Profiling

    If you want to know how your stylesheet performed, pass the profile_run keyword to the transform:

    -
    >>> result = transform(doc, a="/a/b/text()", profile_run=True)
    +
    >>> result = transform(doc, a="/a/b/text()", profile_run=True)
     >>> profile = result.xslt_profile
     

    The value of the xslt_profile property is an ElementTree with profiling @@ -635,7 +641,7 @@ If you want to free it from memory, just do:

    diff --git a/doc/licenses/ZopePublicLicense.txt b/doc/licenses/ZopePublicLicense.txt deleted file mode 100644 index 44e0648..0000000 --- a/doc/licenses/ZopePublicLicense.txt +++ /dev/null @@ -1,59 +0,0 @@ -Zope Public License (ZPL) Version 2.0 ------------------------------------------------ - -This software is Copyright (c) Zope Corporation (tm) and -Contributors. All rights reserved. - -This license has been certified as open source. It has also -been designated as GPL compatible by the Free Software -Foundation (FSF). - -Redistribution and use in source and binary forms, with or -without modification, are permitted provided that the -following conditions are met: - -1. Redistributions in source code must retain the above - copyright notice, this list of conditions, and the following - disclaimer. - -2. Redistributions in binary form must reproduce the above - copyright notice, this list of conditions, and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - -3. The name Zope Corporation (tm) must not be used to - endorse or promote products derived from this software - without prior written permission from Zope Corporation. - -4. The right to distribute this software or to use it for - any purpose does not give you the right to use Servicemarks - (sm) or Trademarks (tm) of Zope Corporation. Use of them is - covered in a separate agreement (see - http://www.zope.com/Marks). - -5. If any files are modified, you must cause the modified - files to carry prominent notices stating that you changed - the files and the date of any change. - -Disclaimer - - THIS SOFTWARE IS PROVIDED BY ZOPE CORPORATION ``AS IS'' - AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT - NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - NO EVENT SHALL ZOPE CORPORATION OR ITS CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - DAMAGE. - - -This software consists of contributions made by Zope -Corporation and many individuals on behalf of Zope -Corporation. Specific attributions are listed in the -accompanying credits file. diff --git a/doc/main.txt b/doc/main.txt index ead457d..75fedd5 100644 --- a/doc/main.txt +++ b/doc/main.txt @@ -159,8 +159,8 @@ Index `_ (PyPI). It has the source that compiles on various platforms. The source distribution is signed with `this key `_. -The latest version is `lxml 4.6.3`_, released 2021-03-21 -(`changes for 4.6.3`_). `Older versions <#old-versions>`_ +The latest version is `lxml 4.6.4`_, released 2021-11-01 +(`changes for 4.6.4`_). `Older versions <#old-versions>`_ are listed below. Please take a look at the @@ -256,7 +256,9 @@ See the websites of lxml .. and the `latest in-development version `_. -.. _`PDF documentation`: lxmldoc-4.6.3.pdf +.. _`PDF documentation`: lxmldoc-4.6.4.pdf + +* `lxml 4.6.4`_, released 2021-11-01 (`changes for 4.6.4`_) * `lxml 4.6.3`_, released 2021-03-21 (`changes for 4.6.3`_) @@ -282,6 +284,7 @@ See the websites of lxml * `older releases `_ +.. _`lxml 4.6.4`: /files/lxml-4.6.4.tgz .. _`lxml 4.6.3`: /files/lxml-4.6.3.tgz .. _`lxml 4.6.2`: /files/lxml-4.6.2.tgz .. _`lxml 4.6.1`: /files/lxml-4.6.1.tgz @@ -294,6 +297,7 @@ See the websites of lxml .. _`lxml 4.4.1`: /files/lxml-4.4.1.tgz .. _`lxml 4.4.0`: /files/lxml-4.4.0.tgz +.. _`changes for 4.6.4`: /changes-4.6.4.html .. _`changes for 4.6.3`: /changes-4.6.3.html .. _`changes for 4.6.2`: /changes-4.6.2.html .. _`changes for 4.6.1`: /changes-4.6.1.html diff --git a/doc/mkhtml.py b/doc/mkhtml.py index c652335..36da5de 100644 --- a/doc/mkhtml.py +++ b/doc/mkhtml.py @@ -194,7 +194,7 @@ def convert_changelog(lxml_path, changelog_file_path, rst2html_script, styleshee out_file.close() -def publish(dirname, lxml_path, release): +def publish(dirname, lxml_path, release, with_donations=True): if not os.path.exists(dirname): os.mkdir(dirname) @@ -245,7 +245,8 @@ def publish(dirname, lxml_path, release): menu = Element("div", {'class': 'sidemenu', 'id': 'sidemenu'}) SubElement(menu, 'div', {'class': 'menutrigger', 'onclick': 'trigger_menu(event)'}).text = "Menu" menu_div = SubElement(menu, 'div', {'class': 'menu'}) - inject_banner(menu_div) + if with_donations: + inject_banner(menu_div) # build HTML pages and parse them back for section, text_files in SITE_STRUCTURE: @@ -266,13 +267,14 @@ def publish(dirname, lxml_path, release): rest2html(script, path, outpath, stylesheet_url) tree = parse(outpath) - page_div = tree.getroot()[1][0] # html->body->div[class=document] - inject_banner(page_div) + if with_donations: + page_div = tree.getroot()[1][0] # html->body->div[class=document] + inject_banner(page_div) - if filename == 'main.txt': - # inject donation buttons - #inject_flatter_button(tree) - inject_donate_buttons(lxml_path, script, tree) + if filename == 'main.txt': + # inject donation buttons + #inject_flatter_button(tree) + inject_donate_buttons(lxml_path, script, tree) trees[filename] = (tree, basename, outpath) build_menu(tree, basename, section_head) @@ -324,4 +326,7 @@ def publish(dirname, lxml_path, release): if __name__ == '__main__': - publish(sys.argv[1], sys.argv[2], sys.argv[3]) + no_donations = '--no-donations' in sys.argv[1:] + if no_donations: + sys.argv.remove('--no-donations') + publish(sys.argv[1], sys.argv[2], sys.argv[3], with_donations=not no_donations) diff --git a/doc/mklatex.py b/doc/mklatex.py index 4151dc8..2bb73b7 100644 --- a/doc/mklatex.py +++ b/doc/mklatex.py @@ -63,6 +63,10 @@ PYGMENTS_IMPORT = r""" \input{_part_pygments.tex} """ +EPYDOC_IMPORT = r""" +\input{_part_epydoc.tex} +""" + def write_chapter(master, title, filename): filename = os.path.join(os.path.dirname(filename), "_part_%s" % os.path.basename(filename)) @@ -175,7 +179,6 @@ def tex_postprocess(src_path, dest_path, want_header=False, process_line=noop): raise Exception("Bueee, no title in %s" % src_path) return title, header - def publish(dirname, lxml_path, release): if not os.path.exists(dirname): os.mkdir(dirname) @@ -250,12 +253,12 @@ def publish(dirname, lxml_path, release): # integrate generated API docs print("Integrating API docs") - apidocsname = 'lxml.tex' - apipath = os.path.join(dirname, "..", "api", "_build", "latex", apidocsname) + apidocsname = 'api.tex' + apipath = os.path.join(dirname, apidocsname) tex_postprocess(apipath, os.path.join(dirname, "_part_%s" % apidocsname), process_line=fix_relative_hyperrefs) - #copy_epydoc_macros(apipath, os.path.join(dirname, '_part_epydoc.tex'), - # set(header)) + copy_epydoc_macros(apipath, os.path.join(dirname, '_part_epydoc.tex'), + set(header)) # convert CHANGES.txt @@ -284,9 +287,9 @@ def publish(dirname, lxml_path, release): for hln in header: if hln.startswith(r"\documentclass"): #hln = hln.replace('article', 'book') - hln = DOCUMENT_CLASS + hln = DOCUMENT_CLASS + EPYDOC_IMPORT elif hln.startswith(r"\begin{document}"): - # pygments support + # pygments and epydoc support master.write(PYGMENTS_IMPORT) elif hln.startswith(r"\title{"): hln = replace_content( diff --git a/doc/pdf/pubkey.asc b/doc/pdf/pubkey.asc deleted file mode 100644 index f72804c..0000000 --- a/doc/pdf/pubkey.asc +++ /dev/null @@ -1,36 +0,0 @@ ------BEGIN PGP PUBLIC KEY BLOCK----- -Version: GnuPG v1.4.2 (GNU/Linux) - -mQGiBEQf3JQRBACciSqxoX0q3VurkRENVVtG/pVqtFh/d2CohbVJlLCrO4s7nnPj -CTfZFt6tmykZjsLJl24XpEJt0O/C0jLcaBqvXVgVvRXHz4DjEYYuQF4LPthhI4MA -4T7ExptX4lU5g3BVJ46vPU8uRBbbxarBRas9rYewgnrYKWpZZCa7yMq+9wCgnyyR -Si4E3viLwi77jda135nA6vcD/iqu8zIl9/dFuUcOvxJrhrm+UdY72puZ1TVczSAH -GOqMjrKkfyHlaJh/ZzWENpTZIfOdVhy7Chvva18vH4Wz7jKj5UeIpRrBvjAD28r3 -Y3W5bfsnpPkvDOyU1vqBsw4q+/250GXEX0JqV2Rbf5yLVgEZPdGrswO460dr4UVS -8RS0BACYTmyrz57AugHc5tRkqNw6o7ux2deOT0c3AbUcOWtOocGumCsUf+M1nOrc -VWkeBWTv4HIIiecWYY/KwIemTthQGjxywaZDxOlBT0BOL/+vfYTq/plZULXr+g90 -rSe82+kLl9N5onkBDJKeDIcJDzRoxIRPV1i0Om/5JBI4jmUnv7QnU3RlZmFuIEJl -aG5lbCA8c2NvZGVyQHVzZXJzLmJlcmxpb3MuZGU+iF8EExECACAFAkQiqKYCGwMG -CwkIBwMCBBUCCAMEFgIDAQIeAQIXgAAKCRANPVNpCNOgHi+2AJ0a0JH8iP3RqrOL -JefvHz1dSl3MxACYo7Ma6CeIgsGnyaSSdNOmNVXn+IhGBBARAgAGBQJEIqk0AAoJ -ELO5mMzzmgZbmCcAoKZ2En1IlsxBpaPPxgWYrUOWfc6hAKCBWODMMOYptCBkSrjg -m3gsrjHgYbQsU3RlZmFuIEJlaG5lbCA8c2NvZGVyQHVzZXJzLnNvdXJjZWZvcmdl -Lm5ldD6IYAQTEQIAIAUCRB/clAIbAwYLCQgHAwIEFQIIAwQWAgMBAh4BAheAAAoJ -EA09U2kI06Aen2YAn0hvuDs+Gslq9vPRFFbsFNJI40PmAJ0chjiiEy0xV5C+n6YX -XFuldRDILYhGBBARAgAGBQJEIp4AAAoJELO5mMzzmgZbgKQAn3pWrmFdj8YaEyuR -tEjKVZJDQ6ZVAJ0Y1igwADT40BPra+G/xiLa3YbCrrkCDQREH9ynEAgAiR4/0r0d -doViNECfSLClllu5K0Bo1SEiMtvVNC3sJYgVzBddD8Xn8UAdjyAgmaL5FC2FsNQu -RxxKkNlHNYCq8ZSWtZaL2MQ+SyMUyHv6VXVCGuSW0COpzbx58u+SZpjyESJ1kaZc -73SaIw6kv/dVQHjurwmlo1lg3dLZ3PG08WGCYUMqkkv2K+J7+puzE2Cjo31gTq4s -LYDCV26wjVQ6BqT2EcHQhVEjh0xq5ugc908cr/2FQAKkTifEbF+OVBGWiFMGgri+ -6+G54/BV/RakpvNCFYBiZHn/M9mQaWt7XoTmnEQ1ldq5KNlRhkqnQRF/NK5VpGcQ -29As28aqpZTECwADBgf/WlRvBRI1Q1eIv2falEv7C6sOxqc3kr5z1uUBTRG5v9t6 -ff9k/J4oC6cnQx00GK3ZR8ija6bl8zwu+0m0M3rW49Krb1rsiT7r4ahOZ7p9RRro -oG3NbUJYgMG10D1nxpaioYqa/m+PpILJM0wfYZZEuX0xkZcOB24yb+J7EIcGR09T -mMd5sXtdTU+w/p7Xi2cP61uQ8qixyHBH8E06qgW2JtVFV9rGn7CNUOvkNaUBRnY5 -QxhdkvKJRx7voOLYWZFUBIWgto+6vmTgKmc2Ho6qddzME9UgwUNcknRgm0cf6Cxr -6zPtxZl8a6KemjQcK7kARSmMNCDkqp/Pohe519A5vYhJBBgRAgAJBQJEH9ynAhsM -AAoJEA09U2kI06Aesv4AnjiVQVLzqnNS/64vvMMP1UARY3HtAJ90YxNGhRNIhWYL -UU16oJlGD/9M1Q== -=gWy2 ------END PGP PUBLIC KEY BLOCK----- diff --git a/doc/performance.txt b/doc/performance.txt index 1a0c9ad..c6f2edb 100644 --- a/doc/performance.txt +++ b/doc/performance.txt @@ -88,18 +88,11 @@ very easy to add as tiny test methods, so if you write a performance test for a specific part of the API yourself, please consider sending it to the lxml mailing list. -The timings presented below compare lxml 3.1.1 (with libxml2 2.9.0) to the +The timings presented below compare lxml 4.6.3 (with libxml2 2.9.10) to the latest released versions of ElementTree (with cElementTree as accelerator -module) in the standard library of CPython 3.3.0. They were run -single-threaded on a 2.9GHz 64bit double core Intel i7 machine under -Ubuntu Linux 12.10 (Quantal). The C libraries were compiled with the -same platform specific optimisation flags. The Python interpreter was -also manually compiled for the platform. Note that many of the following -ElementTree timings are therefore better than what a normal Python -installation with the standard library (c)ElementTree modules would yield. -Note also that CPython 2.7 and 3.2+ come with a newer ElementTree version, -so older Python installations will not perform as good for (c)ElementTree, -and sometimes substantially worse. +module) in the standard library of CPython 3.8.10. They were run +single-threaded on a 2.3GHz 64bit double core Intel i5 machine under +Ubuntu Linux 20.04 (Focal). .. _`bench_etree.py`: https://github.com/lxml/lxml/blob/master/benchmark/bench_etree.py .. _`bench_xpath.py`: https://github.com/lxml/lxml/blob/master/benchmark/bench_xpath.py @@ -141,50 +134,50 @@ is native to libxml2. While 20 to 40 times faster than (c)ElementTree lxml is still more than 10 times as fast as the much improved ElementTree 1.3 in recent Python versions:: - lxe: tostring_utf16 (S-TR T1) 7.9958 msec/pass - cET: tostring_utf16 (S-TR T1) 83.1358 msec/pass + lxe: tostring_utf16 (S-TR T1) 5.9340 msec/pass + cET: tostring_utf16 (S-TR T1) 38.3270 msec/pass - lxe: tostring_utf16 (UATR T1) 8.3222 msec/pass - cET: tostring_utf16 (UATR T1) 84.4688 msec/pass + lxe: tostring_utf16 (UATR T1) 6.2032 msec/pass + cET: tostring_utf16 (UATR T1) 37.7944 msec/pass - lxe: tostring_utf16 (S-TR T2) 8.2297 msec/pass - cET: tostring_utf16 (S-TR T2) 87.3415 msec/pass + lxe: tostring_utf16 (S-TR T2) 6.1841 msec/pass + cET: tostring_utf16 (S-TR T2) 40.2577 msec/pass - lxe: tostring_utf8 (S-TR T2) 6.5677 msec/pass - cET: tostring_utf8 (S-TR T2) 76.2064 msec/pass + lxe: tostring_utf8 (S-TR T2) 4.6697 msec/pass + cET: tostring_utf8 (S-TR T2) 30.5173 msec/pass - lxe: tostring_utf8 (U-TR T3) 1.1952 msec/pass - cET: tostring_utf8 (U-TR T3) 22.0058 msec/pass + lxe: tostring_utf8 (U-TR T3) 1.2085 msec/pass + cET: tostring_utf8 (U-TR T3) 9.0246 msec/pass The difference is somewhat smaller for plain text serialisation:: - lxe: tostring_text_ascii (S-TR T1) 2.7738 msec/pass - cET: tostring_text_ascii (S-TR T1) 4.7629 msec/pass + lxe: tostring_text_ascii (S-TR T1) 2.6727 msec/pass + cET: tostring_text_ascii (S-TR T1) 2.9683 msec/pass - lxe: tostring_text_ascii (S-TR T3) 0.8273 msec/pass - cET: tostring_text_ascii (S-TR T3) 1.5273 msec/pass + lxe: tostring_text_ascii (S-TR T3) 0.6952 msec/pass + cET: tostring_text_ascii (S-TR T3) 1.0073 msec/pass - lxe: tostring_text_utf16 (S-TR T1) 2.7659 msec/pass - cET: tostring_text_utf16 (S-TR T1) 10.5038 msec/pass + lxe: tostring_text_utf16 (S-TR T1) 2.7366 msec/pass + cET: tostring_text_utf16 (S-TR T1) 7.3647 msec/pass - lxe: tostring_text_utf16 (U-TR T1) 2.8017 msec/pass - cET: tostring_text_utf16 (U-TR T1) 10.5207 msec/pass + lxe: tostring_text_utf16 (U-TR T1) 3.0322 msec/pass + cET: tostring_text_utf16 (U-TR T1) 7.5922 msec/pass The ``tostring()`` function also supports serialisation to a Python unicode string object, which is currently faster in ElementTree -under CPython 3.3:: +under CPython 3.8:: - lxe: tostring_text_unicode (S-TR T1) 2.6896 msec/pass - cET: tostring_text_unicode (S-TR T1) 1.0056 msec/pass + lxe: tostring_text_unicode (S-TR T1) 2.7645 msec/pass + cET: tostring_text_unicode (S-TR T1) 1.1806 msec/pass - lxe: tostring_text_unicode (U-TR T1) 2.7366 msec/pass - cET: tostring_text_unicode (U-TR T1) 1.0154 msec/pass + lxe: tostring_text_unicode (U-TR T1) 2.9871 msec/pass + cET: tostring_text_unicode (U-TR T1) 1.1659 msec/pass - lxe: tostring_text_unicode (S-TR T3) 0.7997 msec/pass - cET: tostring_text_unicode (S-TR T3) 0.3154 msec/pass + lxe: tostring_text_unicode (S-TR T3) 0.7446 msec/pass + cET: tostring_text_unicode (S-TR T3) 0.4532 msec/pass lxe: tostring_text_unicode (U-TR T4) 0.0048 msec/pass - cET: tostring_text_unicode (U-TR T4) 0.0160 msec/pass + cET: tostring_text_unicode (U-TR T4) 0.0134 msec/pass For parsing, lxml.etree and cElementTree compete for the medal. Depending on the input, either of the two can be faster. The (c)ET @@ -192,37 +185,37 @@ libraries use a very thin layer on top of the expat parser, which is known to be very fast. Here are some timings from the benchmarking suite:: - lxe: parse_bytesIO (SAXR T1) 13.0246 msec/pass - cET: parse_bytesIO (SAXR T1) 8.2929 msec/pass + lxe: parse_bytesIO (SAXR T1) 14.2074 msec/pass + cET: parse_bytesIO (SAXR T1) 7.9336 msec/pass - lxe: parse_bytesIO (S-XR T3) 1.3542 msec/pass - cET: parse_bytesIO (S-XR T3) 2.4023 msec/pass + lxe: parse_bytesIO (S-XR T3) 1.4477 msec/pass + cET: parse_bytesIO (S-XR T3) 2.1925 msec/pass - lxe: parse_bytesIO (UAXR T3) 7.5610 msec/pass - cET: parse_bytesIO (UAXR T3) 11.2455 msec/pass + lxe: parse_bytesIO (UAXR T3) 8.4128 msec/pass + cET: parse_bytesIO (UAXR T3) 12.2926 msec/pass And another couple of timings `from a benchmark`_ that Fredrik Lundh `used to promote cElementTree`_, comparing a number of different parsers. First, parsing a 274KB XML file containing Shakespeare's Hamlet:: - xml.etree.ElementTree.parse done in 0.017 seconds + xml.etree.ElementTree.parse done in 0.006 seconds xml.etree.cElementTree.parse done in 0.007 seconds - xml.etree.cElementTree.XMLParser.feed(): 6636 nodes read in 0.007 seconds - lxml.etree.parse done in 0.003 seconds - drop_whitespace.parse done in 0.003 seconds + xml.etree.cElementTree.XMLParser.feed(): 6636 nodes read in 0.006 seconds + lxml.etree.parse done in 0.004 seconds + drop_whitespace.parse done in 0.004 seconds lxml.etree.XMLParser.feed(): 6636 nodes read in 0.004 seconds - minidom tree read in 0.080 seconds + minidom tree read in 0.066 seconds And a 3.4MB XML file containing the Old Testament:: - xml.etree.ElementTree.parse done in 0.038 seconds - xml.etree.cElementTree.parse done in 0.030 seconds - xml.etree.cElementTree.XMLParser.feed(): 25317 nodes read in 0.030 seconds - lxml.etree.parse done in 0.016 seconds - drop_whitespace.parse done in 0.015 seconds - lxml.etree.XMLParser.feed(): 25317 nodes read in 0.022 seconds - minidom tree read in 0.288 seconds + xml.etree.ElementTree.parse done in 0.037 seconds + xml.etree.cElementTree.parse done in 0.036 seconds + xml.etree.cElementTree.XMLParser.feed(): 25317 nodes read in 0.036 seconds + lxml.etree.parse done in 0.025 seconds + drop_whitespace.parse done in 0.022 seconds + lxml.etree.XMLParser.feed(): 25317 nodes read in 0.026 seconds + minidom tree read in 0.194 seconds .. _`from a benchmark`: http://svn.effbot.org/public/elementtree-1.3/benchmark.py .. _`used to promote cElementTree`: http://effbot.org/zone/celementtree.htm#benchmarks @@ -232,43 +225,42 @@ of the process in KB before and after parsing (using os.fork() to make sure we start from a clean state each time). For the 274KB hamlet.xml file:: - Memory usage: 7284 - xml.etree.ElementTree.parse done in 0.017 seconds - Memory usage: 9432 (+2148) + Memory usage: 9256 + xml.etree.ElementTree.parse done in 0.006 seconds + Memory usage: 12764 (+3508) xml.etree.cElementTree.parse done in 0.007 seconds - Memory usage: 9432 (+2152) - xml.etree.cElementTree.XMLParser.feed(): 6636 nodes read in 0.007 seconds - Memory usage: 9448 (+2164) - lxml.etree.parse done in 0.003 seconds - Memory usage: 11032 (+3748) - drop_whitespace.parse done in 0.003 seconds - Memory usage: 10224 (+2940) + Memory usage: 12764 (+3508) + xml.etree.cElementTree.XMLParser.feed(): 6636 nodes read in 0.006 seconds + Memory usage: 12720 (+3464) + lxml.etree.parse done in 0.004 seconds + Memory usage: 15052 (+5796) + drop_whitespace.parse done in 0.004 seconds + Memory usage: 14040 (+4784) lxml.etree.XMLParser.feed(): 6636 nodes read in 0.004 seconds - Memory usage: 11804 (+4520) - minidom tree read in 0.080 seconds - Memory usage: 12324 (+5040) + Memory usage: 15812 (+6556) + minidom tree read in 0.066 seconds + Memory usage: 15332 (+6076) And for the 3.4MB Old Testament XML file:: - Memory usage: 10420 - xml.etree.ElementTree.parse done in 0.038 seconds - Memory usage: 20660 (+10240) - xml.etree.cElementTree.parse done in 0.030 seconds - Memory usage: 20660 (+10240) - xml.etree.cElementTree.XMLParser.feed(): 25317 nodes read in 0.030 seconds - Memory usage: 20844 (+10424) - lxml.etree.parse done in 0.016 seconds - Memory usage: 27624 (+17204) - drop_whitespace.parse done in 0.015 seconds - Memory usage: 24468 (+14052) - lxml.etree.XMLParser.feed(): 25317 nodes read in 0.022 seconds - Memory usage: 29844 (+19424) - minidom tree read in 0.288 seconds - Memory usage: 28788 (+18368) + Memory usage: 12456 + xml.etree.ElementTree.parse done in 0.037 seconds + Memory usage: 23288 (+10832) + xml.etree.cElementTree.parse done in 0.036 seconds + Memory usage: 23288 (+10832) + xml.etree.cElementTree.XMLParser.feed(): 25317 nodes read in 0.036 seconds + Memory usage: 23644 (+11220) + lxml.etree.parse done in 0.025 seconds + Memory usage: 31404 (+18948) + drop_whitespace.parse done in 0.022 seconds + Memory usage: 28752 (+16296) + lxml.etree.XMLParser.feed(): 25317 nodes read in 0.026 seconds + Memory usage: 33924 (+21500) + minidom tree read in 0.194 seconds + Memory usage: 31284 (+18828) As can be seen from the sizes, both lxml.etree and cElementTree are -rather memory friendly compared to the pure Python libraries -ElementTree and (especially) minidom. Comparing to older CPython +rather memory friendly and fast. Comparing to older CPython versions, the memory footprint of the minidom library was considerably reduced in CPython 3.3, by about a factor of 4 in this case. @@ -277,26 +269,26 @@ rather close to each other, usually within a factor of two, with winners well distributed over both sides. Similar timings can be observed for the ``iterparse()`` function:: - lxe: iterparse_bytesIO (SAXR T1) 17.9198 msec/pass - cET: iterparse_bytesIO (SAXR T1) 14.4982 msec/pass + lxe: iterparse_bytesIO (SAXR T1) 20.3598 msec/pass + cET: iterparse_bytesIO (SAXR T1) 10.8948 msec/pass - lxe: iterparse_bytesIO (UAXR T3) 8.8522 msec/pass - cET: iterparse_bytesIO (UAXR T3) 12.9857 msec/pass + lxe: iterparse_bytesIO (UAXR T3) 10.1640 msec/pass + cET: iterparse_bytesIO (UAXR T3) 12.9926 msec/pass However, if you benchmark the complete round-trip of a serialise-parse cycle, the numbers will look similar to these:: - lxe: write_utf8_parse_bytesIO (S-TR T1) 19.8867 msec/pass - cET: write_utf8_parse_bytesIO (S-TR T1) 80.7259 msec/pass + lxe: write_utf8_parse_bytesIO (S-TR T1) 18.9857 msec/pass + cET: write_utf8_parse_bytesIO (S-TR T1) 35.7475 msec/pass - lxe: write_utf8_parse_bytesIO (UATR T2) 23.7896 msec/pass - cET: write_utf8_parse_bytesIO (UATR T2) 98.0766 msec/pass + lxe: write_utf8_parse_bytesIO (UATR T2) 22.4853 msec/pass + cET: write_utf8_parse_bytesIO (UATR T2) 42.6254 msec/pass - lxe: write_utf8_parse_bytesIO (S-TR T3) 3.0684 msec/pass - cET: write_utf8_parse_bytesIO (S-TR T3) 24.6122 msec/pass + lxe: write_utf8_parse_bytesIO (S-TR T3) 3.3801 msec/pass + cET: write_utf8_parse_bytesIO (S-TR T3) 11.2493 msec/pass - lxe: write_utf8_parse_bytesIO (SATR T4) 0.3495 msec/pass - cET: write_utf8_parse_bytesIO (SATR T4) 1.9610 msec/pass + lxe: write_utf8_parse_bytesIO (SATR T4) 0.4263 msec/pass + cET: write_utf8_parse_bytesIO (SATR T4) 1.0326 msec/pass For applications that require a high parser throughput of large files, and that do little to no serialization, both cET and lxml.etree are a @@ -352,14 +344,14 @@ restructuring. This can be seen from the tree setup times of the benchmark (given in seconds):: lxe: -- S- U- -A SA UA - T1: 0.0299 0.0343 0.0344 0.0293 0.0345 0.0342 - T2: 0.0368 0.0423 0.0418 0.0427 0.0474 0.0459 - T3: 0.0088 0.0084 0.0086 0.0251 0.0258 0.0261 - T4: 0.0002 0.0002 0.0002 0.0005 0.0006 0.0006 + T1: 0.0219 0.0254 0.0257 0.0216 0.0259 0.0259 + T2: 0.0234 0.0279 0.0283 0.0271 0.0318 0.0307 + T3: 0.0051 0.0050 0.0058 0.0218 0.0233 0.0231 + T4: 0.0001 0.0001 0.0001 0.0004 0.0004 0.0004 cET: -- S- U- -A SA UA - T1: 0.0050 0.0045 0.0093 0.0044 0.0043 0.0043 - T2: 0.0073 0.0075 0.0074 0.0201 0.0075 0.0074 - T3: 0.0033 0.0213 0.0032 0.0034 0.0033 0.0035 + T1: 0.0035 0.0029 0.0078 0.0031 0.0031 0.0029 + T2: 0.0047 0.0051 0.0053 0.0046 0.0055 0.0048 + T3: 0.0016 0.0216 0.0027 0.0021 0.0023 0.0026 T4: 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 The timings are somewhat close to each other, although cET can be @@ -379,30 +371,30 @@ The same tree overhead makes operations like collecting children as in a shallow copy of their list of children, lxml has to create a Python object for each child and collect them in a list:: - lxe: root_list_children (--TR T1) 0.0038 msec/pass - cET: root_list_children (--TR T1) 0.0010 msec/pass + lxe: root_list_children (--TR T1) 0.0036 msec/pass + cET: root_list_children (--TR T1) 0.0005 msec/pass - lxe: root_list_children (--TR T2) 0.0455 msec/pass - cET: root_list_children (--TR T2) 0.0050 msec/pass + lxe: root_list_children (--TR T2) 0.0634 msec/pass + cET: root_list_children (--TR T2) 0.0086 msec/pass This handicap is also visible when accessing single children:: - lxe: first_child (--TR T2) 0.0424 msec/pass - cET: first_child (--TR T2) 0.0384 msec/pass + lxe: first_child (--TR T2) 0.0601 msec/pass + cET: first_child (--TR T2) 0.0548 msec/pass - lxe: last_child (--TR T1) 0.0477 msec/pass - cET: last_child (--TR T1) 0.0467 msec/pass + lxe: last_child (--TR T1) 0.0570 msec/pass + cET: last_child (--TR T1) 0.0534 msec/pass ... unless you also add the time to find a child index in a bigger list. ET and cET use Python lists here, which are based on arrays. The data structure used by libxml2 is a linked tree, and thus, a linked list of children:: - lxe: middle_child (--TR T1) 0.0710 msec/pass - cET: middle_child (--TR T1) 0.0420 msec/pass + lxe: middle_child (--TR T1) 0.0892 msec/pass + cET: middle_child (--TR T1) 0.0510 msec/pass - lxe: middle_child (--TR T2) 1.7393 msec/pass - cET: middle_child (--TR T2) 0.0396 msec/pass + lxe: middle_child (--TR T2) 2.3038 msec/pass + cET: middle_child (--TR T2) 0.0508 msec/pass Element creation @@ -412,18 +404,18 @@ As opposed to ET, libxml2 has a notion of documents that each element must be in. This results in a major performance difference for creating independent Elements that end up in independently created documents:: - lxe: create_elements (--TC T2) 1.0045 msec/pass - cET: create_elements (--TC T2) 0.0753 msec/pass + lxe: create_elements (--TC T2) 0.8032 msec/pass + cET: create_elements (--TC T2) 0.0675 msec/pass Therefore, it is always preferable to create Elements for the document they are supposed to end up in, either as SubElements of an Element or using the explicit ``Element.makeelement()`` call:: - lxe: makeelement (--TC T2) 1.0586 msec/pass - cET: makeelement (--TC T2) 0.1483 msec/pass + lxe: makeelement (--TC T2) 0.8030 msec/pass + cET: makeelement (--TC T2) 0.0625 msec/pass - lxe: create_subelements (--TC T2) 0.8826 msec/pass - cET: create_subelements (--TC T2) 0.0827 msec/pass + lxe: create_subelements (--TC T2) 0.8621 msec/pass + cET: create_subelements (--TC T2) 0.0923 msec/pass So, if the main performance bottleneck of an application is creating large XML trees in memory through calls to Element and SubElement, cET is the best @@ -440,11 +432,11 @@ requires lxml to do recursive adaptations throughout the moved tree structure. The following benchmark appends all root children of the second tree to the root of the first tree:: - lxe: append_from_document (--TR T1,T2) 1.0812 msec/pass - cET: append_from_document (--TR T1,T2) 0.1104 msec/pass + lxe: append_from_document (--TR T1,T2) 1.3800 msec/pass + cET: append_from_document (--TR T1,T2) 0.0513 msec/pass - lxe: append_from_document (--TR T3,T4) 0.0155 msec/pass - cET: append_from_document (--TR T3,T4) 0.0060 msec/pass + lxe: append_from_document (--TR T3,T4) 0.0150 msec/pass + cET: append_from_document (--TR T3,T4) 0.0026 msec/pass Although these are fairly small numbers compared to parsing, this easily shows the different performance classes for lxml and (c)ET. Where the latter do not @@ -455,19 +447,19 @@ with the size of the tree that is moved. This difference is not always as visible, but applies to most parts of the API, like inserting newly created elements:: - lxe: insert_from_document (--TR T1,T2) 3.9763 msec/pass - cET: insert_from_document (--TR T1,T2) 0.1459 msec/pass + lxe: insert_from_document (--TR T1,T2) 5.2345 msec/pass + cET: insert_from_document (--TR T1,T2) 0.0732 msec/pass or replacing the child slice by a newly created element:: - lxe: replace_children_element (--TC T1) 0.0749 msec/pass - cET: replace_children_element (--TC T1) 0.0081 msec/pass + lxe: replace_children_element (--TC T1) 0.0720 msec/pass + cET: replace_children_element (--TC T1) 0.0105 msec/pass as opposed to replacing the slice with an existing element from the same document:: - lxe: replace_children (--TC T1) 0.0052 msec/pass - cET: replace_children (--TC T1) 0.0036 msec/pass + lxe: replace_children (--TC T1) 0.0060 msec/pass + cET: replace_children (--TC T1) 0.0050 msec/pass While these numbers are too small to provide a major performance impact in practice, you should keep this difference in mind when you @@ -481,14 +473,14 @@ deepcopy Deep copying a tree is fast in lxml:: - lxe: deepcopy_all (--TR T1) 3.1650 msec/pass - cET: deepcopy_all (--TR T1) 53.9973 msec/pass + lxe: deepcopy_all (--TR T1) 4.1246 msec/pass + cET: deepcopy_all (--TR T1) 2.5451 msec/pass - lxe: deepcopy_all (-ATR T2) 3.7365 msec/pass - cET: deepcopy_all (-ATR T2) 61.6267 msec/pass + lxe: deepcopy_all (-ATR T2) 4.7867 msec/pass + cET: deepcopy_all (-ATR T2) 2.7504 msec/pass - lxe: deepcopy_all (S-TR T3) 0.7913 msec/pass - cET: deepcopy_all (S-TR T3) 13.6220 msec/pass + lxe: deepcopy_all (S-TR T3) 1.0097 msec/pass + cET: deepcopy_all (S-TR T3) 0.6278 msec/pass So, for example, if you have a database-like scenario where you parse in a large tree and then search and copy independent subtrees from it for further @@ -504,31 +496,31 @@ traversal of the XML tree and especially if few elements are of interest or the target element tag name is known, the ``.iter()`` method is a good choice:: - lxe: iter_all (--TR T1) 1.0529 msec/pass - cET: iter_all (--TR T1) 0.2635 msec/pass + lxe: iter_all (--TR T1) 1.3661 msec/pass + cET: iter_all (--TR T1) 0.2670 msec/pass - lxe: iter_islice (--TR T2) 0.0110 msec/pass - cET: iter_islice (--TR T2) 0.0050 msec/pass + lxe: iter_islice (--TR T2) 0.0122 msec/pass + cET: iter_islice (--TR T2) 0.0033 msec/pass - lxe: iter_tag (--TR T2) 0.0079 msec/pass - cET: iter_tag (--TR T2) 0.0112 msec/pass + lxe: iter_tag (--TR T2) 0.0098 msec/pass + cET: iter_tag (--TR T2) 0.0086 msec/pass - lxe: iter_tag_all (--TR T2) 0.1822 msec/pass - cET: iter_tag_all (--TR T2) 0.5343 msec/pass + lxe: iter_tag_all (--TR T2) 0.6840 msec/pass + cET: iter_tag_all (--TR T2) 0.4323 msec/pass This translates directly into similar timings for ``Element.findall()``:: - lxe: findall (--TR T2) 1.7176 msec/pass - cET: findall (--TR T2) 0.9973 msec/pass + lxe: findall (--TR T2) 3.9611 msec/pass + cET: findall (--TR T2) 0.9227 msec/pass - lxe: findall (--TR T3) 0.3967 msec/pass - cET: findall (--TR T3) 0.2525 msec/pass + lxe: findall (--TR T3) 0.3989 msec/pass + cET: findall (--TR T3) 0.2670 msec/pass - lxe: findall_tag (--TR T2) 0.2258 msec/pass - cET: findall_tag (--TR T2) 0.5770 msec/pass + lxe: findall_tag (--TR T2) 0.7420 msec/pass + cET: findall_tag (--TR T2) 0.4942 msec/pass - lxe: findall_tag (--TR T3) 0.1085 msec/pass - cET: findall_tag (--TR T3) 0.1919 msec/pass + lxe: findall_tag (--TR T3) 0.1099 msec/pass + cET: findall_tag (--TR T3) 0.1748 msec/pass Note that all three libraries currently use the same Python implementation for ``.findall()``, except for their native tree @@ -548,38 +540,38 @@ provides more than one way of accessing it and you should take care which part of the lxml API you use. The most straight forward way is to call the ``xpath()`` method on an Element or ElementTree:: - lxe: xpath_method (--TC T1) 0.3982 msec/pass - lxe: xpath_method (--TC T2) 7.8895 msec/pass - lxe: xpath_method (--TC T3) 0.0477 msec/pass - lxe: xpath_method (--TC T4) 0.3982 msec/pass + lxe: xpath_method (--TC T1) 0.2828 msec/pass + lxe: xpath_method (--TC T2) 5.4705 msec/pass + lxe: xpath_method (--TC T3) 0.0324 msec/pass + lxe: xpath_method (--TC T4) 0.2804 msec/pass This is well suited for testing and when the XPath expressions are as diverse as the trees they are called on. However, if you have a single XPath expression that you want to apply to a larger number of different elements, the ``XPath`` class is the most efficient way to do it:: - lxe: xpath_class (--TC T1) 0.0713 msec/pass - lxe: xpath_class (--TC T2) 1.1325 msec/pass - lxe: xpath_class (--TC T3) 0.0215 msec/pass - lxe: xpath_class (--TC T4) 0.0722 msec/pass + lxe: xpath_class (--TC T1) 0.0570 msec/pass + lxe: xpath_class (--TC T2) 0.6924 msec/pass + lxe: xpath_class (--TC T3) 0.0148 msec/pass + lxe: xpath_class (--TC T4) 0.0446 msec/pass Note that this still allows you to use variables in the expression, so you can parse it once and then adapt it through variables at call time. In other cases, where you have a fixed Element or ElementTree and want to run different expressions on it, you should consider the ``XPathEvaluator``:: - lxe: xpath_element (--TR T1) 0.1101 msec/pass - lxe: xpath_element (--TR T2) 2.0473 msec/pass - lxe: xpath_element (--TR T3) 0.0267 msec/pass - lxe: xpath_element (--TR T4) 0.1087 msec/pass + lxe: xpath_element (--TR T1) 0.0684 msec/pass + lxe: xpath_element (--TR T2) 1.0865 msec/pass + lxe: xpath_element (--TR T3) 0.0174 msec/pass + lxe: xpath_element (--TR T4) 0.0665 msec/pass While it looks slightly slower, creating an XPath object for each of the expressions generates a much higher overhead here:: - lxe: xpath_class_repeat (--TC T1 ) 0.3884 msec/pass - lxe: xpath_class_repeat (--TC T2 ) 7.6182 msec/pass - lxe: xpath_class_repeat (--TC T3 ) 0.0465 msec/pass - lxe: xpath_class_repeat (--TC T4 ) 0.3877 msec/pass + lxe: xpath_class_repeat (--TC T1 ) 0.2813 msec/pass + lxe: xpath_class_repeat (--TC T2 ) 5.4042 msec/pass + lxe: xpath_class_repeat (--TC T3 ) 0.0339 msec/pass + lxe: xpath_class_repeat (--TC T4 ) 0.2706 msec/pass Note that tree iteration can be substantially faster than XPath if your code short-circuits after the first couple of elements were @@ -589,25 +581,25 @@ regardless of how much of it will actually be used. Here is an example where only the first matching element is being searched, a case for which XPath has syntax support as well:: - lxe: find_single (--TR T2) 0.0184 msec/pass - cET: find_single (--TR T2) 0.0052 msec/pass + lxe: find_single (--TR T2) 0.0031 msec/pass + cET: find_single (--TR T2) 0.0026 msec/pass - lxe: iter_single (--TR T2) 0.0024 msec/pass - cET: iter_single (--TR T2) 0.0007 msec/pass + lxe: iter_single (--TR T2) 0.0019 msec/pass + cET: iter_single (--TR T2) 0.0002 msec/pass - lxe: xpath_single (--TR T2) 0.0033 msec/pass + lxe: xpath_single (--TR T2) 0.0861 msec/pass When looking for the first two elements out of many, the numbers explode for XPath, as restricting the result subset requires a more complex expression:: - lxe: iterfind_two (--TR T2) 0.0184 msec/pass - cET: iterfind_two (--TR T2) 0.0062 msec/pass + lxe: iterfind_two (--TR T2) 0.0050 msec/pass + cET: iterfind_two (--TR T2) 0.0036 msec/pass - lxe: iter_two (--TR T2) 0.0029 msec/pass - cET: iter_two (--TR T2) 0.0017 msec/pass + lxe: iter_two (--TR T2) 0.0021 msec/pass + cET: iter_two (--TR T2) 0.0014 msec/pass - lxe: xpath_two (--TR T2) 0.2768 msec/pass + lxe: xpath_two (--TR T2) 0.0916 msec/pass A longer example @@ -774,21 +766,21 @@ ObjectPath can be used to speed up the access to elements that are deep in the tree. It avoids step-by-step Python element instantiations along the path, which can substantially improve the access time:: - lxe: attribute (--TR T1) 4.1828 msec/pass - lxe: attribute (--TR T2) 17.3802 msec/pass - lxe: attribute (--TR T4) 3.8657 msec/pass + lxe: attribute (--TR T1) 2.4018 msec/pass + lxe: attribute (--TR T2) 16.3755 msec/pass + lxe: attribute (--TR T4) 2.3725 msec/pass - lxe: objectpath (--TR T1) 0.9289 msec/pass - lxe: objectpath (--TR T2) 13.3109 msec/pass - lxe: objectpath (--TR T4) 0.9289 msec/pass + lxe: objectpath (--TR T1) 1.1816 msec/pass + lxe: objectpath (--TR T2) 14.4675 msec/pass + lxe: objectpath (--TR T4) 1.2276 msec/pass - lxe: attributes_deep (--TR T1) 6.2900 msec/pass - lxe: attributes_deep (--TR T2) 20.4713 msec/pass - lxe: attributes_deep (--TR T4) 6.1679 msec/pass + lxe: attributes_deep (--TR T1) 3.7086 msec/pass + lxe: attributes_deep (--TR T2) 17.5436 msec/pass + lxe: attributes_deep (--TR T4) 3.8407 msec/pass - lxe: objectpath_deep (--TR T1) 1.3049 msec/pass - lxe: objectpath_deep (--TR T2) 14.0815 msec/pass - lxe: objectpath_deep (--TR T4) 1.3051 msec/pass + lxe: objectpath_deep (--TR T1) 1.4980 msec/pass + lxe: objectpath_deep (--TR T2) 14.7266 msec/pass + lxe: objectpath_deep (--TR T4) 1.4834 msec/pass Note, however, that parsing ObjectPath expressions is not for free either, so this is most effective for frequently accessing the same element. @@ -818,17 +810,17 @@ expressions to be more selective. By choosing the right trees (or even subtrees and elements) to cache, you can trade memory usage against access speed:: - lxe: attribute_cached (--TR T1) 3.1357 msec/pass - lxe: attribute_cached (--TR T2) 15.8911 msec/pass - lxe: attribute_cached (--TR T4) 2.9194 msec/pass + lxe: attribute_cached (--TR T1) 1.9207 msec/pass + lxe: attribute_cached (--TR T2) 15.6903 msec/pass + lxe: attribute_cached (--TR T4) 1.8718 msec/pass - lxe: attributes_deep_cached (--TR T1) 3.8984 msec/pass - lxe: attributes_deep_cached (--TR T2) 16.8300 msec/pass - lxe: attributes_deep_cached (--TR T4) 3.6936 msec/pass + lxe: attributes_deep_cached (--TR T1) 2.6512 msec/pass + lxe: attributes_deep_cached (--TR T2) 16.7937 msec/pass + lxe: attributes_deep_cached (--TR T4) 2.5539 msec/pass - lxe: objectpath_deep_cached (--TR T1) 0.7496 msec/pass - lxe: objectpath_deep_cached (--TR T2) 12.3763 msec/pass - lxe: objectpath_deep_cached (--TR T4) 0.7427 msec/pass + lxe: objectpath_deep_cached (--TR T1) 0.8519 msec/pass + lxe: objectpath_deep_cached (--TR T2) 13.9337 msec/pass + lxe: objectpath_deep_cached (--TR T4) 0.8645 msec/pass Things to note: you cannot currently use ``weakref.WeakKeyDictionary`` objects for this as lxml's element objects do not support weak references (which are diff --git a/doc/s5/lxml-ep2008.html b/doc/s5/lxml-ep2008.html index 008bc99..62ffda7 100644 --- a/doc/s5/lxml-ep2008.html +++ b/doc/s5/lxml-ep2008.html @@ -3,7 +3,7 @@ - + Implementing XML languages with lxml