annotate genshi/core.py @ 856:1e2be9fb3348

Add a couple of fallback imports for Python 3.0.
author cmlenz
date Thu, 12 Nov 2009 11:36:14 +0000
parents 0d9e87c6cf6e
children 24733a5854d9
rev   line source
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
1 # -*- coding: utf-8 -*-
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
2 #
854
0d9e87c6cf6e More work on reducing the size of the diff produced by 2to3.
cmlenz
parents: 852
diff changeset
3 # Copyright (C) 2006-2009 Edgewall Software
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
4 # All rights reserved.
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
5 #
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
6 # This software is licensed as described in the file COPYING, which
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
7 # you should have received as part of this distribution. The terms
230
24757b771651 Renamed Markup to Genshi in repository.
cmlenz
parents: 224
diff changeset
8 # are also available at http://genshi.edgewall.org/wiki/License.
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
9 #
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
10 # This software consists of voluntary contributions made by many
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
11 # individuals. For the exact contribution history, see the revision
230
24757b771651 Renamed Markup to Genshi in repository.
cmlenz
parents: 224
diff changeset
12 # history and logs, available at http://genshi.edgewall.org/log/.
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
13
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
14 """Core classes for markup processing."""
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
15
792
a64cfc8f6fc9 Apply patch to silence a -3 warning about `reduce` removal. Closes #279.
cmlenz
parents: 737
diff changeset
16 try:
856
1e2be9fb3348 Add a couple of fallback imports for Python 3.0.
cmlenz
parents: 854
diff changeset
17 reduce # builtin in Python < 3
1e2be9fb3348 Add a couple of fallback imports for Python 3.0.
cmlenz
parents: 854
diff changeset
18 except NameError:
792
a64cfc8f6fc9 Apply patch to silence a -3 warning about `reduce` removal. Closes #279.
cmlenz
parents: 737
diff changeset
19 from functools import reduce
634
60a1fb39f915 Performance optimization for the `genshi.core._ensure` function: instead of checking whether we're dealing with a markup event stream for every item in the iterable, we now check only the first item, and treat the rest of the iterable depending on whether the first one looks like an event.
cmlenz
parents: 605
diff changeset
20 from itertools import chain
204
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
21 import operator
397
d6e9170c5ccc * Moved some utility functions from `genshi.core` to `genshi.util` (backwards compatibility preserved via imports)
cmlenz
parents: 382
diff changeset
22
d6e9170c5ccc * Moved some utility functions from `genshi.core` to `genshi.util` (backwards compatibility preserved via imports)
cmlenz
parents: 382
diff changeset
23 from genshi.util import plaintext, stripentities, striptags
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
24
377
79a7db5177e9 Add `Attrs` class to `genshi.core.__all__`, so that it can be imported directly from the `genshi` package.
cmlenz
parents: 345
diff changeset
25 __all__ = ['Stream', 'Markup', 'escape', 'unescape', 'Attrs', 'Namespace',
79a7db5177e9 Add `Attrs` class to `genshi.core.__all__`, so that it can be imported directly from the `genshi` package.
cmlenz
parents: 345
diff changeset
26 'QName']
425
5b248708bbed Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents: 408
diff changeset
27 __docformat__ = 'restructuredtext en'
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
28
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
29
17
ad63ad459524 Refactoring to address #6: all match templates are now processed by a single filter, which means that match templates added by included templates are properly applied. A side effect of this refactoring is that `Context` objects may not be reused across multiple template processing runs.
cmlenz
parents: 10
diff changeset
30 class StreamEventKind(str):
397
d6e9170c5ccc * Moved some utility functions from `genshi.core` to `genshi.util` (backwards compatibility preserved via imports)
cmlenz
parents: 382
diff changeset
31 """A kind of event on a markup stream."""
279
4b5b4653d41e Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents: 278
diff changeset
32 __slots__ = []
4b5b4653d41e Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents: 278
diff changeset
33 _instances = {}
4b5b4653d41e Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents: 278
diff changeset
34
4b5b4653d41e Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents: 278
diff changeset
35 def __new__(cls, val):
4b5b4653d41e Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents: 278
diff changeset
36 return cls._instances.setdefault(val, str.__new__(cls, val))
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
37
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
38
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
39 class Stream(object):
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
40 """Represents a stream of markup events.
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
41
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
42 This class is basically an iterator over the events.
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
43
425
5b248708bbed Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents: 408
diff changeset
44 Stream events are tuples of the form::
397
d6e9170c5ccc * Moved some utility functions from `genshi.core` to `genshi.util` (backwards compatibility preserved via imports)
cmlenz
parents: 382
diff changeset
45
d6e9170c5ccc * Moved some utility functions from `genshi.core` to `genshi.util` (backwards compatibility preserved via imports)
cmlenz
parents: 382
diff changeset
46 (kind, data, position)
d6e9170c5ccc * Moved some utility functions from `genshi.core` to `genshi.util` (backwards compatibility preserved via imports)
cmlenz
parents: 382
diff changeset
47
425
5b248708bbed Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents: 408
diff changeset
48 where ``kind`` is the event kind (such as `START`, `END`, `TEXT`, etc),
5b248708bbed Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents: 408
diff changeset
49 ``data`` depends on the kind of event, and ``position`` is a
5b248708bbed Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents: 408
diff changeset
50 ``(filename, line, offset)`` tuple that contains the location of the
5b248708bbed Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents: 408
diff changeset
51 original element or text in the input. If the original location is unknown,
5b248708bbed Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents: 408
diff changeset
52 ``position`` is ``(None, -1, -1)``.
397
d6e9170c5ccc * Moved some utility functions from `genshi.core` to `genshi.util` (backwards compatibility preserved via imports)
cmlenz
parents: 382
diff changeset
53
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
54 Also provided are ways to serialize the stream to text. The `serialize()`
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
55 method will return an iterator over generated strings, while `render()`
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
56 returns the complete generated text at once. Both accept various parameters
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
57 that impact the way the stream is serialized.
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
58 """
605
bc5faca93699 Text templates now default to rendering as plain text; it is no longer necessary to explicitly specify the "text" method to the `render()` or `serialize()` method of the generated markup stream. See tickets #62 and #118.
cmlenz
parents: 593
diff changeset
59 __slots__ = ['events', 'serializer']
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
60
427
68a8308309b9 More API documentation.
cmlenz
parents: 425
diff changeset
61 START = StreamEventKind('START') #: a start tag
68a8308309b9 More API documentation.
cmlenz
parents: 425
diff changeset
62 END = StreamEventKind('END') #: an end tag
68a8308309b9 More API documentation.
cmlenz
parents: 425
diff changeset
63 TEXT = StreamEventKind('TEXT') #: literal text
460
6b5544bb5a99 Apply patch by Alec Thomas for processing XML declarations (#111). Thanks!
cmlenz
parents: 438
diff changeset
64 XML_DECL = StreamEventKind('XML_DECL') #: XML declaration
427
68a8308309b9 More API documentation.
cmlenz
parents: 425
diff changeset
65 DOCTYPE = StreamEventKind('DOCTYPE') #: doctype declaration
68a8308309b9 More API documentation.
cmlenz
parents: 425
diff changeset
66 START_NS = StreamEventKind('START_NS') #: start namespace mapping
68a8308309b9 More API documentation.
cmlenz
parents: 425
diff changeset
67 END_NS = StreamEventKind('END_NS') #: end namespace mapping
68a8308309b9 More API documentation.
cmlenz
parents: 425
diff changeset
68 START_CDATA = StreamEventKind('START_CDATA') #: start CDATA section
68a8308309b9 More API documentation.
cmlenz
parents: 425
diff changeset
69 END_CDATA = StreamEventKind('END_CDATA') #: end CDATA section
68a8308309b9 More API documentation.
cmlenz
parents: 425
diff changeset
70 PI = StreamEventKind('PI') #: processing instruction
68a8308309b9 More API documentation.
cmlenz
parents: 425
diff changeset
71 COMMENT = StreamEventKind('COMMENT') #: comment
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
72
605
bc5faca93699 Text templates now default to rendering as plain text; it is no longer necessary to explicitly specify the "text" method to the `render()` or `serialize()` method of the generated markup stream. See tickets #62 and #118.
cmlenz
parents: 593
diff changeset
73 def __init__(self, events, serializer=None):
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
74 """Initialize the stream with a sequence of markup events.
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
75
425
5b248708bbed Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents: 408
diff changeset
76 :param events: a sequence or iterable providing the events
605
bc5faca93699 Text templates now default to rendering as plain text; it is no longer necessary to explicitly specify the "text" method to the `render()` or `serialize()` method of the generated markup stream. See tickets #62 and #118.
cmlenz
parents: 593
diff changeset
77 :param serializer: the default serialization method to use for this
bc5faca93699 Text templates now default to rendering as plain text; it is no longer necessary to explicitly specify the "text" method to the `render()` or `serialize()` method of the generated markup stream. See tickets #62 and #118.
cmlenz
parents: 593
diff changeset
78 stream
bc5faca93699 Text templates now default to rendering as plain text; it is no longer necessary to explicitly specify the "text" method to the `render()` or `serialize()` method of the generated markup stream. See tickets #62 and #118.
cmlenz
parents: 593
diff changeset
79
bc5faca93699 Text templates now default to rendering as plain text; it is no longer necessary to explicitly specify the "text" method to the `render()` or `serialize()` method of the generated markup stream. See tickets #62 and #118.
cmlenz
parents: 593
diff changeset
80 :note: Changed in 0.5: added the `serializer` argument
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
81 """
498
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
82 self.events = events #: The underlying iterable producing the events
605
bc5faca93699 Text templates now default to rendering as plain text; it is no longer necessary to explicitly specify the "text" method to the `render()` or `serialize()` method of the generated markup stream. See tickets #62 and #118.
cmlenz
parents: 593
diff changeset
83 self.serializer = serializer #: The default serializion method
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
84
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
85 def __iter__(self):
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
86 return iter(self.events)
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
87
204
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
88 def __or__(self, function):
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
89 """Override the "bitwise or" operator to apply filters or serializers
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
90 to the stream, providing a syntax similar to pipes on Unix shells.
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
91
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
92 Assume the following stream produced by the `HTML` function:
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
93
230
24757b771651 Renamed Markup to Genshi in repository.
cmlenz
parents: 224
diff changeset
94 >>> from genshi.input import HTML
204
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
95 >>> html = HTML('''<p onclick="alert('Whoa')">Hello, world!</p>''')
852
04945cd67dad Remove usage of unicode literals in a couple of places where they were not strictly necessary.
cmlenz
parents: 843
diff changeset
96 >>> print(html)
204
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
97 <p onclick="alert('Whoa')">Hello, world!</p>
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
98
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
99 A filter such as the HTML sanitizer can be applied to that stream using
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
100 the pipe notation as follows:
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
101
230
24757b771651 Renamed Markup to Genshi in repository.
cmlenz
parents: 224
diff changeset
102 >>> from genshi.filters import HTMLSanitizer
204
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
103 >>> sanitizer = HTMLSanitizer()
852
04945cd67dad Remove usage of unicode literals in a couple of places where they were not strictly necessary.
cmlenz
parents: 843
diff changeset
104 >>> print(html | sanitizer)
204
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
105 <p>Hello, world!</p>
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
106
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
107 Filters can be any function that accepts and produces a stream (where
397
d6e9170c5ccc * Moved some utility functions from `genshi.core` to `genshi.util` (backwards compatibility preserved via imports)
cmlenz
parents: 382
diff changeset
108 a stream is anything that iterates over events):
204
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
109
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
110 >>> def uppercase(stream):
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
111 ... for kind, data, pos in stream:
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
112 ... if kind is TEXT:
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
113 ... data = data.upper()
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
114 ... yield kind, data, pos
852
04945cd67dad Remove usage of unicode literals in a couple of places where they were not strictly necessary.
cmlenz
parents: 843
diff changeset
115 >>> print(html | sanitizer | uppercase)
204
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
116 <p>HELLO, WORLD!</p>
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
117
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
118 Serializers can also be used with this notation:
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
119
230
24757b771651 Renamed Markup to Genshi in repository.
cmlenz
parents: 224
diff changeset
120 >>> from genshi.output import TextSerializer
204
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
121 >>> output = TextSerializer()
852
04945cd67dad Remove usage of unicode literals in a couple of places where they were not strictly necessary.
cmlenz
parents: 843
diff changeset
122 >>> print(html | sanitizer | uppercase | output)
204
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
123 HELLO, WORLD!
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
124
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
125 Commonly, serializers should be used at the end of the "pipeline";
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
126 using them somewhere in the middle may produce unexpected results.
498
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
127
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
128 :param function: the callable object that should be applied as a filter
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
129 :return: the filtered stream
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
130 :rtype: `Stream`
204
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
131 """
605
bc5faca93699 Text templates now default to rendering as plain text; it is no longer necessary to explicitly specify the "text" method to the `render()` or `serialize()` method of the generated markup stream. See tickets #62 and #118.
cmlenz
parents: 593
diff changeset
132 return Stream(_ensure(function(self)), serializer=self.serializer)
204
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
133
123
93bbdcf9428b Fix for #18: whitespace in space-sensitive elements such as `<pre>` and `<textarea>` is now preserved.
cmlenz
parents: 116
diff changeset
134 def filter(self, *filters):
93bbdcf9428b Fix for #18: whitespace in space-sensitive elements such as `<pre>` and `<textarea>` is now preserved.
cmlenz
parents: 116
diff changeset
135 """Apply filters to the stream.
113
e815c2c07572 Removed the `sanitize()` method from the `Markup` class, and migrate the existing unit tests to `markup.tests.filters`. Provide a `Stream.filter()` method instead which can be used to conveniently apply a filter to a stream.
cmlenz
parents: 111
diff changeset
136
123
93bbdcf9428b Fix for #18: whitespace in space-sensitive elements such as `<pre>` and `<textarea>` is now preserved.
cmlenz
parents: 116
diff changeset
137 This method returns a new stream with the given filters applied. The
93bbdcf9428b Fix for #18: whitespace in space-sensitive elements such as `<pre>` and `<textarea>` is now preserved.
cmlenz
parents: 116
diff changeset
138 filters must be callables that accept the stream object as parameter,
93bbdcf9428b Fix for #18: whitespace in space-sensitive elements such as `<pre>` and `<textarea>` is now preserved.
cmlenz
parents: 116
diff changeset
139 and return the filtered stream.
204
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
140
425
5b248708bbed Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents: 408
diff changeset
141 The call::
204
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
142
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
143 stream.filter(filter1, filter2)
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
144
425
5b248708bbed Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents: 408
diff changeset
145 is equivalent to::
204
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
146
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
147 stream | filter1 | filter2
498
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
148
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
149 :param filters: one or more callable objects that should be applied as
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
150 filters
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
151 :return: the filtered stream
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
152 :rtype: `Stream`
113
e815c2c07572 Removed the `sanitize()` method from the `Markup` class, and migrate the existing unit tests to `markup.tests.filters`. Provide a `Stream.filter()` method instead which can be used to conveniently apply a filter to a stream.
cmlenz
parents: 111
diff changeset
153 """
204
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
154 return reduce(operator.or_, (self,) + filters)
113
e815c2c07572 Removed the `sanitize()` method from the `Markup` class, and migrate the existing unit tests to `markup.tests.filters`. Provide a `Stream.filter()` method instead which can be used to conveniently apply a filter to a stream.
cmlenz
parents: 111
diff changeset
155
688
88814cc26d2b The `Stream.render` now accepts an optional `out` parameter that can be used to pass in a writable file-like object to use for assembling the output, instead of building a big string and returning it.
cmlenz
parents: 685
diff changeset
156 def render(self, method=None, encoding='utf-8', out=None, **kwargs):
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
157 """Return a string representation of the stream.
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
158
498
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
159 Any additional keyword arguments are passed to the serializer, and thus
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
160 depend on the `method` parameter value.
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
161
425
5b248708bbed Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents: 408
diff changeset
162 :param method: determines how the stream is serialized; can be either
200
50eab0469148 Add serialization to plain text, based on cboos' patch. Closes #41.
cmlenz
parents: 182
diff changeset
163 "xml", "xhtml", "html", "text", or a custom serializer
605
bc5faca93699 Text templates now default to rendering as plain text; it is no longer necessary to explicitly specify the "text" method to the `render()` or `serialize()` method of the generated markup stream. See tickets #62 and #118.
cmlenz
parents: 593
diff changeset
164 class; if `None`, the default serialization method of
bc5faca93699 Text templates now default to rendering as plain text; it is no longer necessary to explicitly specify the "text" method to the `render()` or `serialize()` method of the generated markup stream. See tickets #62 and #118.
cmlenz
parents: 593
diff changeset
165 the stream is used
425
5b248708bbed Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents: 408
diff changeset
166 :param encoding: how the output string should be encoded; if set to
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
167 `None`, this method returns a `unicode` object
688
88814cc26d2b The `Stream.render` now accepts an optional `out` parameter that can be used to pass in a writable file-like object to use for assembling the output, instead of building a big string and returning it.
cmlenz
parents: 685
diff changeset
168 :param out: a file-like object that the output should be written to
88814cc26d2b The `Stream.render` now accepts an optional `out` parameter that can be used to pass in a writable file-like object to use for assembling the output, instead of building a big string and returning it.
cmlenz
parents: 685
diff changeset
169 instead of being returned as one big string; note that if
88814cc26d2b The `Stream.render` now accepts an optional `out` parameter that can be used to pass in a writable file-like object to use for assembling the output, instead of building a big string and returning it.
cmlenz
parents: 685
diff changeset
170 this is a file or socket (or similar), the `encoding` must
88814cc26d2b The `Stream.render` now accepts an optional `out` parameter that can be used to pass in a writable file-like object to use for assembling the output, instead of building a big string and returning it.
cmlenz
parents: 685
diff changeset
171 not be `None` (that is, the output must be encoded)
88814cc26d2b The `Stream.render` now accepts an optional `out` parameter that can be used to pass in a writable file-like object to use for assembling the output, instead of building a big string and returning it.
cmlenz
parents: 685
diff changeset
172 :return: a `str` or `unicode` object (depending on the `encoding`
88814cc26d2b The `Stream.render` now accepts an optional `out` parameter that can be used to pass in a writable file-like object to use for assembling the output, instead of building a big string and returning it.
cmlenz
parents: 685
diff changeset
173 parameter), or `None` if the `out` parameter is provided
498
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
174 :rtype: `basestring`
688
88814cc26d2b The `Stream.render` now accepts an optional `out` parameter that can be used to pass in a writable file-like object to use for assembling the output, instead of building a big string and returning it.
cmlenz
parents: 685
diff changeset
175
498
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
176 :see: XMLSerializer, XHTMLSerializer, HTMLSerializer, TextSerializer
688
88814cc26d2b The `Stream.render` now accepts an optional `out` parameter that can be used to pass in a writable file-like object to use for assembling the output, instead of building a big string and returning it.
cmlenz
parents: 685
diff changeset
177 :note: Changed in 0.5: added the `out` parameter
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
178 """
462
c107f6f4c558 Add lower-level serialization functions.
cmlenz
parents: 460
diff changeset
179 from genshi.output import encode
605
bc5faca93699 Text templates now default to rendering as plain text; it is no longer necessary to explicitly specify the "text" method to the `render()` or `serialize()` method of the generated markup stream. See tickets #62 and #118.
cmlenz
parents: 593
diff changeset
180 if method is None:
bc5faca93699 Text templates now default to rendering as plain text; it is no longer necessary to explicitly specify the "text" method to the `render()` or `serialize()` method of the generated markup stream. See tickets #62 and #118.
cmlenz
parents: 593
diff changeset
181 method = self.serializer or 'xml'
123
93bbdcf9428b Fix for #18: whitespace in space-sensitive elements such as `<pre>` and `<textarea>` is now preserved.
cmlenz
parents: 116
diff changeset
182 generator = self.serialize(method=method, **kwargs)
688
88814cc26d2b The `Stream.render` now accepts an optional `out` parameter that can be used to pass in a writable file-like object to use for assembling the output, instead of building a big string and returning it.
cmlenz
parents: 685
diff changeset
183 return encode(generator, method=method, encoding=encoding, out=out)
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
184
278
8de2620504b9 Fix the handling of namespace context for match templates.
cmlenz
parents: 230
diff changeset
185 def select(self, path, namespaces=None, variables=None):
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
186 """Return a new stream that contains the events matching the given
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
187 XPath expression.
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
188
576
53f4088e1e3b Improve docs on `Stream.select()` for #135.
cmlenz
parents: 541
diff changeset
189 >>> from genshi import HTML
53f4088e1e3b Improve docs on `Stream.select()` for #135.
cmlenz
parents: 541
diff changeset
190 >>> stream = HTML('<doc><elem>foo</elem><elem>bar</elem></doc>')
852
04945cd67dad Remove usage of unicode literals in a couple of places where they were not strictly necessary.
cmlenz
parents: 843
diff changeset
191 >>> print(stream.select('elem'))
576
53f4088e1e3b Improve docs on `Stream.select()` for #135.
cmlenz
parents: 541
diff changeset
192 <elem>foo</elem><elem>bar</elem>
852
04945cd67dad Remove usage of unicode literals in a couple of places where they were not strictly necessary.
cmlenz
parents: 843
diff changeset
193 >>> print(stream.select('elem/text()'))
576
53f4088e1e3b Improve docs on `Stream.select()` for #135.
cmlenz
parents: 541
diff changeset
194 foobar
53f4088e1e3b Improve docs on `Stream.select()` for #135.
cmlenz
parents: 541
diff changeset
195
53f4088e1e3b Improve docs on `Stream.select()` for #135.
cmlenz
parents: 541
diff changeset
196 Note that the outermost element of the stream becomes the *context
53f4088e1e3b Improve docs on `Stream.select()` for #135.
cmlenz
parents: 541
diff changeset
197 node* for the XPath test. That means that the expression "doc" would
53f4088e1e3b Improve docs on `Stream.select()` for #135.
cmlenz
parents: 541
diff changeset
198 not match anything in the example above, because it only tests against
53f4088e1e3b Improve docs on `Stream.select()` for #135.
cmlenz
parents: 541
diff changeset
199 child elements of the outermost element:
53f4088e1e3b Improve docs on `Stream.select()` for #135.
cmlenz
parents: 541
diff changeset
200
852
04945cd67dad Remove usage of unicode literals in a couple of places where they were not strictly necessary.
cmlenz
parents: 843
diff changeset
201 >>> print(stream.select('doc'))
576
53f4088e1e3b Improve docs on `Stream.select()` for #135.
cmlenz
parents: 541
diff changeset
202 <BLANKLINE>
53f4088e1e3b Improve docs on `Stream.select()` for #135.
cmlenz
parents: 541
diff changeset
203
53f4088e1e3b Improve docs on `Stream.select()` for #135.
cmlenz
parents: 541
diff changeset
204 You can use the "." expression to match the context node itself
53f4088e1e3b Improve docs on `Stream.select()` for #135.
cmlenz
parents: 541
diff changeset
205 (although that usually makes little sense):
53f4088e1e3b Improve docs on `Stream.select()` for #135.
cmlenz
parents: 541
diff changeset
206
852
04945cd67dad Remove usage of unicode literals in a couple of places where they were not strictly necessary.
cmlenz
parents: 843
diff changeset
207 >>> print(stream.select('.'))
576
53f4088e1e3b Improve docs on `Stream.select()` for #135.
cmlenz
parents: 541
diff changeset
208 <doc><elem>foo</elem><elem>bar</elem></doc>
53f4088e1e3b Improve docs on `Stream.select()` for #135.
cmlenz
parents: 541
diff changeset
209
425
5b248708bbed Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents: 408
diff changeset
210 :param path: a string containing the XPath expression
435
7800a61eae43 More API doc enhancements.
cmlenz
parents: 434
diff changeset
211 :param namespaces: mapping of namespace prefixes used in the path
7800a61eae43 More API doc enhancements.
cmlenz
parents: 434
diff changeset
212 :param variables: mapping of variable names to values
7800a61eae43 More API doc enhancements.
cmlenz
parents: 434
diff changeset
213 :return: the selected substream
498
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
214 :rtype: `Stream`
435
7800a61eae43 More API doc enhancements.
cmlenz
parents: 434
diff changeset
215 :raises PathSyntaxError: if the given path expression is invalid or not
7800a61eae43 More API doc enhancements.
cmlenz
parents: 434
diff changeset
216 supported
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
217 """
230
24757b771651 Renamed Markup to Genshi in repository.
cmlenz
parents: 224
diff changeset
218 from genshi.path import Path
278
8de2620504b9 Fix the handling of namespace context for match templates.
cmlenz
parents: 230
diff changeset
219 return Path(path).select(self, namespaces, variables)
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
220
123
93bbdcf9428b Fix for #18: whitespace in space-sensitive elements such as `<pre>` and `<textarea>` is now preserved.
cmlenz
parents: 116
diff changeset
221 def serialize(self, method='xml', **kwargs):
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
222 """Generate strings corresponding to a specific serialization of the
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
223 stream.
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
224
18
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
225 Unlike the `render()` method, this method is a generator that returns
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
226 the serialized output incrementally, as opposed to returning a single
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
227 string.
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
228
498
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
229 Any additional keyword arguments are passed to the serializer, and thus
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
230 depend on the `method` parameter value.
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
231
425
5b248708bbed Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents: 408
diff changeset
232 :param method: determines how the stream is serialized; can be either
200
50eab0469148 Add serialization to plain text, based on cboos' patch. Closes #41.
cmlenz
parents: 182
diff changeset
233 "xml", "xhtml", "html", "text", or a custom serializer
605
bc5faca93699 Text templates now default to rendering as plain text; it is no longer necessary to explicitly specify the "text" method to the `render()` or `serialize()` method of the generated markup stream. See tickets #62 and #118.
cmlenz
parents: 593
diff changeset
234 class; if `None`, the default serialization method of
bc5faca93699 Text templates now default to rendering as plain text; it is no longer necessary to explicitly specify the "text" method to the `render()` or `serialize()` method of the generated markup stream. See tickets #62 and #118.
cmlenz
parents: 593
diff changeset
235 the stream is used
498
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
236 :return: an iterator over the serialization results (`Markup` or
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
237 `unicode` objects, depending on the serialization method)
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
238 :rtype: ``iterator``
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
239 :see: XMLSerializer, XHTMLSerializer, HTMLSerializer, TextSerializer
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
240 """
462
c107f6f4c558 Add lower-level serialization functions.
cmlenz
parents: 460
diff changeset
241 from genshi.output import get_serializer
605
bc5faca93699 Text templates now default to rendering as plain text; it is no longer necessary to explicitly specify the "text" method to the `render()` or `serialize()` method of the generated markup stream. See tickets #62 and #118.
cmlenz
parents: 593
diff changeset
242 if method is None:
bc5faca93699 Text templates now default to rendering as plain text; it is no longer necessary to explicitly specify the "text" method to the `render()` or `serialize()` method of the generated markup stream. See tickets #62 and #118.
cmlenz
parents: 593
diff changeset
243 method = self.serializer or 'xml'
462
c107f6f4c558 Add lower-level serialization functions.
cmlenz
parents: 460
diff changeset
244 return get_serializer(method, **kwargs)(_ensure(self))
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
245
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
246 def __str__(self):
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
247 return self.render()
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
248
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
249 def __unicode__(self):
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
250 return self.render(encoding=None)
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
251
737
686bbeecb9ac Implement the `__html__` protocol as suggested in #202. This would allow Genshi to be used in combination with other markup generating tools, as long as they support the same protocol.
cmlenz
parents: 719
diff changeset
252 def __html__(self):
686bbeecb9ac Implement the `__html__` protocol as suggested in #202. This would allow Genshi to be used in combination with other markup generating tools, as long as they support the same protocol.
cmlenz
parents: 719
diff changeset
253 return self
686bbeecb9ac Implement the `__html__` protocol as suggested in #202. This would allow Genshi to be used in combination with other markup generating tools, as long as they support the same protocol.
cmlenz
parents: 719
diff changeset
254
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
255
69
e9a3930f8823 A couple of minor performance improvements.
cmlenz
parents: 66
diff changeset
256 START = Stream.START
e9a3930f8823 A couple of minor performance improvements.
cmlenz
parents: 66
diff changeset
257 END = Stream.END
e9a3930f8823 A couple of minor performance improvements.
cmlenz
parents: 66
diff changeset
258 TEXT = Stream.TEXT
460
6b5544bb5a99 Apply patch by Alec Thomas for processing XML declarations (#111). Thanks!
cmlenz
parents: 438
diff changeset
259 XML_DECL = Stream.XML_DECL
69
e9a3930f8823 A couple of minor performance improvements.
cmlenz
parents: 66
diff changeset
260 DOCTYPE = Stream.DOCTYPE
e9a3930f8823 A couple of minor performance improvements.
cmlenz
parents: 66
diff changeset
261 START_NS = Stream.START_NS
e9a3930f8823 A couple of minor performance improvements.
cmlenz
parents: 66
diff changeset
262 END_NS = Stream.END_NS
143
ef761afcedff CDATA sections in XML input now appear as CDATA sections in the output. This should address the problem with escaping the contents of `<style>` and `<script>` elements, which would only get interpreted correctly if the output was served as `application/xhtml+xml`. Closes #24.
cmlenz
parents: 141
diff changeset
263 START_CDATA = Stream.START_CDATA
ef761afcedff CDATA sections in XML input now appear as CDATA sections in the output. This should address the problem with escaping the contents of `<style>` and `<script>` elements, which would only get interpreted correctly if the output was served as `application/xhtml+xml`. Closes #24.
cmlenz
parents: 141
diff changeset
264 END_CDATA = Stream.END_CDATA
69
e9a3930f8823 A couple of minor performance improvements.
cmlenz
parents: 66
diff changeset
265 PI = Stream.PI
e9a3930f8823 A couple of minor performance improvements.
cmlenz
parents: 66
diff changeset
266 COMMENT = Stream.COMMENT
e9a3930f8823 A couple of minor performance improvements.
cmlenz
parents: 66
diff changeset
267
843
004f81b59d97 Refactored the template flattening method to be less recursive.
cmlenz
parents: 822
diff changeset
268
111
8a4d9064f363 Some fixes and more unit tests for the XPath engine.
cmlenz
parents: 100
diff changeset
269 def _ensure(stream):
8a4d9064f363 Some fixes and more unit tests for the XPath engine.
cmlenz
parents: 100
diff changeset
270 """Ensure that every item on the stream is actually a markup event."""
634
60a1fb39f915 Performance optimization for the `genshi.core._ensure` function: instead of checking whether we're dealing with a markup event stream for every item in the iterable, we now check only the first item, and treat the rest of the iterable depending on whether the first one looks like an event.
cmlenz
parents: 605
diff changeset
271 stream = iter(stream)
60a1fb39f915 Performance optimization for the `genshi.core._ensure` function: instead of checking whether we're dealing with a markup event stream for every item in the iterable, we now check only the first item, and treat the rest of the iterable depending on whether the first one looks like an event.
cmlenz
parents: 605
diff changeset
272 event = stream.next()
60a1fb39f915 Performance optimization for the `genshi.core._ensure` function: instead of checking whether we're dealing with a markup event stream for every item in the iterable, we now check only the first item, and treat the rest of the iterable depending on whether the first one looks like an event.
cmlenz
parents: 605
diff changeset
273
60a1fb39f915 Performance optimization for the `genshi.core._ensure` function: instead of checking whether we're dealing with a markup event stream for every item in the iterable, we now check only the first item, and treat the rest of the iterable depending on whether the first one looks like an event.
cmlenz
parents: 605
diff changeset
274 # Check whether the iterable is a real markup event stream by examining the
60a1fb39f915 Performance optimization for the `genshi.core._ensure` function: instead of checking whether we're dealing with a markup event stream for every item in the iterable, we now check only the first item, and treat the rest of the iterable depending on whether the first one looks like an event.
cmlenz
parents: 605
diff changeset
275 # first item it yields; if it's not we'll need to do some conversion
60a1fb39f915 Performance optimization for the `genshi.core._ensure` function: instead of checking whether we're dealing with a markup event stream for every item in the iterable, we now check only the first item, and treat the rest of the iterable depending on whether the first one looks like an event.
cmlenz
parents: 605
diff changeset
276 if type(event) is not tuple or len(event) != 3:
60a1fb39f915 Performance optimization for the `genshi.core._ensure` function: instead of checking whether we're dealing with a markup event stream for every item in the iterable, we now check only the first item, and treat the rest of the iterable depending on whether the first one looks like an event.
cmlenz
parents: 605
diff changeset
277 for event in chain([event], stream):
145
56d534eb53f9 * Fix error in expression evaluation when the expression evaluates to an iterable that does not produce event tuples.
cmlenz
parents: 143
diff changeset
278 if hasattr(event, 'totuple'):
56d534eb53f9 * Fix error in expression evaluation when the expression evaluates to an iterable that does not produce event tuples.
cmlenz
parents: 143
diff changeset
279 event = event.totuple()
56d534eb53f9 * Fix error in expression evaluation when the expression evaluates to an iterable that does not produce event tuples.
cmlenz
parents: 143
diff changeset
280 else:
56d534eb53f9 * Fix error in expression evaluation when the expression evaluates to an iterable that does not produce event tuples.
cmlenz
parents: 143
diff changeset
281 event = TEXT, unicode(event), (None, -1, -1)
634
60a1fb39f915 Performance optimization for the `genshi.core._ensure` function: instead of checking whether we're dealing with a markup event stream for every item in the iterable, we now check only the first item, and treat the rest of the iterable depending on whether the first one looks like an event.
cmlenz
parents: 605
diff changeset
282 yield event
60a1fb39f915 Performance optimization for the `genshi.core._ensure` function: instead of checking whether we're dealing with a markup event stream for every item in the iterable, we now check only the first item, and treat the rest of the iterable depending on whether the first one looks like an event.
cmlenz
parents: 605
diff changeset
283 return
60a1fb39f915 Performance optimization for the `genshi.core._ensure` function: instead of checking whether we're dealing with a markup event stream for every item in the iterable, we now check only the first item, and treat the rest of the iterable depending on whether the first one looks like an event.
cmlenz
parents: 605
diff changeset
284
60a1fb39f915 Performance optimization for the `genshi.core._ensure` function: instead of checking whether we're dealing with a markup event stream for every item in the iterable, we now check only the first item, and treat the rest of the iterable depending on whether the first one looks like an event.
cmlenz
parents: 605
diff changeset
285 # This looks like a markup event stream, so we'll just pass it through
60a1fb39f915 Performance optimization for the `genshi.core._ensure` function: instead of checking whether we're dealing with a markup event stream for every item in the iterable, we now check only the first item, and treat the rest of the iterable depending on whether the first one looks like an event.
cmlenz
parents: 605
diff changeset
286 # unchanged
60a1fb39f915 Performance optimization for the `genshi.core._ensure` function: instead of checking whether we're dealing with a markup event stream for every item in the iterable, we now check only the first item, and treat the rest of the iterable depending on whether the first one looks like an event.
cmlenz
parents: 605
diff changeset
287 yield event
60a1fb39f915 Performance optimization for the `genshi.core._ensure` function: instead of checking whether we're dealing with a markup event stream for every item in the iterable, we now check only the first item, and treat the rest of the iterable depending on whether the first one looks like an event.
cmlenz
parents: 605
diff changeset
288 for event in stream:
145
56d534eb53f9 * Fix error in expression evaluation when the expression evaluates to an iterable that does not produce event tuples.
cmlenz
parents: 143
diff changeset
289 yield event
111
8a4d9064f363 Some fixes and more unit tests for the XPath engine.
cmlenz
parents: 100
diff changeset
290
69
e9a3930f8823 A couple of minor performance improvements.
cmlenz
parents: 66
diff changeset
291
345
8e75b83d3e71 Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
292 class Attrs(tuple):
8e75b83d3e71 Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
293 """Immutable sequence type that stores the attributes of an element.
18
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
294
434
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
295 Ordering of the attributes is preserved, while access by name is also
345
8e75b83d3e71 Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
296 supported.
18
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
297
182
41db0260ebb1 Renamed `Attributes` to `Attrs` to reduce the verbosity.
cmlenz
parents: 172
diff changeset
298 >>> attrs = Attrs([('href', '#'), ('title', 'Foo')])
18
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
299 >>> attrs
403
32b283e1d310 Remove some magic/overhead from `Attrs` creation and manipulation by not automatically wrapping attribute names in `QName`.
cmlenz
parents: 397
diff changeset
300 Attrs([('href', '#'), ('title', 'Foo')])
18
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
301
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
302 >>> 'href' in attrs
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
303 True
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
304 >>> 'tabindex' in attrs
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
305 False
403
32b283e1d310 Remove some magic/overhead from `Attrs` creation and manipulation by not automatically wrapping attribute names in `QName`.
cmlenz
parents: 397
diff changeset
306 >>> attrs.get('title')
18
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
307 'Foo'
345
8e75b83d3e71 Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
308
425
5b248708bbed Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents: 408
diff changeset
309 Instances may not be manipulated directly. Instead, the operators ``|`` and
5b248708bbed Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents: 408
diff changeset
310 ``-`` can be used to produce new instances that have specific attributes
345
8e75b83d3e71 Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
311 added, replaced or removed.
8e75b83d3e71 Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
312
425
5b248708bbed Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents: 408
diff changeset
313 To remove an attribute, use the ``-`` operator. The right hand side can be
345
8e75b83d3e71 Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
314 either a string or a set/sequence of strings, identifying the name(s) of
8e75b83d3e71 Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
315 the attribute(s) to remove:
8e75b83d3e71 Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
316
8e75b83d3e71 Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
317 >>> attrs - 'title'
403
32b283e1d310 Remove some magic/overhead from `Attrs` creation and manipulation by not automatically wrapping attribute names in `QName`.
cmlenz
parents: 397
diff changeset
318 Attrs([('href', '#')])
345
8e75b83d3e71 Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
319 >>> attrs - ('title', 'href')
8e75b83d3e71 Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
320 Attrs()
8e75b83d3e71 Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
321
8e75b83d3e71 Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
322 The original instance is not modified, but the operator can of course be
8e75b83d3e71 Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
323 used with an assignment:
8e75b83d3e71 Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
324
18
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
325 >>> attrs
403
32b283e1d310 Remove some magic/overhead from `Attrs` creation and manipulation by not automatically wrapping attribute names in `QName`.
cmlenz
parents: 397
diff changeset
326 Attrs([('href', '#'), ('title', 'Foo')])
345
8e75b83d3e71 Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
327 >>> attrs -= 'title'
18
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
328 >>> attrs
403
32b283e1d310 Remove some magic/overhead from `Attrs` creation and manipulation by not automatically wrapping attribute names in `QName`.
cmlenz
parents: 397
diff changeset
329 Attrs([('href', '#')])
18
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
330
425
5b248708bbed Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents: 408
diff changeset
331 To add a new attribute, use the ``|`` operator, where the right hand value
5b248708bbed Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents: 408
diff changeset
332 is a sequence of ``(name, value)`` tuples (which includes `Attrs`
5b248708bbed Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents: 408
diff changeset
333 instances):
170
f1ac0510d392 Allow initialization of `Attributes` with keyword arguments.
cmlenz
parents: 161
diff changeset
334
403
32b283e1d310 Remove some magic/overhead from `Attrs` creation and manipulation by not automatically wrapping attribute names in `QName`.
cmlenz
parents: 397
diff changeset
335 >>> attrs | [('title', 'Bar')]
32b283e1d310 Remove some magic/overhead from `Attrs` creation and manipulation by not automatically wrapping attribute names in `QName`.
cmlenz
parents: 397
diff changeset
336 Attrs([('href', '#'), ('title', 'Bar')])
171
34e0455ada92 Follow-up to [214]: allow initializing `Attributes` with attribute names that contain dashes or conflict with a reserved word (such as ?class?.)
cmlenz
parents: 170
diff changeset
337
345
8e75b83d3e71 Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
338 If the attributes already contain an attribute with a given name, the value
8e75b83d3e71 Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
339 of that attribute is replaced:
171
34e0455ada92 Follow-up to [214]: allow initializing `Attributes` with attribute names that contain dashes or conflict with a reserved word (such as ?class?.)
cmlenz
parents: 170
diff changeset
340
403
32b283e1d310 Remove some magic/overhead from `Attrs` creation and manipulation by not automatically wrapping attribute names in `QName`.
cmlenz
parents: 397
diff changeset
341 >>> attrs | [('href', 'http://example.org/')]
32b283e1d310 Remove some magic/overhead from `Attrs` creation and manipulation by not automatically wrapping attribute names in `QName`.
cmlenz
parents: 397
diff changeset
342 Attrs([('href', 'http://example.org/')])
18
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
343 """
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
344 __slots__ = []
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
345
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
346 def __contains__(self, name):
18
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
347 """Return whether the list includes an attribute with the specified
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
348 name.
498
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
349
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
350 :return: `True` if the list includes the attribute
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
351 :rtype: `bool`
18
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
352 """
133
b9a0031d4bbb Minor cleanup and performance improvement for the builder module.
cmlenz
parents: 123
diff changeset
353 for attr, _ in self:
b9a0031d4bbb Minor cleanup and performance improvement for the builder module.
cmlenz
parents: 123
diff changeset
354 if attr == name:
b9a0031d4bbb Minor cleanup and performance improvement for the builder module.
cmlenz
parents: 123
diff changeset
355 return True
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
356
852
04945cd67dad Remove usage of unicode literals in a couple of places where they were not strictly necessary.
cmlenz
parents: 843
diff changeset
357 def __getitem__(self, i):
04945cd67dad Remove usage of unicode literals in a couple of places where they were not strictly necessary.
cmlenz
parents: 843
diff changeset
358 """Return an item or slice of the attributes list.
04945cd67dad Remove usage of unicode literals in a couple of places where they were not strictly necessary.
cmlenz
parents: 843
diff changeset
359
04945cd67dad Remove usage of unicode literals in a couple of places where they were not strictly necessary.
cmlenz
parents: 843
diff changeset
360 >>> attrs = Attrs([('href', '#'), ('title', 'Foo')])
04945cd67dad Remove usage of unicode literals in a couple of places where they were not strictly necessary.
cmlenz
parents: 843
diff changeset
361 >>> attrs[1]
04945cd67dad Remove usage of unicode literals in a couple of places where they were not strictly necessary.
cmlenz
parents: 843
diff changeset
362 ('title', 'Foo')
04945cd67dad Remove usage of unicode literals in a couple of places where they were not strictly necessary.
cmlenz
parents: 843
diff changeset
363 >>> attrs[1:]
04945cd67dad Remove usage of unicode literals in a couple of places where they were not strictly necessary.
cmlenz
parents: 843
diff changeset
364 Attrs([('title', 'Foo')])
04945cd67dad Remove usage of unicode literals in a couple of places where they were not strictly necessary.
cmlenz
parents: 843
diff changeset
365 """
04945cd67dad Remove usage of unicode literals in a couple of places where they were not strictly necessary.
cmlenz
parents: 843
diff changeset
366 items = tuple.__getitem__(self, i)
04945cd67dad Remove usage of unicode literals in a couple of places where they were not strictly necessary.
cmlenz
parents: 843
diff changeset
367 if type(i) is slice:
04945cd67dad Remove usage of unicode literals in a couple of places where they were not strictly necessary.
cmlenz
parents: 843
diff changeset
368 return Attrs(items)
04945cd67dad Remove usage of unicode literals in a couple of places where they were not strictly necessary.
cmlenz
parents: 843
diff changeset
369 return items
04945cd67dad Remove usage of unicode literals in a couple of places where they were not strictly necessary.
cmlenz
parents: 843
diff changeset
370
345
8e75b83d3e71 Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
371 def __getslice__(self, i, j):
593
aa5762c7b7f1 Minor, cosmetic tweaks.
cmlenz
parents: 576
diff changeset
372 """Return a slice of the attributes list.
aa5762c7b7f1 Minor, cosmetic tweaks.
cmlenz
parents: 576
diff changeset
373
aa5762c7b7f1 Minor, cosmetic tweaks.
cmlenz
parents: 576
diff changeset
374 >>> attrs = Attrs([('href', '#'), ('title', 'Foo')])
aa5762c7b7f1 Minor, cosmetic tweaks.
cmlenz
parents: 576
diff changeset
375 >>> attrs[1:]
aa5762c7b7f1 Minor, cosmetic tweaks.
cmlenz
parents: 576
diff changeset
376 Attrs([('title', 'Foo')])
aa5762c7b7f1 Minor, cosmetic tweaks.
cmlenz
parents: 576
diff changeset
377 """
345
8e75b83d3e71 Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
378 return Attrs(tuple.__getslice__(self, i, j))
8e75b83d3e71 Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
379
8e75b83d3e71 Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
380 def __or__(self, attrs):
8e75b83d3e71 Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
381 """Return a new instance that contains the attributes in `attrs` in
8e75b83d3e71 Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
382 addition to any already existing attributes.
498
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
383
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
384 :return: a new instance with the merged attributes
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
385 :rtype: `Attrs`
345
8e75b83d3e71 Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
386 """
8e75b83d3e71 Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
387 repl = dict([(an, av) for an, av in attrs if an in self])
8e75b83d3e71 Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
388 return Attrs([(sn, repl.get(sn, sv)) for sn, sv in self] +
8e75b83d3e71 Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
389 [(an, av) for an, av in attrs if an not in self])
8e75b83d3e71 Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
390
326
08ada6b4b767 Fixed `__repr__` of the `QName`, `Attrs`, and `Expression` classes so that the output can be used as code to instantiate the object again.
cmlenz
parents: 279
diff changeset
391 def __repr__(self):
08ada6b4b767 Fixed `__repr__` of the `QName`, `Attrs`, and `Expression` classes so that the output can be used as code to instantiate the object again.
cmlenz
parents: 279
diff changeset
392 if not self:
08ada6b4b767 Fixed `__repr__` of the `QName`, `Attrs`, and `Expression` classes so that the output can be used as code to instantiate the object again.
cmlenz
parents: 279
diff changeset
393 return 'Attrs()'
345
8e75b83d3e71 Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
394 return 'Attrs([%s])' % ', '.join([repr(item) for item in self])
8e75b83d3e71 Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
395
8e75b83d3e71 Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
396 def __sub__(self, names):
8e75b83d3e71 Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
397 """Return a new instance with all attributes with a name in `names` are
8e75b83d3e71 Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
398 removed.
498
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
399
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
400 :param names: the names of the attributes to remove
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
401 :return: a new instance with the attribute removed
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
402 :rtype: `Attrs`
345
8e75b83d3e71 Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
403 """
8e75b83d3e71 Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
404 if isinstance(names, basestring):
8e75b83d3e71 Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
405 names = (names,)
8e75b83d3e71 Make `Attrs` instances immutable.
cmlenz
parents: 326
diff changeset
406 return Attrs([(name, val) for name, val in self if name not in names])
326
08ada6b4b767 Fixed `__repr__` of the `QName`, `Attrs`, and `Expression` classes so that the output can be used as code to instantiate the object again.
cmlenz
parents: 279
diff changeset
407
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
408 def get(self, name, default=None):
18
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
409 """Return the value of the attribute with the specified name, or the
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
410 value of the `default` parameter if no such attribute is found.
435
7800a61eae43 More API doc enhancements.
cmlenz
parents: 434
diff changeset
411
7800a61eae43 More API doc enhancements.
cmlenz
parents: 434
diff changeset
412 :param name: the name of the attribute
7800a61eae43 More API doc enhancements.
cmlenz
parents: 434
diff changeset
413 :param default: the value to return when the attribute does not exist
7800a61eae43 More API doc enhancements.
cmlenz
parents: 434
diff changeset
414 :return: the attribute value, or the `default` value if that attribute
7800a61eae43 More API doc enhancements.
cmlenz
parents: 434
diff changeset
415 does not exist
498
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
416 :rtype: `object`
18
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
417 """
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
418 for attr, value in self:
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
419 if attr == name:
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
420 return value
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
421 return default
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
422
77
f1aa49c759b2 * Simplify implementation of the individual XPath tests (use closures instead of callable classes)
cmlenz
parents: 73
diff changeset
423 def totuple(self):
161
a25f9fc5787d Various docstring additions and other cosmetic changes.
cmlenz
parents: 147
diff changeset
424 """Return the attributes as a markup event.
a25f9fc5787d Various docstring additions and other cosmetic changes.
cmlenz
parents: 147
diff changeset
425
425
5b248708bbed Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents: 408
diff changeset
426 The returned event is a `TEXT` event, the data is the value of all
161
a25f9fc5787d Various docstring additions and other cosmetic changes.
cmlenz
parents: 147
diff changeset
427 attributes joined together.
434
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
428
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
429 >>> Attrs([('href', '#'), ('title', 'Foo')]).totuple()
852
04945cd67dad Remove usage of unicode literals in a couple of places where they were not strictly necessary.
cmlenz
parents: 843
diff changeset
430 ('TEXT', '#Foo', (None, -1, -1))
498
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
431
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
432 :return: a `TEXT` event
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
433 :rtype: `tuple`
161
a25f9fc5787d Various docstring additions and other cosmetic changes.
cmlenz
parents: 147
diff changeset
434 """
852
04945cd67dad Remove usage of unicode literals in a couple of places where they were not strictly necessary.
cmlenz
parents: 843
diff changeset
435 return TEXT, ''.join([x[1] for x in self]), (None, -1, -1)
77
f1aa49c759b2 * Simplify implementation of the individual XPath tests (use closures instead of callable classes)
cmlenz
parents: 73
diff changeset
436
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
437
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
438 class Markup(unicode):
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
439 """Marks a string as being safe for inclusion in HTML/XML output without
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
440 needing to be escaped.
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
441 """
18
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
442 __slots__ = []
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
443
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
444 def __add__(self, other):
204
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
445 return Markup(unicode(self) + unicode(escape(other)))
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
446
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
447 def __radd__(self, other):
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
448 return Markup(unicode(escape(other)) + unicode(self))
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
449
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
450 def __mod__(self, args):
713
a58a50e89d04 The `Markup` class now supports mappings for right hand of the `%` (modulo) operator in the same way the Python string classes do, except that the substituted values are escape. Also, the special constructor which took positional arguments that would be substituted was removed. Thus the `Markup` class now supports the same arguments as that of its `unicode` base class. Closes #211. Many thanks to Christian Boos for the patch!
cmlenz
parents: 688
diff changeset
451 if isinstance(args, dict):
a58a50e89d04 The `Markup` class now supports mappings for right hand of the `%` (modulo) operator in the same way the Python string classes do, except that the substituted values are escape. Also, the special constructor which took positional arguments that would be substituted was removed. Thus the `Markup` class now supports the same arguments as that of its `unicode` base class. Closes #211. Many thanks to Christian Boos for the patch!
cmlenz
parents: 688
diff changeset
452 args = dict(zip(args.keys(), map(escape, args.values())))
a58a50e89d04 The `Markup` class now supports mappings for right hand of the `%` (modulo) operator in the same way the Python string classes do, except that the substituted values are escape. Also, the special constructor which took positional arguments that would be substituted was removed. Thus the `Markup` class now supports the same arguments as that of its `unicode` base class. Closes #211. Many thanks to Christian Boos for the patch!
cmlenz
parents: 688
diff changeset
453 elif isinstance(args, (list, tuple)):
a58a50e89d04 The `Markup` class now supports mappings for right hand of the `%` (modulo) operator in the same way the Python string classes do, except that the substituted values are escape. Also, the special constructor which took positional arguments that would be substituted was removed. Thus the `Markup` class now supports the same arguments as that of its `unicode` base class. Closes #211. Many thanks to Christian Boos for the patch!
cmlenz
parents: 688
diff changeset
454 args = tuple(map(escape, args))
a58a50e89d04 The `Markup` class now supports mappings for right hand of the `%` (modulo) operator in the same way the Python string classes do, except that the substituted values are escape. Also, the special constructor which took positional arguments that would be substituted was removed. Thus the `Markup` class now supports the same arguments as that of its `unicode` base class. Closes #211. Many thanks to Christian Boos for the patch!
cmlenz
parents: 688
diff changeset
455 else:
a58a50e89d04 The `Markup` class now supports mappings for right hand of the `%` (modulo) operator in the same way the Python string classes do, except that the substituted values are escape. Also, the special constructor which took positional arguments that would be substituted was removed. Thus the `Markup` class now supports the same arguments as that of its `unicode` base class. Closes #211. Many thanks to Christian Boos for the patch!
cmlenz
parents: 688
diff changeset
456 args = escape(args)
a58a50e89d04 The `Markup` class now supports mappings for right hand of the `%` (modulo) operator in the same way the Python string classes do, except that the substituted values are escape. Also, the special constructor which took positional arguments that would be substituted was removed. Thus the `Markup` class now supports the same arguments as that of its `unicode` base class. Closes #211. Many thanks to Christian Boos for the patch!
cmlenz
parents: 688
diff changeset
457 return Markup(unicode.__mod__(self, args))
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
458
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
459 def __mul__(self, num):
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
460 return Markup(unicode(self) * num)
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
461
204
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
462 def __rmul__(self, num):
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
463 return Markup(num * unicode(self))
516a6cae0aa8 * Implement reverse add/mul operators for `Markup` class, so that the result is also a `Markup` instance.
cmlenz
parents: 200
diff changeset
464
17
ad63ad459524 Refactoring to address #6: all match templates are now processed by a single filter, which means that match templates added by included templates are properly applied. A side effect of this refactoring is that `Context` objects may not be reused across multiple template processing runs.
cmlenz
parents: 10
diff changeset
465 def __repr__(self):
382
d7da3fba7faf * Added documentation for the various stream event kinds.
cmlenz
parents: 377
diff changeset
466 return '<%s %r>' % (self.__class__.__name__, unicode(self))
17
ad63ad459524 Refactoring to address #6: all match templates are now processed by a single filter, which means that match templates added by included templates are properly applied. A side effect of this refactoring is that `Context` objects may not be reused across multiple template processing runs.
cmlenz
parents: 10
diff changeset
467
54
01981cbc7575 Fix a number of escaping problems:
cmlenz
parents: 34
diff changeset
468 def join(self, seq, escape_quotes=True):
434
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
469 """Return a `Markup` object which is the concatenation of the strings
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
470 in the given sequence, where this `Markup` object is the separator
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
471 between the joined elements.
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
472
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
473 Any element in the sequence that is not a `Markup` instance is
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
474 automatically escaped.
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
475
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
476 :param seq: the sequence of strings to join
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
477 :param escape_quotes: whether double quote characters in the elements
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
478 should be escaped
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
479 :return: the joined `Markup` object
498
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
480 :rtype: `Markup`
434
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
481 :see: `escape`
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
482 """
54
01981cbc7575 Fix a number of escaping problems:
cmlenz
parents: 34
diff changeset
483 return Markup(unicode(self).join([escape(item, quotes=escape_quotes)
34
ae293292cbb1 quotes should not be escaped inside text nodes
mgood
parents: 27
diff changeset
484 for item in seq]))
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
485
822
ce5ad2d540b3 Get rid of some Python 2.3 legacy that's no longer needed now that 2.4 is the baseline.
cmlenz
parents: 793
diff changeset
486 @classmethod
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
487 def escape(cls, text, quotes=True):
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
488 """Create a Markup instance from a string and escape special characters
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
489 it may contain (<, >, & and \").
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
490
434
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
491 >>> escape('"1 < 2"')
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
492 <Markup u'&#34;1 &lt; 2&#34;'>
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
493
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
494 If the `quotes` parameter is set to `False`, the \" character is left
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
495 as is. Escaping quotes is generally only required for strings that are
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
496 to be used in attribute values.
434
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
497
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
498 >>> escape('"1 < 2"', quotes=False)
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
499 <Markup u'"1 &lt; 2"'>
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
500
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
501 :param text: the text to escape
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
502 :param quotes: if ``True``, double quote characters are escaped in
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
503 addition to the other special characters
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
504 :return: the escaped `Markup` string
498
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
505 :rtype: `Markup`
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
506 """
73
b0fd16111f2e Some more performance tweaks.
cmlenz
parents: 69
diff changeset
507 if not text:
b0fd16111f2e Some more performance tweaks.
cmlenz
parents: 69
diff changeset
508 return cls()
b0fd16111f2e Some more performance tweaks.
cmlenz
parents: 69
diff changeset
509 if type(text) is cls:
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
510 return text
737
686bbeecb9ac Implement the `__html__` protocol as suggested in #202. This would allow Genshi to be used in combination with other markup generating tools, as long as they support the same protocol.
cmlenz
parents: 719
diff changeset
511 if hasattr(text, '__html__'):
686bbeecb9ac Implement the `__html__` protocol as suggested in #202. This would allow Genshi to be used in combination with other markup generating tools, as long as they support the same protocol.
cmlenz
parents: 719
diff changeset
512 return Markup(text.__html__())
686bbeecb9ac Implement the `__html__` protocol as suggested in #202. This would allow Genshi to be used in combination with other markup generating tools, as long as they support the same protocol.
cmlenz
parents: 719
diff changeset
513
73
b0fd16111f2e Some more performance tweaks.
cmlenz
parents: 69
diff changeset
514 text = unicode(text).replace('&', '&amp;') \
b0fd16111f2e Some more performance tweaks.
cmlenz
parents: 69
diff changeset
515 .replace('<', '&lt;') \
b0fd16111f2e Some more performance tweaks.
cmlenz
parents: 69
diff changeset
516 .replace('>', '&gt;')
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
517 if quotes:
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
518 text = text.replace('"', '&#34;')
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
519 return cls(text)
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
520
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
521 def unescape(self):
434
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
522 """Reverse-escapes &, <, >, and \" and returns a `unicode` object.
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
523
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
524 >>> Markup('1 &lt; 2').unescape()
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
525 u'1 < 2'
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
526
498
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
527 :return: the unescaped string
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
528 :rtype: `unicode`
434
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
529 :see: `genshi.core.unescape`
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
530 """
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
531 if not self:
852
04945cd67dad Remove usage of unicode literals in a couple of places where they were not strictly necessary.
cmlenz
parents: 843
diff changeset
532 return ''
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
533 return unicode(self).replace('&#34;', '"') \
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
534 .replace('&gt;', '>') \
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
535 .replace('&lt;', '<') \
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
536 .replace('&amp;', '&')
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
537
116
88ac4c680120 Merged [135:138/branches/experimental/cspeedups].
cmlenz
parents: 115
diff changeset
538 def stripentities(self, keepxmlentities=False):
88ac4c680120 Merged [135:138/branches/experimental/cspeedups].
cmlenz
parents: 115
diff changeset
539 """Return a copy of the text with any character or numeric entities
88ac4c680120 Merged [135:138/branches/experimental/cspeedups].
cmlenz
parents: 115
diff changeset
540 replaced by the equivalent UTF-8 characters.
88ac4c680120 Merged [135:138/branches/experimental/cspeedups].
cmlenz
parents: 115
diff changeset
541
88ac4c680120 Merged [135:138/branches/experimental/cspeedups].
cmlenz
parents: 115
diff changeset
542 If the `keepxmlentities` parameter is provided and evaluates to `True`,
434
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
543 the core XML entities (``&amp;``, ``&apos;``, ``&gt;``, ``&lt;`` and
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
544 ``&quot;``) are not stripped.
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
545
498
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
546 :return: a `Markup` instance with entities removed
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
547 :rtype: `Markup`
434
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
548 :see: `genshi.util.stripentities`
6
5da45906dda7 Simplified implementation of `py:content` directive.
cmlenz
parents: 5
diff changeset
549 """
116
88ac4c680120 Merged [135:138/branches/experimental/cspeedups].
cmlenz
parents: 115
diff changeset
550 return Markup(stripentities(self, keepxmlentities=keepxmlentities))
88ac4c680120 Merged [135:138/branches/experimental/cspeedups].
cmlenz
parents: 115
diff changeset
551
88ac4c680120 Merged [135:138/branches/experimental/cspeedups].
cmlenz
parents: 115
diff changeset
552 def striptags(self):
434
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
553 """Return a copy of the text with all XML/HTML tags removed.
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
554
498
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
555 :return: a `Markup` instance with all tags removed
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
556 :rtype: `Markup`
434
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
557 :see: `genshi.util.striptags`
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
558 """
116
88ac4c680120 Merged [135:138/branches/experimental/cspeedups].
cmlenz
parents: 115
diff changeset
559 return Markup(striptags(self))
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
560
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
561
541
4a53763b3948 Merged cspeedups branch into trunk.
cmlenz
parents: 498
diff changeset
562 try:
4a53763b3948 Merged cspeedups branch into trunk.
cmlenz
parents: 498
diff changeset
563 from genshi._speedups import Markup
4a53763b3948 Merged cspeedups branch into trunk.
cmlenz
parents: 498
diff changeset
564 except ImportError:
4a53763b3948 Merged cspeedups branch into trunk.
cmlenz
parents: 498
diff changeset
565 pass # just use the Python implementation
4a53763b3948 Merged cspeedups branch into trunk.
cmlenz
parents: 498
diff changeset
566
843
004f81b59d97 Refactored the template flattening method to be less recursive.
cmlenz
parents: 822
diff changeset
567
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
568 escape = Markup.escape
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
569
843
004f81b59d97 Refactored the template flattening method to be less recursive.
cmlenz
parents: 822
diff changeset
570
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
571 def unescape(text):
434
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
572 """Reverse-escapes &, <, >, and \" and returns a `unicode` object.
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
573
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
574 >>> unescape(Markup('1 &lt; 2'))
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
575 u'1 < 2'
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
576
498
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
577 If the provided `text` object is not a `Markup` instance, it is returned
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
578 unchanged.
434
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
579
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
580 >>> unescape('1 &lt; 2')
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
581 '1 &lt; 2'
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
582
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
583 :param text: the text to unescape
498
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
584 :return: the unescsaped string
5b42b341185a A couple of minor doc refinements.
cmlenz
parents: 462
diff changeset
585 :rtype: `unicode`
434
e065d7906b68 * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
586 """
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
587 if not isinstance(text, Markup):
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
588 return text
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
589 return text.unescape()
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
590
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
591
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
592 class Namespace(object):
18
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
593 """Utility class creating and testing elements with a namespace.
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
594
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
595 Internally, namespace URIs are encoded in the `QName` of any element or
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
596 attribute, the namespace URI being enclosed in curly braces. This class
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
597 helps create and test these strings.
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
598
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
599 A `Namespace` object is instantiated with the namespace URI.
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
600
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
601 >>> html = Namespace('http://www.w3.org/1999/xhtml')
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
602 >>> html
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
603 <Namespace "http://www.w3.org/1999/xhtml">
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
604 >>> html.uri
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
605 u'http://www.w3.org/1999/xhtml'
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
606
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
607 The `Namespace` object can than be used to generate `QName` objects with
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
608 that namespace:
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
609
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
610 >>> html.body
326
08ada6b4b767 Fixed `__repr__` of the `QName`, `Attrs`, and `Expression` classes so that the output can be used as code to instantiate the object again.
cmlenz
parents: 279
diff changeset
611 QName(u'http://www.w3.org/1999/xhtml}body')
18
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
612 >>> html.body.localname
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
613 u'body'
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
614 >>> html.body.namespace
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
615 u'http://www.w3.org/1999/xhtml'
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
616
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
617 The same works using item access notation, which is useful for element or
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
618 attribute names that are not valid Python identifiers:
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
619
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
620 >>> html['body']
326
08ada6b4b767 Fixed `__repr__` of the `QName`, `Attrs`, and `Expression` classes so that the output can be used as code to instantiate the object again.
cmlenz
parents: 279
diff changeset
621 QName(u'http://www.w3.org/1999/xhtml}body')
18
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
622
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
623 A `Namespace` object can also be used to test whether a specific `QName`
425
5b248708bbed Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents: 408
diff changeset
624 belongs to that namespace using the ``in`` operator:
18
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
625
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
626 >>> qname = html.body
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
627 >>> qname in html
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
628 True
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
629 >>> qname in Namespace('http://www.w3.org/2002/06/xhtml2')
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
630 False
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
631 """
224
e4dad1145f84 Implement support for namespace prefixes in XPath expressions.
cmlenz
parents: 204
diff changeset
632 def __new__(cls, uri):
e4dad1145f84 Implement support for namespace prefixes in XPath expressions.
cmlenz
parents: 204
diff changeset
633 if type(uri) is cls:
e4dad1145f84 Implement support for namespace prefixes in XPath expressions.
cmlenz
parents: 204
diff changeset
634 return uri
685
3e8d0c061ac7 Fix #180 (py2.6 warning).
cmlenz
parents: 666
diff changeset
635 return object.__new__(cls)
224
e4dad1145f84 Implement support for namespace prefixes in XPath expressions.
cmlenz
parents: 204
diff changeset
636
279
4b5b4653d41e Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents: 278
diff changeset
637 def __getnewargs__(self):
4b5b4653d41e Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents: 278
diff changeset
638 return (self.uri,)
4b5b4653d41e Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents: 278
diff changeset
639
4b5b4653d41e Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents: 278
diff changeset
640 def __getstate__(self):
4b5b4653d41e Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents: 278
diff changeset
641 return self.uri
4b5b4653d41e Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents: 278
diff changeset
642
4b5b4653d41e Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents: 278
diff changeset
643 def __setstate__(self, uri):
4b5b4653d41e Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents: 278
diff changeset
644 self.uri = uri
4b5b4653d41e Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents: 278
diff changeset
645
18
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
646 def __init__(self, uri):
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
647 self.uri = unicode(uri)
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
648
18
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
649 def __contains__(self, qname):
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
650 return qname.namespace == self.uri
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
651
278
8de2620504b9 Fix the handling of namespace context for match templates.
cmlenz
parents: 230
diff changeset
652 def __ne__(self, other):
8de2620504b9 Fix the handling of namespace context for match templates.
cmlenz
parents: 230
diff changeset
653 return not self == other
8de2620504b9 Fix the handling of namespace context for match templates.
cmlenz
parents: 230
diff changeset
654
18
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
655 def __eq__(self, other):
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
656 if isinstance(other, Namespace):
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
657 return self.uri == other.uri
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
658 return self.uri == other
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
659
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
660 def __getitem__(self, name):
852
04945cd67dad Remove usage of unicode literals in a couple of places where they were not strictly necessary.
cmlenz
parents: 843
diff changeset
661 return QName(self.uri + '}' + name)
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
662 __getattr__ = __getitem__
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
663
793
7cf2407671c2 Get rid of a couple more -3 warnings.
cmlenz
parents: 792
diff changeset
664 def __hash__(self):
7cf2407671c2 Get rid of a couple more -3 warnings.
cmlenz
parents: 792
diff changeset
665 return hash(self.uri)
7cf2407671c2 Get rid of a couple more -3 warnings.
cmlenz
parents: 792
diff changeset
666
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
667 def __repr__(self):
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
668 return '<Namespace "%s">' % self.uri
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
669
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
670 def __str__(self):
18
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
671 return self.uri.encode('utf-8')
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
672
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
673 def __unicode__(self):
18
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
674 return self.uri
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
675
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
676
147
f7fb556f2678 Use `xmlcharrefreplace` when encoding the output in `Stream.render()`, so that encoding the output to legacy encodings such as ASCII or ISO-8859-1 should always work.
cmlenz
parents: 145
diff changeset
677 # The namespace used by attributes such as xml:lang and xml:space
141
b3ceaa35fb6b * No escaping of `<script>` or `<style>` tags in HTML output (see #24)
cmlenz
parents: 140
diff changeset
678 XML_NAMESPACE = Namespace('http://www.w3.org/XML/1998/namespace')
b3ceaa35fb6b * No escaping of `<script>` or `<style>` tags in HTML output (see #24)
cmlenz
parents: 140
diff changeset
679
b3ceaa35fb6b * No escaping of `<script>` or `<style>` tags in HTML output (see #24)
cmlenz
parents: 140
diff changeset
680
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
681 class QName(unicode):
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
682 """A qualified element or attribute name.
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
683
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
684 The unicode value of instances of this class contains the qualified name of
666
9729855cacf4 `QName` can now be constructed from a string with a leading curly brace, and some doc improvements. Closes #164.
cmlenz
parents: 634
diff changeset
685 the element or attribute, in the form ``{namespace-uri}local-name``. The
9729855cacf4 `QName` can now be constructed from a string with a leading curly brace, and some doc improvements. Closes #164.
cmlenz
parents: 634
diff changeset
686 namespace URI can be obtained through the additional `namespace` attribute,
9729855cacf4 `QName` can now be constructed from a string with a leading curly brace, and some doc improvements. Closes #164.
cmlenz
parents: 634
diff changeset
687 while the local name can be accessed through the `localname` attribute.
18
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
688
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
689 >>> qname = QName('foo')
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
690 >>> qname
326
08ada6b4b767 Fixed `__repr__` of the `QName`, `Attrs`, and `Expression` classes so that the output can be used as code to instantiate the object again.
cmlenz
parents: 279
diff changeset
691 QName(u'foo')
18
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
692 >>> qname.localname
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
693 u'foo'
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
694 >>> qname.namespace
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
695
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
696 >>> qname = QName('http://www.w3.org/1999/xhtml}body')
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
697 >>> qname
326
08ada6b4b767 Fixed `__repr__` of the `QName`, `Attrs`, and `Expression` classes so that the output can be used as code to instantiate the object again.
cmlenz
parents: 279
diff changeset
698 QName(u'http://www.w3.org/1999/xhtml}body')
18
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
699 >>> qname.localname
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
700 u'body'
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
701 >>> qname.namespace
4cbebb15a834 Actually make use of the `markup.core.Namespace` class, and add a couple of doctests.
cmlenz
parents: 17
diff changeset
702 u'http://www.w3.org/1999/xhtml'
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
703 """
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
704 __slots__ = ['namespace', 'localname']
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
705
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
706 def __new__(cls, qname):
666
9729855cacf4 `QName` can now be constructed from a string with a leading curly brace, and some doc improvements. Closes #164.
cmlenz
parents: 634
diff changeset
707 """Create the `QName` instance.
9729855cacf4 `QName` can now be constructed from a string with a leading curly brace, and some doc improvements. Closes #164.
cmlenz
parents: 634
diff changeset
708
9729855cacf4 `QName` can now be constructed from a string with a leading curly brace, and some doc improvements. Closes #164.
cmlenz
parents: 634
diff changeset
709 :param qname: the qualified name as a string of the form
9729855cacf4 `QName` can now be constructed from a string with a leading curly brace, and some doc improvements. Closes #164.
cmlenz
parents: 634
diff changeset
710 ``{namespace-uri}local-name``, where the leading curly
9729855cacf4 `QName` can now be constructed from a string with a leading curly brace, and some doc improvements. Closes #164.
cmlenz
parents: 634
diff changeset
711 brace is optional
9729855cacf4 `QName` can now be constructed from a string with a leading curly brace, and some doc improvements. Closes #164.
cmlenz
parents: 634
diff changeset
712 """
100
5e9987f34e6c Ported [111] to trunk.
cmlenz
parents: 96
diff changeset
713 if type(qname) is cls:
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
714 return qname
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
715
852
04945cd67dad Remove usage of unicode literals in a couple of places where they were not strictly necessary.
cmlenz
parents: 843
diff changeset
716 parts = qname.lstrip('{').split('}', 1)
100
5e9987f34e6c Ported [111] to trunk.
cmlenz
parents: 96
diff changeset
717 if len(parts) > 1:
852
04945cd67dad Remove usage of unicode literals in a couple of places where they were not strictly necessary.
cmlenz
parents: 843
diff changeset
718 self = unicode.__new__(cls, '{%s' % qname)
136
636e0100fcaf Minor performance improvements in serialization.
cmlenz
parents: 133
diff changeset
719 self.namespace, self.localname = map(unicode, parts)
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
720 else:
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
721 self = unicode.__new__(cls, qname)
136
636e0100fcaf Minor performance improvements in serialization.
cmlenz
parents: 133
diff changeset
722 self.namespace, self.localname = None, unicode(qname)
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
723 return self
279
4b5b4653d41e Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents: 278
diff changeset
724
4b5b4653d41e Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents: 278
diff changeset
725 def __getnewargs__(self):
4b5b4653d41e Some adjustments to make core data structures picklable (requires protocol 2).
cmlenz
parents: 278
diff changeset
726 return (self.lstrip('{'),)
326
08ada6b4b767 Fixed `__repr__` of the `QName`, `Attrs`, and `Expression` classes so that the output can be used as code to instantiate the object again.
cmlenz
parents: 279
diff changeset
727
08ada6b4b767 Fixed `__repr__` of the `QName`, `Attrs`, and `Expression` classes so that the output can be used as code to instantiate the object again.
cmlenz
parents: 279
diff changeset
728 def __repr__(self):
08ada6b4b767 Fixed `__repr__` of the `QName`, `Attrs`, and `Expression` classes so that the output can be used as code to instantiate the object again.
cmlenz
parents: 279
diff changeset
729 return 'QName(%s)' % unicode.__repr__(self.lstrip('{'))
Copyright (C) 2012-2017 Edgewall Software