File: filtering.myt

package info (click to toggle)
myghty 1.1-6
  • links: PTS, VCS
  • area: main
  • in suites: buster, stretch
  • size: 1,924 kB
  • ctags: 2,278
  • sloc: python: 11,705; makefile: 10
file content (274 lines) | stat: -rw-r--r-- 17,243 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
<%flags>inherit='document_base.myt'</%flags>
<&|doclib.myt:item, name="filtering", description="Filtering and Flushing (and Escaping)", escapedesc=True, header="Additional Features" &>

<p>This section describes some options that can be applied to Myghty components which affect how the request object deals with their output.   The request object supports the capturing of component output in a buffer which is flushed upon completion to provide simple and flexible component output behavior, or sending the output directly to the underlying output stream to provide faster perceived response time.  This option is known as <b>autoflush</b>.   Post-processing functions can be attached to the final output of a component at the top-level or callable component level, allowing user-defined text operations on the output, known as <b>filtering</b>.  Autoflushing and filtering have some dependencies on each other, so they are described together.</p>

<p>As a convenient alternative to filtering, common text-escaping functions applicable to a web application environment, plus support for user-defined escape functions, are provided under the functionality of <b>escapes</b>, described at the end of the section.</p>

<&|doclib.myt:item, name="autoflush", description="The Autoflush Option", escapedesc=True &>
<p>The <&|formatting.myt:codeline&>autoflush</&> option controls whether the output of a component is sent to the underlying output stream as it is produced, or if it is first captured in a buffer which is then sent in one chunk at the end of the request's lifecycle.  This is significant in a web context, as it affects "perceived performance", which means the response time of an unbuffered page is nearly immediate, even though the time it takes to finish might be the same as that of a buffered page.</p>

<P>While the autoflush option can improve perceived performance, there are also increased complexities with an autoflushed, i.e. unbuffered page.  HTTP headers, including hard redirects, must be sent before any content is written, else the response will have already begun and any new headers will simply be displayed with the page's content.   A soft redirect, not being dependent on HTTP headers, will still function, but it's output also may be corrupted via any preceding output.  Error messages also will appear inline with already existing content rather than on a page of their own.</p>

<p>
The option can be set for an entire application, for a set of files or directories via autohandlers/inherited superpages, for an individual page, or even an individual method or subcomponent within a page.   Within all of those scopes, the flag can be set at a more specific level and will override the more general level.  </p>

<p>With no configuration, the parameter defaults to <&|formatting.myt:codeline&>False</&>, meaning that component output is captured in a buffer, which is flushed at the end of the request or subcomponent's execution.  This produces the simplest behavior and is fine for most applications.</p>

<p>But, here you are and you want to turn <&|formatting.myt:codeline&>autoflush</&> on.  To set it across an entire application, specify <span class="codeline">autoflush=True</span> to the Interpreter or HTTPHandler being used.  Or to configure via http.conf with mod_python:</p>

<&|formatting.myt:code&>
	PythonOption MyghtyAutoflush True
</&>

<p>When autoflush is true for an entire application, no buffer is placed between the output of a component and the underlying request output stream.  The flag can be overridden back to <&|formatting.myt:codeline&>False</&> within directories and pages via the use of the <&|formatting.myt:codeline&>autoflush</&> flag within the %flags section of the page.  To set the value of autoflush for a particular directory, place an <&|formatting.myt:codeline&>autohandler</&> file at the base of the directory as such:

<&|formatting.myt:code&><%text>
<%flags>autoflush=False</%flags>
% m.call_next()
</%text></&>

<p>The Myghty request will run the autohandler which then calls the inherited page via the <&|formatting.myt:codeline&>m.call_next()</&> call.   The autoflush flag indicates that buffering should be enabled for the execution of this page, overriding the per-application setting of True. </p>

<p>The ultimate <span class="codeline">autoflush</span> flag that is used for a page is the innermost occuring flag within the templates that comprise the wrapper chain.  If no autoflush flag is present, the next enclosing template is used, and if no template contains an autoflush flag, the application setting is used.  Even though an autohandler executes before the page that it encloses, the Myghty request figures out what the autoflush behavior should be before executing any components so that it takes the proper effect.</p>

<p>So any page can control its own autoflush behavior as follows:</p>

<&|formatting.myt:code&><%text>
<%flags>autoflush=False</%flags>
<html>
	<head>
	...
</html>
</%text></&>

<&|doclib.myt:item, name="subcomponents", description="Setting Autoflush in Subcomponents" &>
<p>
Subcomponent or methods can determine their autoflush behavior as follows:
</p>
<&|formatting.myt:code&><%text>
<%def mycomp>
<%flags>autoflush=False</%flags>
	... stuff ...
</%def>
</%text></&>
<p>There is one limitation to the autoflush flag when used in a subcomponent.  If autoflush is set to True on a subcomponent, within a request that has autoflush set to False, the component will send its unfiltered data directly to the output stream of its parent; however since the overall request is not autoflushing and is instead capturing its content in a buffer of its own, the content is still stored in a buffer, which does not get sent to the client until the request is complete.  Note that this limitation does not exist the other way around;  if an overall request is autoflushing, and a subcomponent sets autoflush to False, that subcomponent's output will be buffered,  until the subcomponent completes its execution.  This is significant for a subcomponent whos output is being processed by a <% "<%filter>" %> section.  More on this later.
</p>
</&>

<&|doclib.myt:item, name="autohandlers", description="Non-Buffered with Autohandlers", escapedesc=True  &>
<p>What happens when a page in an autoflush=True environment interacts with one or more autohandlers or inherited superpages?  The superpage will execute first, output whatever content it has before it calls the subpage, and then will call <&|formatting.myt:codeline&>m.call_next()</&> to pass control to the subpage.  If the subpage then wants to play with HTTP headers and/or perform redirects, it's out of luck:</p>

	<&|formatting.myt:code, title="autohandler - autoflush enabled"&><%text>
	<%flags>autoflush=True</%flags>
	<html>
		<head></head>
		<body>
	% m.call_next()
		</body>
	</html>
	</%text></&>

	<&|formatting.myt:code, title="page.myt - wants to send a redirect"&><%text>
	<%python scope="init">
		m.send_redirect("page2.myt", hard=True)
	</%python>
	</%text></&>



<p>The above example will fail!  Since the autohandler executes and prints the top HTML tags to the underlying output stream, by the time page.myt tries to send its redirect, the HTTP headers have already been written and you'll basically get a broken HTML page.   What to do?  Either page.myt needs to specify that it is not an autoflushing page, or it can detach itself from its inherited parent.</p>

<p>Solution One -  Turn Autoflush On:</p>

	<&|formatting.myt:code, title="page.myt"&><%text>
	<%flags>autoflush=False</%flags>
	<%python scope="init">
		m.send_redirect("page2.myt", hard=True)
	</%python>
	</%text></&>

<p>This is the most general-purpose method, which just disables autoflush for just that one page.</p>

<p>Solution Two - Inherit from None</p>

	<&|formatting.myt:code, title="page.myt"&><%text>
	<%flags>inherit=None</%flags>
	<%python scope="init">
		m.send_redirect("page2.myt", hard=True)
	</%python>
	</%text></&>
	
<p>This method is appropriate for a page that never needs to output any content, i.e. it always will be performing a redirect.  The autohandler here is not inherited, so never even gets called.  This saves you the processing time of the autohandler setting up buffers and producing content.  Of course, if there are autohandlers that are performing operations that this subpage depends upon, then you must be sure to inherit from those pages, possibly through the use of "alternate" autohandlers that inherit only from the desired pages.  

</&>
</&>





<&|doclib.myt:item, name="filtering", description="Filtering", escapedesc=True &>
<p>Filtering means that the output stream of a component is sent through a text processing function which modifies the content before it is passed on to the ultimate output stream.   Typical usages of text filtering are modifying entity references, trimming whitespace, converting plain-text to HTML, and lots of other things.  For the general purpose per-component filter, Myghty supplies the <nobr><% "<%filter>" %></nobr> tag.  
</p>


<&|doclib.myt:item, name="filter", description="The <%filter> Tag", escapedesc=True &>
<p>%filter describes a filtering function that is applied to the final output of a component.  This is more common on subcomponents or methods but works within the scope of any top-level component as well.   The Python code within the %filter section provides the body of the to be used; the heading of the function is generated within the compiled component and not normally seen.  The filter function is provided with one argument <i>f</i> which contains the content to be filtered; the function processes content and returns the new value.</p>

<p>Example:</p>

<&|formatting.myt:code&><%text>
<%filter>
import re
return re.sub(r"turkey", "penguin", f)
</%filter>

dang those flyin turkeys !

</%text></&>

<p> will produce:</p>

<&|formatting.myt:code&>
dang those flyin penguins !
</&>	

</&>

<&|doclib.myt:item, name="escapefilter", description="Escaping Content in a Filter Section", escapedesc=True &>
<p>Myghty has some built in escaping functions, described in the next section  <&formatting.myt:link, path="filtering_escaping"&>.  While these functions are easy enough to use within substitutions or any other Python code, you can of course use them within a filter section as well.</p>
<p>This is a component that HTML escapes its output, i.e. replaces the special characters <% "&, <, and >" | h%> with entity reference encoding:</p>

	<&|formatting.myt:code&><%text>
	<%def bodytext>
		<%filter>
			return m.apply_escapes(f, 'h')
		</%filter>

		# ... component output
	</%def>
	</%text></&>

</&>

<&|doclib.myt:item, name="filterflush", description="Filtering Behavior with Autoflush Enabled", escapedesc=True &>

<p>The usual case when a %filter section is used is that all <&|formatting.myt:codeline&>m.write()</&> statements, both explicit and implicit, send their content to a buffer.  Upon completion of the component's execution, the buffer's content is passed through the function defined in the %filter section.  However when autoflush is enabled, the extra buffer is not used and the filtering function is attached directly to each call to <&|formatting.myt:codeline&>m.write()</&>.  For regular blocks of HTML, the entire block is sent inside of one big <&|formatting.myt:codeline&>write()</&> statement, but each python substitution or other code call splits it up, resulting in another call to <&|formatting.myt:codeline&>write()</&>.</p>

<p>Since a non-autoflushing component is more predictable for filtering purposes than an autoflushing component, it is often useful to have autoflush disabled for a component that uses a %filter section.  As stated in the autoflush section, autoflushing behavior can be changed per component, per page or for the whole application, and is the default value as well.   There is also another configuration option 

can be overridden for all filter components by the setting "dont_auto_flush_filters" - see the section <&formatting.myt:link, path="parameters", &> for more information.</p>

</&>

<&|doclib.myt:item, name="trim", description="Filtering Whitespace - the Trim Flag", escapedesc=True &>
<p>A common need for components is to trim off the whitespace at the beginning and/or the end of a component output.  It is convenient to define subcomponents and methods on multiple lines, but this inherently includes newlines in the output of that component, since Myghty sees the blank lines in the source.  But lots of times the ultimate output of a component needs to not have any surrounding whitespace, such as a component that outputs a hyperlink.  While a regular %filter section can be used for this, Myghty provides the <&|formatting.myt:codeline&>trim</&> flag, as so:</p>

	<&|formatting.myt:code &><%text>
	for more information, click <&makelink, a="here", p=4.3, xg="foo" &>.
	
	<%def makelink trim="both">
	<%args>
		p
		xg
		a
	</%args>
	
	<%doc>note this component has a lot of whitespace in it</%doc>
	<A href="http://foo.myt?xg=<% xg %>&p=<% p | u %>"><% a %></a>
	
	</%def>
	</%text></&>

	<p>Output:</p>
 	<&|formatting.myt:code &><%text>
	for more information, click <A href="http://foo.myt?xg=foo&p=4.3">here</a>.
	</%text></&>
	<p><&|formatting.myt:codeline&>trim</&> supports the three options <&|formatting.myt:codeline&>left</&>, <&|formatting.myt:codeline&>right</&>, or <&|formatting.myt:codeline&>both</&>, trimming whitespace on the left, right and both sides of component output, respectively.
	</p>
</&>

</&>


<&|doclib.myt:item, name="escaping", description="Escaping Content", escapedesc=True &>

<p>Escaping usually refers to a kind of filtering that converts the characters in a string into encoded values that can be safely passed through other character-parsing systems without them interfering.</p>

<p>Myghty provides built in support for HTML and URL escaping (also called URL encoding), and has plans for entity-reference escaping.  User-defined escape functions can be added to an application as well.
</p>

<&|doclib.myt:item, name="substitutions", description="Escaping Substitutions", escapedesc=True &>

<p>Substitutions, first introduced in <&formatting.myt:link, path="embedding_substitutions"&>,  can include escape flags, specified by the following notation:</p>

	<&|formatting.myt:code &><%text> 
	<% "i am an argument" | u %> 
	</%text></&>

<p>The above example will URL encode the embedded string.  The two escape flags included with Myghty are "u" for url encoding, and "h" for HTML encoding.    Entity reference encoding is in the works.</p>

<p>Multiple escape flags are separated by a comma:</p>

	<&|formatting.myt:code &><%text> 
	<% "multiple escapes" | h, u %> 
	</%text></&>

<p>Which will HTML and URL escape the given string.</p>

</&>


<&|doclib.myt:item, name="programmatic", description="Programmatic Escaping", escapedesc=True &>

<p>The HTML and URL-encoded escaping functions described above are easy enough to use programmatically as well.  The request object provides the escaping functions via the <&|formatting.myt:codeline&>apply_escapes()</&> method for this purpose.  This method uses the same flags as an escaped substitution, the defaults being "h" for HTML escaping and "u" for URL encoding.</p>

<p>In this example, a component receives the argument "text" and displays it in a textarea, where HTML escaping is required:</p>

<&|formatting.myt:code&><%text>
	<%args>
		text
	</%args>
	<%python>
		# HTML escape the given text
		text = m.apply_escapes(text, 'h')
	</%python>

	<textarea><% text %></textarea>
</%text></&>

<p>The first argument to <&|formatting.myt:codeline&>apply_escapes()</&> is the text to be escaped, and the second is a list of escape flags.  Since strings are lists in Python, multiple flags can be specified either in a single string as in <&|formatting.myt:codeline&>"hu"</&> or as a regular list such as <&|formatting.myt:codeline&>['h', 'u']</&>.

</&>

<&|doclib.myt:item, name="custom", description="Custom Escape Flags", escapedesc=True &>
<p>You can add your own escape flags to your application via the <&|formatting.myt:codeline&>escapes</&> configuration parameter.  <&|formatting.myt:codeline&>escapes</&> is in the form of a dictionary, with the key names being the single-character escaping token and the values being function pointers to escaping functions.</p>

<p>In this example, an escape flag 'p' is added which provides the ability to convert the word "turkey" into "penguin":

<&|formatting.myt:code&><%text>
    escapes = {
        'p':re.sub('turkey', 'penguin', f)
    }
</%text></&>

</&>



<&|doclib.myt:item, name="custom", description="Default Escape Flags", escapedesc=True &>

<p>Default escaping can be configured via the configuration parameter <&|formatting.myt:codeline&>default_escape_flags</&> (PythonOption MyghtyDefaultEscapeFlags).  The format of this parameter is a list of escape flag characters.  This applies the given flags to <b>all</b> substitutions in an application.</p>

<p>When default escaping is used, the special flag "n" can be specified in the substitution to disable the default escape flags for that substitution.</p>
</&>



</&>




</&>