myghty-1.1/ 0000755 0001750 0001750 00000000000 10501065765 011677 5 ustar malex malex myghty-1.1/CHANGES 0000644 0001750 0001750 00000057260 10501064125 012671 0 ustar malex malex 1.1
- added unicode support ([#9])
- changed handling of non-string arguments to m.write and m.apply_escapes.
all object, except None, get coerced to a string. (None get converted
to the empty string.)
- the out_buffer argument of m.create_subrequest now works ([#12])
1.0.2
- disable_wrapping argument to request will allow a full request
to take place without calling any inherited components
(inheritance relationship still exists though)
- fix to do_remove() on MemoryNamespaceManager
1.0.1
- fixed lexer bug reporting error with closing tag missing
- html exception reporting html-escapes error message
- session object takes "cookie_expires" - True (end of session),
False (never), datetime, or timedelta
- fixed closure-with-content bug
1.0
- lots more docstrings, plus a generated pydoc section
in the docs. still many more docstrings to go.
- m.abort takes optional "reason" parameter along with
return code
- License changed to MIT License
- WSGIHandler no longer url un-escapes PATH_INFO
- MODULE:modname:callable syntax can also be called as:
@modname:callable.
- oops again, its "__all__", not "__ALL__" ! make sure all
your code that tries to "from myghty import *" still works.
- added more docs for configuration, resolution
- added helper functions for writing custom resolvers: 'cache_args'
to ModuleComponentSource, default 'file modification time' for
FileComponentSource
- added module_root_adjust in place of 'adjust' for ResolvePathModule,
component_root_adjust in place of 'adjust' for FileResolver.
- ResolvePathModule arguments are also global config parameters
- argument to path_translate/PathTranslate() can be a callable instead
of a list
0.99a
- added 'ZBlog' demo, a bigger MVC framework which interfaces
to SQLAlchemy as well as an enhanced Myghtyjax (mjax docs
forthcoming hopefully)
- component-calls-with-content can send named arguments to
m.content(), function can get at them via m.content_args[ Below are configuration instructions for the three most basic types of configuration: the standalone handler, a CGI handler, and running under mod_python. For further information on configuration, see:
The standalone handler is a web server built off of Python's BaseHTTPServer class, and is great for local workstation development and testing. Here is a quick example to simply serve pages from the current directory - place the following code into a file run_server.py:
<&|formatting.myt:code, syntaxtype="python"&> #!/usr/local/bin/python import myghty.http.HTTPServerHandler as HTTPServerHandler # create the server. httpd = HTTPServerHandler.HTTPServer( # port number to listen on. port = 8080, # HSHandler list. indicates paths where the file should be interpreted # as a Myghty component request. # Format is a list of dictionaries, each maps a regular expression matching a URI # to an instance of HTTPServerHandler.HSHandler, containing the arguments for # a Myghty interprter. for HTTP requests of type "text/*", this list is matched # first against the incoming request URI. handlers = [ {'.*\.myt' : HTTPServerHandler.HSHandler(data_dir = './cache', component_root = './')}, ], # document root list. indicates paths where the file should be served # like a normal file, with the appropriate MIME type set as the content-type. # These are served for all non "text/*" HTTP requests, and all # incoming URIs that do not match the list of handlers above. docroot = [{'.*' : './'}], ) # run the server httpd.serve_forever() &>Then, in that same directory, place another file, called index.myt:
<&|formatting.myt:code, syntaxtype="myghty"&>To run the server, type:
<&|formatting.myt:code, syntaxtype=None&> python ./run_server.py &>and point a web browser to http://localhost:8080/index.myt. The data directory ./cache will be automatically created to store data files.
Other examples of the Standalone handler are available in examples/shoppingcart/run_cart.py for a straightforward example, or tools/run_docs.py for an advanced example that also makes use of custom resolution strategies.
&> <&|doclib.myt:item, name="cgi", description="CGI", &>Serving Myghty template files directly via CGI can be achieved with the <&|formatting.myt:codeline&>myghty.cgi&> utility located in the <&|formatting.myt:codeline&>/tools&> directory. This program is a simple interface to the <&|formatting.myt:codeline&>CGIHandler&>, which converts the "path-info" of the requested URI into a Myghty component call. The script's configuration information is present within the top half of the script itself, to allow the most straightforward configuration, although it could certainly be modified to load configuration information from any other source such as other Python modules or configuration files.
It requires configuration of the component root, data directory, and optionally additional Python libraries to run. Other configuration parameters can be added to the handle() call as well. The cgi handler will handle requests of the form:
<&|formatting.myt:codeline&><% "http://
The script is below. Modify the appropriate lines and copy the myghty.cgi program into your webserver's cgi-bin directory for a basic cgi-based template handler. For usage within custom CGI scripts, see the next section detailing programmatic methods of calling Myghty.
<&|formatting.myt:code, syntaxtype="python" &> #!/usr/local/bin/python # myghty cgi runner. place in cgi-bin directory and address Myghty templates # with URLs in the form: # http://mysite.com/cgi-bin/myghty.cgi/path/to/template.myt # component root. this is where the Myghty templates are. component_root = '/path/to/croot' # data directory. this is where Myghty puts its object files. data_dir = '/path/to/datadir' # libraries. Put paths to additional custom Python libraries here. lib = ['/path/to/custom/libraries'] import sys [sys.path.append(path) for path in lib] import myghty.http.CGIHandler as handler handler.handle(component_root=component_root, data_dir=data_dir) &> &> <&|doclib.myt:item, name="mod_python", description="mod_python", &>This section assumes familiarity with basic Apache configuration. Myghty includes a handler known as myghty.http.ApacheHandler which can interpret requests from the mod_python request object. This handler can be configured directly within the httpd.conf file of Apache, using regular Apache configuration file directives to configure its options. Alternatively, the ApacheHandler can be used within an external Python module that defines its own mod_python handler, which allows most of the configuration of the handler to be stated within a Python file instead of the httpd.conf file. The first method, described in this section, is expedient for a straightforward Myghty template service, or a simple view-controller setup. While the full range of configurational options can be present directly in http.conf stated as Apache configuration directives, including Python imports, functions, and datastructures, the syntax of embedding Python into conf directives can quickly become burdensome when configuring an application with a complex resolution stream. Therefore it is recommended that Apache users also become familiar with programmatic configuration, described in the section <&formatting.myt:link, path="configuration_programmatic_httphandler_ApacheHandler"&>.
Myghty configuration parameters are written in the Apache httpd.conf file as "Myghty" plus the parameter name in InitialCaps. The full range of configuration parameters in <&formatting.myt:link, path="params" &> may be used. The values (right-hand side of the configuration directive) are Python evaluable expressions. In the simplest case, this is just a string, which is mostly easily identified as <% 'r"
Below is a straightforward example that routes all Apache requests for files with the extension ".myt" to the Myghty ApacheHandler:
<&|formatting.myt:code, syntaxtype="conf" &> # associate .myt files with mod_python # mod_python 3.1 uses 'mod_python' AddHandler mod_python .myt # or for mod_python 2.7 use 'python-program' # AddHandler python-program .myt # set the handler called by mod_python to be the Myghty ApacheHandler PythonHandler myghty.ApacheHandler::handle # set python library paths - this line is used to indicate # additional user-defined library paths. this path is not required for the # Myghty templates themselves. PythonPath "sys.path+[r'/path/to/my/libraries']" # set component root. # for this example, an incoming URL of http://mysite.com/files/myfile.myt # will be resolved as: /path/to/htdocs/files/myfile.myt PythonOption MyghtyComponentRoot r"/path/to/htdocs" # data directory where myghty will write its object files, # as well as session, cache, and lock files PythonOption MyghtyDataDir r"/path/to/writeable/data/directory/" # other options - simply write as 'Myghty' with the param name in # InitialCaps format, values should be legal python expressions # watch out for using quotes "" as apache.conf removes them - # use r"value" or '"value"' instead PythonOption MyghtyWhen this is done, requests to Apache which refer to pages with the extension .myt will be routed to the ApacheHandler, which will resolve the filename into a component which is then executed.
An additional format for the "MyghtyComponentRoot" parameter, a list of multiple paths, can be specified as a list of dictionaries. An example: <&|formatting.myt:code, syntaxtype="conf"&> # Multiple Roots, each has a key to identify it, # and their ordering determines their precedence PythonOption MyghtyComponentRoot <% "\\" %> "[ <% "\\" %> {'components':'/optional/path/to/components'}, <% "\\" %> {'main':'/path/to/htdocs/htdocs'} <% "\\" %> ]" &>
Keep in mind that the MyghtyComponentRoot parameter (normally called component_root) defines filesystem paths that have no relationship to Apache DocumentRoots. From the perspective of Apache, there is only a single mod_python handler being invoked, and it has no awareness of the component_root. This means that any incoming URL which matches the Myghty handler will be matched to a root in the component_root and served as a Myghty template, effectively allowing "access" to files that are not directly access-controlled by Apache. To restrict direct access to Myghty component files which are meant for internal use, an alternate file extension, such as ".myc" can be used, so that while a Myghty component can internally find those files within the component_root, the Apache server has no knowledge of the .myc extension and they are not served. This also requires that the .myc files are kept in a directory or directories separate from any configured Apache DocuementRoots.
Myghty also has the ability to handle directory requests and requests for nonexistent files via various mechanisms, including <&formatting.myt:link, path="specialtempl_dhandler"&> and <&formatting.myt:link, path="modulecomponents"&>. However, the example above is configured to only respond to URLs with the specific file extension of ".myt". To handle directory requests without a filename being present, or requests for many different file extensions at once, replace the usage of <&|formatting.myt:codeline&>AddHandler&> with the Apache <&|formatting.myt:codeline&>SetHandler&> directive combined with the <% "
The above MyghtyModuleComponents, the apache version of <&formatting.myt:link, path="parameters", param="module_components"&>, is just one way to serve module components; there is also <&formatting.myt:link, path="parameters", param="module_root"&>, as well as the Routes resolver.
When serving all files within a directory, one should take care that Myghty is not be used to handle binary files, such as images. Also, it might be inappropriate to serve other kinds of text files such as stylesheets (.css files) and javascript files (.js files), even though one could use Myghty templating to serve these. To get around these issues, when straight file-extension matching is not enough, the Myghty and non-Myghty files can be placed in different directories and Apache correspondingly configured to enable Python handling in the Myghty directory only.
<&|doclib.myt:item, name="multiple", description="Advanced mod_python Configuration - Multiple ApacheHandlers", &>Several Interpreters can be configured with their own set of configuration parameters and executed all within the same Python interpreter instance, through the use of the <&formatting.myt:link, path="parameters", param="interpreter_name"&> configuration parameter.
In the example below, a site configures three main dynamic areas: a documentation section, a catalog section, and the default section for all requests that do not correspond to the previous two. It uses three ApacheHandlers each with different component_root configuration parameters, but they share a common data_dir. The handlers are each configured inside a <% "
Configuring component roots and path translation based on the incoming URI can also be accomplished within the scope of a single Interpreter by defining a custom set of resolver rules. This technique is described in <& formatting.myt:link, path="resolver" &>.
&> &> &> myghty-1.1/doc/components/doclib.myt 0000644 0001750 0001750 00000010206 10501064114 016602 0 ustar malex malex <%python scope="global"> import sys, string, re # datastructure that will store the whole contents of the documentation class TOCElement: def __init__(self, filename, name, description, parent = None, ext = None, header = None, last_updated = 0): self.filename = filename self.name = name self.parent = parent self.path = self._create_path() self.header = header if self.parent is not None: self.root = parent.root self.root.pathlookup[self.path] = self if self.parent.filename != self.filename: self.root.filelookup[self.filename] = self self.isTop = True else: self.root = self self.pathlookup = {} self.pathlookup[''] = self self.filelookup = {} self.filelookup[filename] = self if ext is not None: self.ext = ext else: self.ext = self.root.ext self.last_updated = last_updated self.description = description self.content = None self.previous = None self.next = None self.children = [] if parent: if len(parent.children): self.previous = parent.children[-1] parent.children[-1].next = self parent.children.append(self) if last_updated > parent.last_updated: parent.last_updated = self.last_updated def get_file(self, name): name = re.sub("\.\w+$", "", name) return self.root.filelookup[name] def lookup(self, path): return self.root.pathlookup[path] def get_link(self, includefile = True, anchor = True): if includefile: if anchor: return "%s%s#%s" % (self.filename, self.ext, self.path) else: return "%s%s" % (self.filename, self.ext) else: if anchor: return "#" + self.path else: return "" def _create_path(self): elem = self tokens = [] while elem.parent is not None: tokens.insert(0, elem.name) elem = elem.parent path = string.join(tokens, '_') return path %python> <%python scope="request"> current = Value() filename = Value() %python> <%args scope="request"> paged = 'yes' %args> <%python scope="init"> try: a = r isdynamic = True ext = ".myt" except: isdynamic = False ext = ".html" request_comp = m.request_comp() if isdynamic and not m.interpreter.attributes.get('docs_static_cache', False): page_cache = True else: page_cache = False # for dynamic page, cache the output of the final page if page_cache: if m.cache_self(key="doc_%s" % paged, component = request_comp): return list_comp = m.fetch_next() files = request_comp.attributes['files'] title = request_comp.attributes.setdefault('title', "Documentation") version = request_comp.attributes['version'] wrapper = request_comp.attributes['wrapper'] index = request_comp.attributes['index'] onepage = request_comp.attributes['onepage'] def buildtoc(): root = TOCElement("", "root", "root element", ext = ext) current.assign(root) for file in files: filename.assign(file) comp = m.fetch_component(file + ".myt") main = m.scomp(comp) return root if not page_cache: # non-dynamic (i.e. command-line) page, cache the datastructure so successive # pages are fast (disables auto-recompiling) cache = m.get_cache(list_comp) toc = cache.get_value('toc', createfunc = buildtoc) else: toc = buildtoc() last_updated = toc.last_updated m.comp(wrapper, isdynamic=isdynamic, ext = ext, toc = toc, comp = request_comp, onepage = onepage, paged = paged, title = title, version = version, index=index, last_updated = last_updated) %python> <%method title> <% m.request_comp().get_attribute('title', inherit = True) or "Documentation" %> %method> <%method item> <%doc>stores an item in the table of contents%doc> <%args> # name should be a URL friendly name used for hyperlinking the section name # description is the heading for the item description escapedesc = False header = None %args> <%python scope="init"> if escapedesc: description = m.apply_escapes(description, ['h']) current(TOCElement(filename(), name, description, current(), header = header, last_updated = m.caller.component_source.last_modified)) current().content = m.content() current(current().parent) %python>%method> <%method current> <%init>return current()%init> %method> myghty-1.1/doc/components/formatting.myt 0000644 0001750 0001750 00000023153 10501064114 017525 0 ustar malex malex <%doc>formatting.myt - library of HTML formatting functions to operate on a TOCElement tree%doc> <%global> import string, re import highlight %global> <%def printtocelement> <%doc>prints a TOCElement as a table of contents item and prints its immediate child items%doc> <%args> item includefile bold = False full = False children = True %args> % if children:<% m.content() %>
', f, re.S) f = "
" + f + "
" return f %filter> <% m.content() | h%> %method> <%method itemlink trim="both"> <%args> item includefile %args> <% item.description %> %method> <%method codeline trim="both"> <% m.content() %> %method> <%method code autoflush=False> <%args> title = None syntaxtype = 'myghty' html_escape = True %args> <%init> def fix_indent(f): f =string.expandtabs(f, 4) g = '' lines = string.split(f, "\n") whitespace = None for line in lines: if whitespace is None: match = re.match(r"^([ ]*).+", line) if match is not None: whitespace = match.group(1) if whitespace is not None: line = re.sub(r"^%s" % whitespace, "", line) if whitespace is not None or re.search(r"\w", line) is not None: g += (line + "\n") return g.rstrip() content = highlight.highlight(fix_indent(m.content()), html_escape = html_escape, syntaxtype = syntaxtype) %init><% content %>
Myghty provides the ability to cache any kind of data, including component output, component return values, and user-defined data structures, for fast re-retrieval. All components, whether file-based or subcomponent, are provided with their own cache namespace, which in turn stores any number of key/value pairs. Included with Myghty are implementations using files, dbm files, direct in-memory dictionaries, and memcached. User-defined implementations are also supported and can be specified at runtime. The particular implementation used can optionally be specified on a per-key basis, so that any single namespace can store individual values across any number of implementations at the same time.
Caching is generally used when there are process-intensive and/or slow operations that must be performed to produce output, and those operations also have little or no dependencies on external arguments, i.e. their value is not likely to change in response to request variables. Examples of things that are good for caching include weather information, stock data, sports scores, news headlines, or anything other kind of data that can be expensive to retrieve and does not need to be updated with real-time frequency.
The front-end to the mechanism is provided by the <&|formatting.myt:codeline&>myghty.cache&> package, and can be configured and used through global configuration parameters, per-component flags, and a programmatic interface.
<&|doclib.myt:item, name="component", description="Caching a Component's Output"&>The simplest form of caching is the caching of a component's return value and output content via flags. An example using a subcomponent (subcomponents are explained in <& formatting.myt:link, path="components_subcomponent"&>):
<&|formatting.myt:code&><%text> <%def heavytext> <%flags> use_cache = True cache_type = 'dbm' cache_expiretime = 30 %flags> <%init> data = big_long_query() %init> Your big query returned: <% data.get_info() %> %def> %text>&>In this example, the component's output text and its return value (if any) will be stored the first time it is called. Any calls to this component within the next 30 seconds will automatically return the cached value, and the %init section and body will not be executed. At the moment 30 seconds have elapsed, the first call to occur within this new period will result in the component executing in full again and recreating its output text and return value. Subsequent calls that occur during this second execution will continue to return the prior value until the new value is complete. Once the new value is complete, it is stored in the cache and the expiration counter begins again, for the next 30 seconds.
Note that the parameter <&|formatting.myt:codeline&>cache_type&> is set to <&|formatting.myt:codeline&>'dbm'&>, which indicates that dbm-based caching is used. This is the default setting when a data_dir parameter is configured with the Myghty application.
For components that contain a %filter section, the result of filtering is stored in the cache as well. This allows the cache to be useful in limiting the execution of a process-intensive or time-consuming filtering function.
When a component is recompiled, its cache contents are automatically expired, so that the cache can be refreshed with the value returned by the newly modified component. This means it is safe to set a cache setting with no expire time at all for a component whose output never changes, and in fact such a component only executes once per compilation and never at all again, for the life of the cache.
&> <&|doclib.myt:item, name="interface", description="Programmatic Interface"&>The traditional caching interface looks like this: <&|formatting.myt:code&><%text> <%init> def create_data(): return get_some_data() cache = m.get_cache() data = cache.get_value('mydata', type='memory', createfunc=create_data, expiretime=60) %init> %text>&> Where "mydata" is a key that the data will be keyed upon, the type of cache is in memory only, the create_data() function is used to create the initial value of 'mydata' as well as regenerating it when it is expired, and the expire time is 60 seconds.
The creation function argument is optional, and the cache can be populated externally as well: <&|formatting.myt:code&><%text> <%init> cache = m.get_cache() if not cache.has_key('mydata'): cache.set_value('mydata', get_some_data(), expiretime=60) data = cache.get_value('mydata') %init> %text>&> This is a more familiar way to check a dictionary for a value and set it. However, the previous "creation function" methodology has a significant advantage, in that it allows the cache mechanism to execute the function in the context of a global "busy" lock, which prevents other processes and threads from executing the same function at the same time, and instead forces them to retrieve the previous expired value until the new value is completed. If no previous value exists, they all wait for the single process/thread to create the new value. For a creation function that is slow or uses a lot of resources, this limits those resources to only one concurrent usage at a time, and once a cache value exists, only one request will experience any slowness upon recreation.
To programmatically cache the output text of a component, use the <&|formatting.myt:codeline&>m.cache_self()&> method on request, which is a reentrant component-calling method: <&|formatting.myt:code&><%text> <%init> if m.cache_self(key="mykey"): return %init> # rest of component %text>&> For an uncached component, the cache_self method will execute the current component a second time. Upon the second execution, when the cache_self line is encountered the second time, it returns false and allows the component to complete its execution. The return value and output is cached, after being sent through any output filters present. Then returning up to the initial cache_self call, it returns true and delivers the components output and optionally its return value. Filtering is also disabled in the component as it should have already occurred within the original caching step. The process for an already cached component is that it simply returns true and delivers the component output.
To get the component's return value via this method: <&|formatting.myt:code&><%text> <%init> ret = Value() if m.cache_self(key="mykey", retval = ret): return ret() # rest of component return 3 + 5 %init> %text>&> A value object is used here to pass a return value via a method parameter. The return value is simply the cached return value of the component.
Generally, the %flags method of caching a component's output and return value is a lot easier than the programmatic interface. The main advantage of the programmatic interface is if the actual key is to be programmatically decided based on component arguments it can be figured out at runtime and sent as the "key" argument. This also applies if any of the other properties of the cache are to be determined at run-time rather than compile time.
&> <&|doclib.myt:item, name="details", description="More on Caching"&>The cached information may be shared within the scope of one process or across multiple processes. Synchronization mechanisms are used to insure that the regeneration is only called by one thread of one process at a time, returning the expired value to other processes and threads while the regeneration is occuring. This maximizes performance even for a very slow data-regeneration mechanism. In the case of a non-memory-based cache, an external process can also access the same cache.
Note that Myghty only includes thread-scoped synchronization for the Windows platform (contributors feel free to contribute a Win32 file locking scheme). The "file" and "dbm" cache methodologies therefore may not be entirely synchronized across multiple processes on Windows. This only occurs if multiple servers are running against the same cache since Windows doesnt have any forking capability and therefore an Apache server or similar is only using threads.
Caching has an assortment of container methodolgies, such as <&|formatting.myt:codeline&>MemoryContainer&> and <&|formatting.myt:codeline&>DBMContainer&>, and provides a base Container class that can be subclassed to add new methodologies. A single component's cache can have containers of any number of different types and configurations.
Caching of the URI resolution step can also be done to improve performance. See <&formatting.myt:link, path="parameters", param="use_static_source"&> for more information on using the URICache.
&> <&|doclib.myt:item, name="options", description="Cache Options"&>Caching options are all specified as Myghty configuration parameters in the form <&|formatting.myt:codeline&>cache_XXXX&>, to identify them as options being sent to the Cache object. When calling the m.get_cache() method, parameters may be specified with or without the cache_ prefix; they are stripped off. While some cache options apply to the Cache object itself, others apply to specific forms of the Container class, the two current classes being <&|formatting.myt:codeline&>MemoryContainer&> and <&|formatting.myt:codeline&>DBMContainer&>.
The full list of current options is as follows:
<&|formatting.myt:paramtable&> <&|formatting.myt:param, name="cache_container_class", classname="Cache", type="class object" , users =None&> This is a class object which is expected to be a subclass of <&|formatting.myt:codeline&>myghty.container.Container&>, which will be used to provide containment services. This option need only be used in the case of a user-defined container class that is not built into the static list of options in the Cache class. To use one of the built in container classes, use <&|formatting.myt:codeline&>cache_type&> instead. &> <&|formatting.myt:param, name="cache_data_dir", classname="DBMContainer", type="string", default="same as Interpreter data_dir", users=None &> This is the data directory to be used by the DBMContainer (file-based cache) to store its DBM files as well as its lockfiles. It is set by default to be the same as the data_dir parameter for the Myghty application. As it creates its own subdirectories for its files (as does Interpreter), the files are kept separate from Myghty compiled pages. &> <&|formatting.myt:param, name="cache_dbm_dir", classname="DBMContainer", type="string", default="cache_data_dir + '/container_dbm'", users=None &> This value indicates the directory in which to create the dbm files used by DBMContainer; if not present, defaults to a subdirectory beneath <&|formatting.myt:codeline&>cache_data_dir&>. &> <&|formatting.myt:param, name="cache_dbmmodule", classname="DBMContainer", type="module", default="anydbm", users=None &>DBMContainer uses dbm files via the Python built-in <&|formatting.myt:codeline&>anydbm&> module, which searches for a platform specific dbm module to use. Any Python dbm module can be specified here in place of it. To specify this option under mod_python as an Apache configuration directive, use this format:
<&|formatting.myt:code&><%text> PythonOption MyghtyCacheDbmmodule "__import__('gdbm')" %text>&> &> <&|formatting.myt:param, name="cache_debug_file", classname="Cache", type="file object", users=None &> If pointing to a Python file object, container operations performed by the caching system will be logged, allowing the viewing of how often data is being refreshed as well as how many concurrent threads and processes are hitting various containers. When running with ApacheHandler or CGIHandler, this parameter can be set to the standard Apache log via the parameter <&|formatting.myt:codeline&>log_cache_operations&>. &> <&|formatting.myt:param, name="cache_lock_dir", classname="DBMContainer", type="string", default="cache_data_dir + '/container_dbm_lock'", users=None &> This value indicates the directory in which to create the lock files used by DBMContainer; if not present, defaults to a subdirectory beneath <&|formatting.myt:codeline&>cache_data_dir&>. &> <&|formatting.myt:param, name="cache_url", classname="MemcachedNamespaceManager", type="string", default="None", users=None &> The memcached URL to connect to for memcached usage, e.g. "localhost:11211". &> <&|formatting.myt:param, name="cache_type", classname="Cache", type="module", users =None, default="file or memory" &>This is the type of container being used. Current options are <&|formatting.myt:codeline&>file&>, <&|formatting.myt:codeline&>dbm&>, <&|formatting.myt:codeline&>memory&>, and <&|formatting.myt:codeline&>ext:memcached&>.
This option defaults to <&|formatting.myt:codeline&>dbm&> if a <&|formatting.myt:codeline&>data_dir&> option is present in the current application, else uses <&|formatting.myt:codeline&>memory&>.
&> <&|formatting.myt:param, name="log_cache_operations", classname="ApacheHandler or CGIHandler", type="boolean", default="False", users=None &> Sets the Cache <&|formatting.myt:codeline&>cache_debug_file&> argument to point to the Apache error log or standard error output. See <&|formatting.myt:codeline&>cache_debug_file&>. &> &> &> <&|doclib.myt:item, name="types", description="Cache Types"&>All templates in Myghty are referred to as "Components". Components, while they may look like plain HTML pages with a few lines of Python in them, are actually callable units of code which have their own properties, attributes, input arguments, and return values. One can think of a Component anywhere within the spectrum between "HTML page" and "callable Python object", and use it in either way or a combination of both.
A single template, while it is a component itself, also can contain other components within it, which are referred to as "subcomponents", and a subcategory of subcomponents called "methods". The template's component itself is called a "file-based component", and when it is the main component referenced by a request it is also known as the "top level component".
When a component is instantiated within the runtime environment, it is a Python object with the usual reference to "self" as well as its own attributes and methods, and the body of the component occurs within a function call on that object. All components extend from the base class myghty.component.Component. File-based components extend from myghty.component.FileComponent and subcomponents extend from myghty.component.SubComponent.
Additionally, unique to Myghty is a non-template form of component called a "module component", which is written instead as a regular Python class. These components are described in the next section, <&formatting.myt:link,path="modulecomponents"&>, extending from the class myghty.component.ModuleComponent.
<&|doclib.myt:item, name="example", description="Component Calling Example", &>The most basic component operation is to have one template call another. In the simplest sense, this is just an HTML include, like a server side include. To have a template "page.myt" call upon another template "header.myt":
<&|formatting.myt:code, title="page.myt"&><%text> <& header.myt &> ... rest of page %text>&> <&|formatting.myt:code, title="header.myt"&><%text>Produces:
<&|formatting.myt:code, syntaxtype="html"&><%text>When calling components, the path to the component is given as an environment-specific URI, and not an actual filesystem path. While the path can be specified as absolute, it is still determined as relative to one or more of the configured Myghty component roots. Myghty uses the <&formatting.myt:link, path="parameters", param="component_root"&> parameter as a list of filesystem paths with which to search for the requested component. If a relative path is used, the path is converted to an absolute path based on its relation to the location of the calling component, and then matched up against the list of component roots.
&> <&|doclib.myt:item, name="args", description="Component Arguments - the <%args> tag", &>Components, since they are really Python functions, support argument lists. These arguments are supplied to the top-level component from the client request arguments, such as via a POST'ed form. When a component is called from another component, the calling component specifies its own local argument list to be sent to the called component.
A component can access all arguments that were sent to it by locating them in the ARGS dictionary. More commonly, it can specify a list of arguments it would like to receive as local variables via the <% "<%args>" %> tag:
<&|formatting.myt:code&><%text> <%args> username password # sessionid defaults to None sessionid = None %args> <%python scope="init"> if sessionid is None: sessionid = create_sid() if password != get_password(username): m.send_redirect("loginfailed.myt", hard=True) %python> %text>&>In the above example, the 'username' and 'password' arguments are required; if they are not present in the argument list sent to this component, an error will be raised. The 'sessionid' argument is given a default value, so it is not required in the argument list.
A component like the one above may be called with a URL such as:
<&|formatting.myt:code, syntaxtype=None&><%text> http://foo.bar.com/login.myt?username=john&password=foo&sessionid=57347438 %text>&>The values sent in an <% "<%args>" %> section are analgous to a Python function being called with named parameters. The above set of arguments, expressed as a Python function, looks like this:
<&|formatting.myt:code, syntaxtype="python"&><%text> def do_run_component(self, username, password, sessionid = None): %text>&>What this implies is that the default value sent for "sessionid" only takes effect within the body of the component. It does not set a default value for "sessionid" anywhere else. Different components could easily set different default values for "sessionid" and they would all take effect if "sessionid" is not present in the argument list.
Components can pass argument lists to other components when called. Below, a component 'showuser.myt' is called by another component 'page.myt':
<&|formatting.myt:code, title="showuser.myt"&><%text> <%args> username email %args> Username: <% username %>The component call tags "<% '<& &>' %>" take a named-parameter list just like a Python function, and can also have as the very last argument dictionary with ** notation just like in regular Python:
<&|formatting.myt:code&><%text> <& comp.myt, arg1=3.7, **ARGS &> %text>&>Above, the dictionary ARGS always has a list of all arguments sent to the component, regardless of whether or not they were specified in the <% "<%args>" %> section. This is a way of passing through "anonymous" arguments from a component's caller to its components being called.
<&|doclib.myt:item, name="argscope", description="Argument Scope: component/request/subrequest/dynamic", &>So far we have talked about "component-scoped" arguments, that is, the list of arguments that are sent directly to a component by its caller. While the very first component called in a request (i.e. the top-level component) will receive the client request arguments as its component-scoped arguments, any further component calls will only receive the arguments sent by its direct caller.
To make it easier for all components to see the original request arguments, the attribute scope="request" may be specified in any <% "<%args>" %> section to indicate that arguments should be taken from the original request, and not the immediate caller. Normally, the default value of scope is component, indicating that only the immediate component arguments should be used.
<&|formatting.myt:code&><%text> <%args scope="request"> sessionid %args> <%args scope="component"> username %args> hello <% username %>, to edit your preferences click here. %text>&>Above, the argument "sessionid" must be sent by client request, but the argument "username" must be sent by the calling component. If this component is called as the top-level component, both arguments must be present in the client request.
Request arguments are also always available via the <&formatting.myt:link, path="request_members", member="request_args"&> and <&formatting.myt:link, path="request_members", member="root_request_args"&> members of the request object.
Note that there is special behavior associated with request-scoped arguments when using subrequests (described later in this section). Since a subrequest is a "request within a request", it is not clear whether the "request" arguments should come from the originating request, or the immediate, "child" request. The attribute scope="subrequest" indicates that arguments should be located in the immediate request, whether or not it is a subrequest, in contrast to scope="request" which always refers to the arguments of the ultimate root request. Subrequests are described in the section <&formatting.myt:link, path="components_programmatic_subrequests"&> below.
The component that wants to be flexible about its arguments may also specify its arguments with "dynamic" scope. In dynamic scope, the argument is located within the most local arguments first, and then upwards towards the request until found. The following component will retrieve its arguments locally if present, or if not, from the request, no matter where it is called:
<&|formatting.myt:code&><%text> <%args scope="dynamic"> username email %args> hello <% username %>, your email address is <% email %>. %text>&> &> &> <&|doclib.myt:item, name="subcomponent", description="How to Define a Subcomponent", &>A subcomponent is a component defined within a larger template, and acts as a callable "subsection" of that page. Subcomponents support almost all the functionality of a file-based component, allowing Python blocks of init, cleanup and component scope, but not global, request or thread scope.
A subcomponent, albeit a nonsensical one, looks like this:
<&|formatting.myt:code&><%text> <%def mycomponent> <%args> arg1 = 'foo' arg2 = 'bar' %args> <%python scope="init"> string = arg1 + " " + arg2 %python> i am mycomponent ! <% string %> %def> %text>&>A regular subcomponent like this one is always called by another component, i.e. it can never be called directly from the request as a top-level component. Furthermore, subcomponents defined with the <% "<%def>" %> tag are private to the template file they appear in.
The subcomponent has access to all global variables, such as m and r, but it does not have access to the local variables of its containing component. This would include variables specified in the body of the main component, i.e. in init-, cleanup- and component-scoped <% "<%python>" %> blocks. Variables declared in global-, request- and thread-scoped <% "<%python>" %> blocks are available within subcomponents, subject to the restrictions on variables declared in those blocks. Variables declared within the body of a subcomponent remain local to that subcomponent.
<&|doclib.myt:item, name="calling", description="Calling a Subcomponent", &>Subcomponents are called in a similar manner as a file-based component:
<&|formatting.myt:code&><%text> welcome to <& title, username='john' &> <%def title> <%args> username %args> bling bling bling <% username %> bling bling bling %text>&>Note that a subcomponent can be defined at any point in a template and is still available throughout the entire template.
&> &> <&|doclib.myt:item, name="method", description="How to Define a Method", &>A method is similar to a subcomponent, except its functionality is available outside of the file it appears in, and it can take advantage of inheritance from other template files.
<&|formatting.myt:code&><%text> <%method imamethod> <%args> radius coeffiecient = .5424 %args> <%python scope="init"> foob = call_my_func(radius, coefficient) %python> fractional fizzywhatsle: <% foob %> %method> %text>&> <&|doclib.myt:item, name="calling", description="Calling a Method", &>A method can be called from within the file it appears in the same fashion as a subcomponent, i.e. simply by its name, in which case it is located in the same way as a subcomponent. The other format of method calling is <% "
With the compound method calling format, if the method is not located in the specified component, the component's inherited parent will be searched, and in turn that component's inherited parent, etc., until no more parents exist. The parent-child relationship of components, as well as the keywords SELF, REQUEST, and PARENT are described in the section <&formatting.myt:link, path="inheritance"&>.
&> &> <&|doclib.myt:item, name="closure", description="How to Define a Closure", &> Version 0.98 introduces a lightweight alternative to %def and %method called <% "<%closure>" %>. This tag defines a local function definition using Python keyword def, which is callable via the same mechanism as that of subcomponents. A closure is in fact not a component at all and can only be used within the block that it is defined, and also must be defined before it is called. It offers the advantage that it is created within the scope of the current code body, and therefore has access to the same variable namespace: <&|formatting.myt:code&><%text> <%closure format_x> <%args> format = '%d' %args> <% format % x %> %closure> % for x in (1,2,3): <& format_x, format='X:%d' &> % %text>&>Closures support the <% "<%args>" | h%> tag, as well as <&formatting.myt:link, path="scopedpython_init" &> and <& formatting.myt:link, path="scopedpython_cleanup" &>. Closures can also be nested. They currently do not support the "component call with content" calling style but this may be added in the future.
&> <&|doclib.myt:item, name="flags", description="Subcomponent Flags", &>Subcomponents and methods also may specify flags as described in the section <&formatting.myt:link, path="otherblocks_flags"&>. The most useful flags for a subcomponent are the <&|formatting.myt:codeline&>trim&> and <&|formatting.myt:codeline&>autoflush&> flags, described in <&formatting.myt:link, path="filtering"&>.
There are two formats for specifing flags in a subcomponent:
<&|formatting.myt:code&><%text> # traditional way <%def buffered> <%flags> autoflush=False %flags> this is a buffered component %def> # inline-attribute way <%method hyperlink trim="both"> <%args> link name %args> name %method> %text>&> &> <&|doclib.myt:item, name="callwithcontent", description="Component Calls with Content", &>Subcomponents and methods can also be called with a slightly different syntax, in a way that allows the calling component to specify a contained section of content to be made available to the called component as a Python function. Any subcomponent can query the global m object for a function that executes this content, if it is present. When the function is called, the code sent within the body of the component call with content is executed; this contained code executes within the context and namespace of the calling component.
<&|formatting.myt:code&><%text> <&| printme &> i am content that will be grabbed by PRINTME. &> %text>&>The called component can then reference the contained content like this:
<&|formatting.myt:code&><%text> <%def printme> I am PRINTME, what do you have to say ?The method <&|formatting.myt:codeline&>m.content()&> executes the code contained within the <% "<&| &>/&> " | h%> tags in its call to "printme", and returns it as a string. A component may query the request object m for the presense of this function via the method <&|formatting.myt:codeline&>m.has_content()&>.
A component call with content is one of the most powerful features of Myghty, allowing the creation of custom tags that can produce conditional sections, iterated sections, content-grabbing, and many other features. It is similar but not quite the same as the template inheritance methodology, in that it allows the body of a component to be distilled into a callable function passed to an enclosing component, but it involves a client explicitly opting to wrap part of itself in the body of another component call, rather than a client implicitly opting to wrap its entire self in the body of another component call.
&> <&|doclib.myt:item, name="programmatic", description="Calling Components Programmatically", &>The special component calling tags described above are just one way to call components. They can also be called directly off of the request object m, which is handy both for calling components within %python blocks as well as for capturing either the return value or the resulting content of a subcomponent. Component objects can also be directly referenced and executed via these methods.
The full index of request methods and members can be found in <&formatting.myt:link, path="request" &>.
<&|doclib.myt:item, name="comp", description="m.comp(component, **params)", &>This method allows you to call a component just like in the regular way except via Python code. The arguments are specified in the same way to the function's argument list. The output will be streamed to the component's output stream just like any other content. If the component specifies a return value, it will be returned. A component, since it is really just a python function, can have a return value simply by using the python statement <&|formatting.myt:codeline&>return&>. The value of component can be an actual component object obtained via <&|formatting.myt:codeline&>fetch_component()&>, or a string specifying a filesystem path or local subcomponent or method location.
<&|formatting.myt:code&><%text> <%python> m.comp('/foo/bar.myt', arg1='hi') %python> %text>&> &> <&|doclib.myt:item, name="scomp", description="m.scomp(component, **params)", &>This method is the same as "comp" except the output of the component is captured in a separate buffer and returned as the return value of scomp().
<&|formatting.myt:code&><%text> <%python> component = m.fetch_component('mycomponent') content = m.scomp(component) m.write("" + content + "") %python> %text>&> &> <&|doclib.myt:item, name="subrequests", description="Subrequests", &>
A subrequest is an additional twist on calling a component, it calls the component with its own request object that is created from the current request. A subrequest is similar to an internal redirect which returns control back to the calling page. The subrequest has its own local argument list as well, separate from the original request arguments.
<&|formatting.myt:code&><%text> <%python> ret = m.subexec('/my/new/component.myt', arg1='hi') %python> %text>&>The subexec method takes either a string URI or a component object as its first argument, and the rest of the named parameters are sent as arguments to the component.
Use subrequests to call a component when you want its full inheritance chain, i.e. its autohandlers, to be called as well.
The subexec method is comprised of several more fine-grained methods as illustrated in this example:
<&|formatting.myt:code&><%text> <%python> # get a component to call component = m.fetch_component('mysubreq.myt') # make_subrequest - # first argument is the component or component URI, # following arguments are component arguments subreq = m.make_subrequest(component, arg1 = 'foo') # execute the request. return value is sent ret = subreq.execute() %python> %text>&>The make_subrequest method can also be called as create_subrequest, which in addition to supporting component arguments, lets you specify all other request object arguments as well: <&|formatting.myt:code&><%text> <%python> import StringIO # get a component to call component = m.fetch_component('mysubreq.myt') # make a subrequest with our own # output buffer specified buf = StringIO.StringIO() subreq = m.create_subrequest(component, out_buffer = buf, request_args = {'arg1':'foo'}, ) # execute the request. # return value is sent, our own buffer # is populated with the component's # content output ret = subreq.execute() %python> %text>&> &> <&|doclib.myt:item, name="callself", description="call_self(buffer, retval)", &>
The "call_self" method is provided so that a component may call itself and receive its own content in a buffer as well as its return value. "call_self" is an exotic way of having a component filter its own results, and is also the underlying method by which component caching operates. Note that for normal filtering of a component's results, Myghty provides a full set of methods described in the section <&formatting.myt:link, path="filtering_filtering"&>, so call_self should not generally be needed.
call_self uses a "reentrant" methodology, like this:
<&|formatting.myt:code&><%text> <%python scope="init"> import StringIO # value object to store the return value ret = Value() # buffer to store the component output buffer = StringIO.StringIO() if m.call_self(buffer, ret): m.write("woop! call self !" + buffer.getvalue() + " and we're done") return ret() # ... rest of component %python> %text>&>The initial call to call_self will return True, indicating that the component has been called and its output and return value captured, at which point the component should return. Within the call_self call, the component is executed again; call_self returns False to indicate that the thread of execution is "inside" of the initial call_self and that content is being captured.
It is recommended that call_self be called only in an init-scoped Python block before any other content has been written, else that content will be printed to the output as well as captured.
&> &> <&|doclib.myt:item, name="methods", description="Component Methods", &>Instances of Component objects can be accessed many ways from the request object, including the <&formatting.myt:link, path="request_methods", method="fetch_component"&> method, and the <&formatting.myt:link, path="request_members", method="current_component"&>, <&formatting.myt:link, path="request_members", method="request_component"&>, and <&formatting.myt:link, path="request_members", method="base_component"&> members. The <&formatting.myt:link, path="request_methods", method="fetch_next"&> method returns the next component in an inheritance chain. Finally, <&|formatting.myt:codeline&>self&> refers to the current component.
The methods available directly from <&|formatting.myt:codeline&>Component&> are listed below, followed by the members.
<&|formatting.myt:paramtable&> <&|formatting.myt:function_doc, name="call_method", arglist=['methodname', '**params']&>Calls a method on the current component, and returns its return value. This method is shorthand for locating the current request via <&|formatting.myt:codeline&>request.instance()&>, locating the method via <&|formatting.myt:codeline&>locate_inherited_method()&> and calling <&|formatting.myt:codeline&>m.comp()&>.
&> <&|formatting.myt:function_doc, name="get_flag", arglist=["key", "inherit=False"]&>Returns the value of a flag for this component. If "inherit" is True, the value of the flag will be searched for in the chain of parent components, if it is not found locally.
&> <&|formatting.myt:function_doc, name="get_sub_component", arglist=['name']&>Returns the subcomponent denoted by name. For a subcomponent or method, returns the subcomponent of the owning (file-based) component. Note this is not for methods; for those, use locate_inherited_method.
&> <&|formatting.myt:function_doc, name="has_filter", arglist=[]&>Returns true if this component has a filter section, and or a "trim" flag.
&> <&|formatting.myt:function_doc, name="locate_inherited_method", arglist=['name']&>Returns the method component associated with name. The method is searched for in the current component and up the inheritance chain. For a subcomponent or method, returns the method of the owning (file-based) component. Note this is not for non-method subcomponents; for those, use get_sub_component(). &> <&|formatting.myt:function_doc, name="scall_method", arglist=['methodname', '**params']&>
Calls a method on the current component, captures its content and returns its content as a string. This method is shorthand for locating the current request via <&|formatting.myt:codeline&>request.instance()&>, locating the method via <&|formatting.myt:codeline&>locate_inherited_method()&> and calling <&|formatting.myt:codeline&>m.scomp()&>.
&> <&|formatting.myt:function_doc, name="use_auto_flush", arglist=[]&>Returns True or False if this component requires autoflush be turned on or off for its execution, or returns None if no requirement is set. This method searches within the current components flags, or within parent component flags if not present.
&> &> &> <&|doclib.myt:item, name="members", description="Component Members", &> <&|formatting.myt:paramtable&> <&|formatting.myt:member_doc, name="args"&> A list of argument names, corresponding to variable names in the component-scoped <% "<%args>" %> section, which have a default value specified. &> <&|formatting.myt:member_doc, name="attr"&> A dictionary of component attributes, corresponding to those set by the <% "<%attr>" %> tag. The attributes can be set at once by assigning a dictionary to this member. However, to set and retrieve individual attributes, it is best to use the special <&formatting.myt:link, member="attributes"&> member which takes advantage of inheritance. &> <&|formatting.myt:member_doc, name="attributes"&> A dictionary accessor for the <&formatting.myt:link, member="attr"&> dictionary member that locates its members first in the local component attributes, then searches up the inheritance chain for the attribute. &> <&|formatting.myt:member_doc, name="dir_name"&>The web-specific directory name where the current component resides, i.e. for this component its "<% self.dir_name %>". For a subcomponent or method, it is the directory name of the owning (file-based) component.
&> <&|formatting.myt:member_doc, name="file"&>The actual filesystem location of a component, for a component that was loaded directly from a Myghty template file, else it is None.
&> <&|formatting.myt:member_doc, name="filter"&>Reference to the function that will perform filtering on the component. This filter is directly stated in the <% "<%filter>" %> section described in <&formatting.myt:link, path="filtering_filtering_filter"&>.
&> <&|formatting.myt:member_doc, name="flags"&> Dictionary of flags for this component. Also can be accessed via the <&formatting.myt:link, path="components_programmatic_methods", method="get_flag"&> method. &> <&|formatting.myt:member_doc, name="id" &>A unique identifier for the current component, which is comprised of the key name for its component root joined with its web-specific path, i.e. for this component its "<% self.id %>". &> <&|formatting.myt:member_doc, name="is_file_component", arglist=[]&>
True if this component is a file based component.
&> <&|formatting.myt:member_doc, name="is_method_component", arglist=[]&>True if this component is a method component.
&> <&|formatting.myt:member_doc, name="is_module_component", arglist=[]&>True if this component is a module component.
&> <&|formatting.myt:member_doc, name="is_sub_component", arglist=[]&>True if this component is a subcomponent or method component.
&> <&|formatting.myt:member_doc, name="name", &>The filename or name of the current component, i.e. for this component its "<% self.name %>". &> <&|formatting.myt:member_doc, name="owner"&>
For a subcomponent or method subcomponent, the owning file-based component, otherwise it is self.
&> <&|formatting.myt:member_doc, name="parent_component"&>For a component in an inheritance chain (i.e. via %flags or via autohandlers), the inheriting component. For a subcomponent or method, returns the parent of the owning (file-based) component. Inheritance is described in <&formatting.myt:link, path="inheritance"&>.
&> <&|formatting.myt:member_doc, name="path"&>The URI corresponding to the component. For this component its "<% self.path %>". For a subcomponent or method, it is the URI of the owning (file-based) component.
&> <&|formatting.myt:member_doc, name="request_args"&> A list of argument names, corresponding to variable names in the request-scoped <% '<%args scope="request">' %> section, which do have a default value specified. &> <&|formatting.myt:member_doc, name="required_args"&> A list of argument names, corresponding to variable names in the component-scoped <% '<%args>' %> section, which do not have a default value specified., i.e. they are required component arguments. &> <&|formatting.myt:member_doc, name="required_request_args"&> A list of argument names, corresponding to variable names in the request-scoped <% '<%args scope="request">' %> section, which do not have a default value specified, i.e. are required request arguments. &> <&|formatting.myt:member_doc, name="required_subrequest_args"&> A list of argument names, corresponding to variable names in the subrequest-scoped <% '<%args scope="subrequest">' %> section, which do not have a default value specified, i.e. are required subrequest arguments. &> <&|formatting.myt:member_doc, name="subrequest_args"&> A list of argument names, corresponding to variable names in the subrequest-scoped <% '<%args scope="subrequest">' %> section, which do have a default value specified. &> &> &> &> myghty-1.1/doc/content/docstrings.myt 0000644 0001750 0001750 00000001253 10501064115 017015 0 ustar malex malex <%flags>inherit='document_base.myt'%flags> <%attr>title='Modules and Classes'%attr> <&|doclib.myt:item, name="docstrings", description="Modules and Classes" &> <%init> import myghty.interp as interp import myghty.request as request import myghty.resolver as resolver import myghty.csource as csource import myghty.component as component import myghty.session as session import myghty.container as container %init> <& pydoc.myt:obj_doc, obj=request &> <& pydoc.myt:obj_doc, obj=component &> <& pydoc.myt:obj_doc, obj=interp &> <& pydoc.myt:obj_doc, obj=resolver &> <& pydoc.myt:obj_doc, obj=csource &> <& pydoc.myt:obj_doc, obj=session &> &> myghty-1.1/doc/content/document_base.myt 0000644 0001750 0001750 00000001320 10501064115 017441 0 ustar malex malex <%flags>inherit="doclib.myt"%flags> <%python scope="global"> files = [ 'whatsitdo', 'installation', 'configuration', 'programmatic', 'embedding', 'scopedpython', 'globals', 'components', 'modulecomponents', 'request', 'otherblocks', 'inheritance', 'specialtempl', 'filtering', 'session', 'cache', 'resolver', 'unicode', 'params', 'technical', 'docstrings' ] %python> <%attr> files=files wrapper='section_wrapper.myt' onepage='documentation' index='index' title='Myghty Documentation' version = '1.1' %attr> myghty-1.1/doc/content/embedding.myt 0000644 0001750 0001750 00000020005 10501064115 016550 0 ustar malex malex <%flags>inherit='document_base.myt'%flags> <&|doclib.myt:item, name="embedding", description="Embedding Python in HTML", header="The Myghty Environment" &>A Myghty file usually is laid out as an HTML file, or other text file, containing specialized tags that are recognized by the Myghty page compiler. When compiled, the file is converted into a python module which is then executed as regular python code. A Myghty template in its compiled form is typically referred to as a component. A component can also contain one or more subcomponents and/or methods, which are described further in the section <&formatting.myt:link, path="components", text="Components"&>. Basically when we say "component" we are talking about a self contained unit of Myghty templating code. The term "top level component" refers to the outermost component within a request, which is the page itself being executed. The term "file based component" refers to a component corresponding to the file that it appears in.
<&|doclib.myt:item, name="control", description="Control Lines", &>Control lines look like this:
<&|formatting.myt:code &> <%text> % for x in range(0, 10): hello!The percent sign must be the very first character on the line, and the rest of the text is interpreted directly as Python code. The whitespace of the line, as well as the presence of a colon at the end of the line, is significant in determining the indentation of subsequent, non-control lines. As in the example above, the "for" statement followed by a colon, sets the indentation to be one level deeper, which causes the html text "hello!" to be iterated within the block created by the Python statement. The block is then closed by placing another control line, containing only whitespace plus an optional comment.
A more involved example:
<&|formatting.myt:code &><%text> % for mood in ['happy', 'happy', 'sad', 'sad', 'happy']: % if mood == 'happy':Note that the whitespace is not significant in plain HTML or text lines. When this template is converted to Python code, the plain text will be embedded in <&|formatting.myt:codeline&>write&> statements that are indented properly within the block. Block-closing statements like "else:" and "except:" are also properly interpreted.
&> <&|doclib.myt:item, name="comment", description="Comment Lines", &>Note that a blank control line, i.e. starting with '%', is significant in affecting the whitespace indentation level, whether or not it contains a comment character '#' followed by a comment. To do line-based comments without affecting whitespace, use '#' as the very first character on a line:
<&|formatting.myt:code &><%text> % for x in (1,2,3): hi <% x %> # a comment % # a block-closing control line %text>&>Comments can also be done with the <% "<%doc>" %> tag described in <&formatting.myt:link, path="otherblocks_doc" &>.
&> <&|doclib.myt:item, name="substitutions", description="Substitutions", &>A substitution is an embedded python expression, whos evaluated value will be sent to the output stream of the component via a <&|formatting.myt:codeline&>m.write()&> statement:
<&|formatting.myt:code &><%TEXT> Three plus five is: <% 3 + 5 %> %TEXT>&>produces:
<&|formatting.myt:code &><%TEXT> Three plus five is: 8 %TEXT>&>Substitutions can also span multiple lines which is handy in conjunction with triple-quoted blocks.
The text of substitutions can also be HTML or URL escaped via the use of flags. For a description of escape flags, see the section <&formatting.myt:link, path="filtering_escaping"&>.
&> <&|doclib.myt:item, name="blocks", description="Python Blocks", &>A python block is a block of pure python code:
<&|formatting.myt:code &><%text> <%python> user = usermanager.get_user() m.write("username is %s" % user.get_name()) %python> %text>&>Code within a %python block is inserted directly into the component's generated Python code, with its whitespace normalized to that of the most recent control line. The %python tags, as well as the code within the tags, can be at any indentation level in relation to the rest of the document, including other %python blocks; it is only necessary that the indentation of the code within the block is internally consistent with itself. See the next section for an example.
There are also variations upon the %python block, where the contained Python code is executed within a specific context of a component's execution, such as initialization, cleanup, or global. These special variations are explained in <&formatting.myt:link, path="scopedpython"&>.
&> <&|doclib.myt:item, name="whitespace", description="Controlling Whitespace with the Backslash", &>To allow for finer control of the whitespace inherently generated by multiline HTML or Python control structures, the backslash character "\" can be used at the end of any line to suppress newline generation: <&|formatting.myt:code&><%text> \ % for x in (1,2,3): [<% x %>]\ % %text>&> Which will produce: <&|formatting.myt:code&><%text> [1][2][3] %text>&> &> <&|doclib.myt:item, name="indentation", description="Indentation Behavior", &>
The interaction of control lines, plain text, and python blocks is regulated by the Myghty engine to create an overall indentation scheme that is functional but also allows HTML and python blocks to be laid out with a high degree of freedom. The following example illustrates the indentation behavior:
<&|formatting.myt:code &><%text> <%python> forecasts = { 'monday':'stormy', 'tuesday':'sunny', 'wednesday':'sunny', 'thursday':'humid', 'friday':'tornado' } %python> % for day in ['monday', 'tuesday', 'wednesday', 'thursday', 'friday']: <%python> weather = forecasts[day] if weather == 'tornado': advice = "run for the hills !" elif weather == 'stormy': advice = "bring an umbrella" else: advice = "enjoy the day...." %python> Weather for <% day %>: <% forecasts[day] %> Advice: <% advice %> % # end for %text>&>The above block, when compiled, translates into the following Python code, that is then executed to produce the final output:
<&|formatting.myt:code, syntaxtype="python" &><%text> # BEGIN BLOCK body m.write(''' ''') # test.myt Line 1 forecasts = { 'monday':'stormy', 'tuesday':'sunny', 'wednesday':'sunny', 'thursday':'humid', 'friday':'tornado' } # test.myt Line 11 m.write(''' ''') for day in ['monday', 'tuesday', 'wednesday', 'thursday', 'friday']: # test.myt Line 13 m.write(''' ''') # test.myt Line 14 weather = forecasts[day] if weather == 'tornado': advice = "run for the hills !" elif weather == 'stormy': advice = "bring an umbrella" else: advice = "enjoy the day...." # test.myt Line 24 m.write(''' Weather for ''') m.write( day ) m.write(''': ''') m.write( forecasts[day] ) m.write(''' Advice: ''') # test.myt Line 26 m.write( advice ) m.write(''' ''') # test.myt Line 28 # end for # END BLOCK body %text>&> &> &> myghty-1.1/doc/content/filtering.myt 0000644 0001750 0001750 00000041533 10501064115 016626 0 ustar malex malex <%flags>inherit='document_base.myt'%flags> <&|doclib.myt:item, name="filtering", description="Filtering and Flushing (and Escaping)", escapedesc=True, header="Additional Features" &>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 autoflush. 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 filtering. Autoflushing and filtering have some dependencies on each other, so they are described together.
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 escapes, described at the end of the section.
<&|doclib.myt:item, name="autoflush", description="The Autoflush Option", escapedesc=True &>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.
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.
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.
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.
But, here you are and you want to turn <&|formatting.myt:codeline&>autoflush&> on. To set it across an entire application, specify autoflush=True to the Interpreter or HTTPHandler being used. Or to configure via http.conf with mod_python:
<&|formatting.myt:code&> PythonOption MyghtyAutoflush True &>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>&>
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.
The ultimate autoflush 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.
So any page can control its own autoflush behavior as follows:
<&|formatting.myt:code&><%text> <%flags>autoflush=False%flags> ... %text>&> <&|doclib.myt:item, name="subcomponents", description="Setting Autoflush in Subcomponents" &>Subcomponent or methods can determine their autoflush behavior as follows:
<&|formatting.myt:code&><%text> <%def mycomp> <%flags>autoflush=False%flags> ... stuff ... %def> %text>&>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.
&> <&|doclib.myt:item, name="autohandlers", description="Non-Buffered with Autohandlers", escapedesc=True &>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:
<&|formatting.myt:code, title="autohandler - autoflush enabled"&><%text> <%flags>autoflush=True%flags> % m.call_next() %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>&>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.
Solution One - Turn Autoflush On:
<&|formatting.myt:code, title="page.myt"&><%text> <%flags>autoflush=False%flags> <%python scope="init"> m.send_redirect("page2.myt", hard=True) %python> %text>&>This is the most general-purpose method, which just disables autoflush for just that one page.
Solution Two - Inherit from None
<&|formatting.myt:code, title="page.myt"&><%text> <%flags>inherit=None%flags> <%python scope="init"> m.send_redirect("page2.myt", hard=True) %python> %text>&>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 &>
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
%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 f which contains the content to be filtered; the function processes content and returns the new value.
Example:
<&|formatting.myt:code&><%text> <%filter> import re return re.sub(r"turkey", "penguin", f) %filter> dang those flyin turkeys ! %text>&>will produce:
<&|formatting.myt:code&> dang those flyin penguins ! &> &> <&|doclib.myt:item, name="escapefilter", description="Escaping Content in a Filter Section", escapedesc=True &>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.
This is a component that HTML escapes its output, i.e. replaces the special characters <% "&, <, and >" | h%> with entity reference encoding:
<&|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 &>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()&>.
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.
&> <&|doclib.myt:item, name="trim", description="Filtering Whitespace - the Trim Flag", escapedesc=True &>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:
<&|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 %> %def> %text>&>Output:
<&|formatting.myt:code &><%text> for more information, click here. %text>&><&|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.
&> &> <&|doclib.myt:item, name="escaping", description="Escaping Content", escapedesc=True &>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.
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.
<&|doclib.myt:item, name="substitutions", description="Escaping Substitutions", escapedesc=True &>Substitutions, first introduced in <&formatting.myt:link, path="embedding_substitutions"&>, can include escape flags, specified by the following notation:
<&|formatting.myt:code &><%text> <% "i am an argument" | u %> %text>&>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.
Multiple escape flags are separated by a comma:
<&|formatting.myt:code &><%text> <% "multiple escapes" | h, u %> %text>&>Which will HTML and URL escape the given string.
&> <&|doclib.myt:item, name="programmatic", description="Programmatic Escaping", escapedesc=True &>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.
In this example, a component receives the argument "text" and displays it in a textarea, where HTML escaping is required:
<&|formatting.myt:code&><%text> <%args> text %args> <%python> # HTML escape the given text text = m.apply_escapes(text, 'h') %python> %text>&>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 &>
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.
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 &>
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 all substitutions in an application.
When default escaping is used, the special flag "n" can be specified in the substitution to disable the default escape flags for that substitution.
&> &> &> myghty-1.1/doc/content/globals.myt 0000644 0001750 0001750 00000021004 10501064115 016255 0 ustar malex malex <%flags>inherit='document_base.myt'%flags> <&|doclib.myt:item, name="globals", description="Standard Global Variables"&>Myghty templates and components always have access to a set of global variables that are initialized on a per-request basis. The Myghty request object m is always available, as are the component arguments ARGS. When running with any HTTPHandler-based environment, the HTTP request object r is also available, which in mod_python is the actual mod_python request object, else it is a compatible emulating object. The Myghty session object, or mod_python's own session object, may be configured to be available as the variable s. Finally, any set of user-configured global variables can be defined as well; the value of these globals can be specified on a per-interpreter or per-request basis.
<&|doclib.myt:item, name="globalm", description="Your Best Friend: m"&>m is known as the "request", which represents the runtime context of the template being executed. Its not the same as the HTTP-specific request object r and is mostly agnostic of HTTP. m includes methods for handling output and writing content, calling other components, as well as other services that a template will usually need. The full list of request methods is described in <&formatting.myt:link, path="request"&>.
&> <&|doclib.myt:item, name="globalargs", description="Your Other Best Friend: ARGS"&>ARGS represents a dictionary of all arguments sent to the current component. While a component can specify arguments to be available in the component's namespace via the <% "<%args>" %> tag, the ARGS dictionary contains all arguments supplied to a component regardless of them being named in the <% "<%args>" %> section or not.
In the case of a top-level component called in an HTTP context, ARGS contains the full set of client request parameters. Each field is one of: a string, a list of strings, or for handling file upload objects, a Field object (from the FieldStorage API) or a list of Field objects.
For components called by other components, ARGS contains all the arguments sent by the calling component.
In all cases, the HTTP request arguments, or whatever arguments were originally sent to the request, are available via the request member <&formatting.myt:link, path="request_members", member="request_args" &>.
Component arguments are described in <&formatting.myt:link,path="components_args"&>.
&> <&|doclib.myt:item, name="globalr", description="Your Pal: r"&>When running Myghty with any of the HTTPHandlers, i.e. ApacheHandler, CGIHandler, WSGIHandler, or HTTPServerHandler, variable r is a reference to either the mod python request object or a compatible emulation object. In the case of ApacheHandler, it is the actual mod_python request. In other cases, it attempts to provide a reasonably compatible interface, including the member variables headers_in, headers_out, err_headers_out, args, content_type, method, path_info, and filename (more can be added...just ask/submit patches). The request object is useful applications that need awareness of HTTP-specific concepts, such as headers and cookies, beyond what the more generic m object provides which attempts to be largely agnostic with regards to HTTP.
Under WSGIHandler, r also contains the member variables environ and start_response, so that an application may also have direct access to WSGI-specific constructs if needed.
&> <&|doclib.myt:item, name="globals", description="Your Fair Weather Friend: s"&>s references the Myghty session object. It can also be configured to reference the mod_python session object when running with mod_python 3.1 To use s, you need to turn it on via <& formatting.myt:link, path="session_options", param="use_session" &>.
The Myghty session is still available even if s is not configured. See the section <&formatting.myt:link, path="session"&> for full information on the session object. &> <&|doclib.myt:item, name="globalcustom", description="Make your Own Friends"&>
Myghty supports the addition of any number of global variables that will be compiled into the namespace of all templates. The value of these variables can be specified on a per-application basis or a per-request basis. As of version 0.98, both scopes can be used simultaneously. Per-application globals can be specified via the initial interpreter configurational parameters, or within the httpd.conf file in a mod_python environment. Per-request globals require that the variables be initialized before the Myghty request begins, which requires programmatic "chaining" to the Interpreter via the methods described in <& formatting.myt:link, path="configuration_programmatic" &>.
The two configuration parameters to add global arguments are <&|formatting.myt:codeline&>allow_globals&>, which specifies a list of global variable names to compile into templates, and <&|formatting.myt:codeline&>global_args&>, which is a dictionary containing the names of the variables mapped to their desired values. A basic example of programmatic global variables looks like:
<&|formatting.myt:code, syntaxtype="python" &> import myghty.http.WSGIHandler def application(environ, start_response): handler = myghty.http.WSGIHandler.get_handler( allow_globals = ['myglobal'], component_root='/path/to/htdocs', data_dir='/path/to/datadirectory' ) return handler.handle( environ, start_response, global_args = {'myglobal' : 'hi'} ) &>Above, all Myghty components will have access to the global variable "myglobal" which has a per-request value of "hi". Note that the allow_globals parameter is only used on the first request, when constructing a new Interpreter object, whereas global_args may be specified for each request.
Another example, using Interpreter:
<&|formatting.myt:code, syntaxtype="python"&> interpreter = interp.Interpreter( allow_globals = ['myglobal'], data_dir = '/path/to/datadir', component_root = '/foo/components', ) interpreter.execute("file.myt", global_args = {'myglobal':MyGlobalThingy()} ) &>Here is an ApacheHandler example which specifies globals within both scopes:
<&|formatting.myt:code, syntaxtype="python"&> import myghty.http.ApacheHandler as ApacheHandler # create per-application global object appglobal = 'myappglobal' def handle(req): # create per-request global object myglob = MyGlobal(req) handler = ApacheHandler.get_handler( req, allow_globals = ['appglobal', 'myglobal'], global_args = {'appglobal' : appglobal} ) return handler.handle(req, global_args = {'myglobal':myglob}) &>Here is an application-scoped global added in a mod_python environment via the httpd.conf file:
<&|formatting.myt:code, syntaxtype="conf"&> # specify list of global variable names PythonOption MyghtyAllowGlobals ['myglobal'] # specify the value of the global variable PythonOption MyghtyGlobalArgs "{'myglobal': <% "\\" %> __import__('mystuff.util').util.MyGlobalThingy()}" &> <&|doclib.myt:item, name="assignment", description="Assignment to Request-Scoped Globals"&>When the allow_globals configuration parameter specifies global variables to be compiled into all templates, if the variable is not present at request time, it is assigned the value of None (as of 0.98a). This is handy for global variables whos value is not determined until within a request.
To assign to a global variable, use m.global_args:
<&|formatting.myt:code&><%text> # assume the configuration parameter global_args = ['x','y','z'] is set <& hi &> % m.global_args['x'] = 'im x!' % m.global_args['y'] = 'im y!' <& hi &> <%def hi> x is '<% x %>' y is '<% y %>' z is '<% z %>' %def> %text>&>this will produce:
<&|formatting.myt:code&> x is: '' y is: '' z is: '' x is: 'im x!' y is: 'im y!' z is: '' &> &> &> &> myghty-1.1/doc/content/inheritance.myt 0000644 0001750 0001750 00000021520 10501064115 017126 0 ustar malex malex <%flags>inherit='document_base.myt'%flags> <&|doclib.myt:item, name="inheritance", description="Inheritance", &>Inheritance allows a file-based component to be "wrapped" by another file-based component. This means the requested page executes as a method call inside of the inheriting page, which executes first. The basic idea of this is to allow a whole set of pages to have standardized behavior applied to them by an "inheriting" component, the application of which can be as simple as a standard header and footer, or something more complicated such as an authentication scheme, a content caching scheme, or a filtering scheme.
Inheritance also establishes a relationship between pages with regards to method calling as well as component attributes.
<&|doclib.myt:item, name="wrapper", description="The Wrapper Chain", &>A set of pages that all inherit each other is sometimes called the "wrapper chain". The wrapper chain is an actual property of the request, and is determined dynamically for each new request based on what files are present in the filesystem and what inheritance pattern they specify. When a template X inherits from a template Y, and that template in turn inherits from template Z, the wrapper chain is created:
<&|formatting.myt:code&> Z -> Y -> X &>The request above was called specifying component X as the requested component. X inherits from Y, either via an explicit flag or an autohandler configuration (more on that later), and Y inherits from Z. Therefore a wrapper chain with Z at the beginning and X at the end is created. When the request executes, control is passed to Z first. Z performs its component operations, then programmatically instructs the request to call the next component in the wrapper chain, which is Y. Y does the same thing and calls X, the originally requested component. When X is complete, control passes back to Y, and when Y is complete, control passes back to Z.
The flag used to specify that a component should inherit from another is called "inherit", and is specified in the <% "<%flags>" %> section of the component. The component to inherit from is specified by its component-root-relative URI. When an inherited parent component wants to call its inheriting child, it usually uses the <&formatting.myt:link, path="request_methods", method="call_next"&> method of the request object. The child is only executed if its inherited parent explicitly does so.
If no "inherit" flag is specified for a page, the page will attempt to inherit from a template in the nearest enclosing directory named "autohandler". Whereas the inherit flag allows a component to explicitly specify its inherited parent, the autohandler mechanism allows the configuration of implicitly inheriting parents. Autohandlers are described in the next section <&formatting.myt:link, path="specialtempl_autohandler", text="Autohandlers"&>.
&> <&|doclib.myt:item, name="example", description="Example - Basic Wrapping", &>In this example, the requested page is called "index.myt", and its inherited parent is called "base.myt". base.myt supplies a standard HTML header and footer, and index.myt supplies the content in the middle of the <% "
" | h %> tags. <&|formatting.myt:code, title="index.myt, inherits from base.myt"&><%text> <%flags>inherit='/base.myt'%flags> I am index.myt %text>&> <&|formatting.myt:code, title="base.myt, the parent template"&><%text>While the <&formatting.myt:link, path="request_methods", method="call_next"&> method of request is the simplest way to call the next component in the wrapper chain, the method <&formatting.myt:link, path="request_methods", method="fetch_next"&> exists to pop the next component off the chain but not execute it, as well as <&formatting.myt:link, path="request_methods", method="fetch_all"&> which pops off and returns the entire list of components in the wrapper chain.
&> <&|doclib.myt:item, name="basecomp", description="The Base Component", &>In the wrapper chain <% '"Z -> Y -> X"' | h%> described at the beginning of the section, the component X is known as the request component, and is accessible throughout the life of the request via the <&formatting.myt:link,path="request_members", member="request_component"&> member of the request. It also is established as the initial "base component" of the request. The base component is accessible via the <&formatting.myt:link,path="request_members", member="base_component"&> request member, and it is defined first as the lead requested component in a wrapper chain. When methods in other template files are called, the base component changes to be the file that the method appears in, throughout the life of that method's execution, and upon method completion returns to its previous value.
The base component is also referred to by the special component keyword 'SELF'. This keyword can be used directly via the <&formatting.myt:link, path="request_methods", method="fetch_component"&> method, but it is more commonly referenced in method component calls, as detailed in the next section. &> <&|doclib.myt:item, name="method", description="Method and Attribute Inheritance", &>
Methods, first described in <&formatting.myt:link, path="components_methods" &>, are normally called with the <% "
It is for this reason that the base component and the SELF keyword is of particular value in fetch_component and method calls, since it indicates the innermost component in the current inheritance chain. An template at the end of a wrapper chain (i.e. template Z in the previous section) can specify the SELF keyword when calling a method, and the method will be located from the innermost template first (i.e. component X), and on up the wrapper chain until found.
Similarly, component attributes are located using an inheritance scheme as well. Attributes are referenced via the <&formatting.myt:link, path="components_members", member="attributes"&> member of the component object. The attributes dictionary, while it is a regular dictionary interface, will search for requested values in the parent of the component if not found locally.
&> <&|doclib.myt:item, name="methodexample", description="Method Inheritance Example", &>Here is an example where the parent component is an autohandler, which because of its name, automatically becomes the inherited parent of the child component, as long as the child component does not explicitly specify otherwise.
Both in the parent component as well as the child component that inherits from it specify a method "title". The autohandler can render the title of the page via the "title" method, where it is guaranteed to exist at least in the autohandler's own version of the method, but can be overridden by the inheriting page. Additionally, the autohandler has an <% "<%attr>" %> section indicating the path to a file location. The child page will look in its own attribute dictionary for this location, where it will ultimately come from the inheriting parent.
<&|formatting.myt:code, title="autohandler - specifies root title method and attributes"&><%text> <%attr> # path to some files fileroot = '/docs/myfiles' %attr>Myghty includes an out-of-the-box instant-gratification examples/documentation server you can run directly from the distribution files, which listens on port 8000 by default. Extract the distribution from its .tar.gz file. Then run the server as follows:
<&|formatting.myt:code, syntaxtype="cmd" &> cd /path/to/Myghty-X.XX/ python ./tools/run_docs.py &>Then point a webbrowser to the location http://localhost:8000/. An alternative port can be specified on the command line, e.g. python ./tools/run_docs.py 8100.
The demo server is a handy tool to browse through a release without having to perform an install. The underlying HTTP server implementation can also be handy for development and prototyping.
&> <&|doclib.myt:item, name="install", description="Installing the Library", &>Myghty now installs with setuptools, which is the next generation of the standard Python distutils module. Its basic usage is the same as that of distutils. Switch to the user account under which Python is installed, and run: <&|formatting.myt:code, syntaxtype="cmd" &> cd /path/to/Myghty-X.XX/ python setup.py install &> As some systems may have multiple Python interpreters installed, be sure to use the Python executeable that corresponds to the Python being used by the webserver, such as the mod_python configuration, to insure the files go into the correct library path. setup.py will precompile the Myghty .py files and install them in the library path for the Python executeable you just ran.
This installer also installs Myghty in a version-specific location, such as "site-packages/Myghty-0.99-py2.3.egg/". If you have installed a version of Myghty prior to 0.99, the distutils-based installation, which lives in "site-packages/myghty", will produce a conflict message when running setup.py. After installation, you should delete the old install, either manually or via the command python ez_setup.py -D myghty. &> <&|doclib.myt:item, name="docgen", description="Generating the Documentation", &>
This documentation can also be generated into flat html files that are browseable directly from the filesystem. Myghty can create these files by running the genhtml.py utility:
<&|formatting.myt:code, syntaxtype="cmd" &> cd /path/to/Myghty-X.XX/doc python genhtml.py &> &> <&|doclib.myt:item, name="paste", description="Running Paste Templates", &>Myghty now includes a few Python Paste templates, which are pre-built Myghty applications that can install themselves into a runnable application. Python 2.4 is required to run Python Paste.
Myghty's standard install procedure will automatically download and install all Python Paste components, which are also available at http://pythonpaste.org/download. Also required is WSGIUtils, which must be installed from a particular .egg file format, via:
<&|formatting.myt:code, syntaxtype="cmd" &> python ez_setup.py http://pylons.groovie.org/files/WSGIUtils-0.6-py2.4.egg &>When Python Paste is installed, it will install the script "paster" into the standard Python scripts location. Insure that this location is in your path. Then to set up a Paste Template, just do:
<&|formatting.myt:code, syntaxtype="cmd" &> cd /target/directory paster create --template=myghty_simple myproject cd myproject paster serve server.conf &>The myghty_simple template is a very small four-template configuration, which will by default listen on port 8080. Also included is myghty_modulecomponent, which shows off a more controller-oriented configuration, and myghty_routes, which builds a new Rails-like "Routes" configuration.
When a new Paste Template project is created, the file <%"
There is also a generic tool for running any Myghty template either to standard output or to a file. The command is as follows:
<&|formatting.myt:code, syntaxtype="cmd" &> python tools/gen.py --help usage: gen.py [options] files... options: -h, --help show this help message and exit --croot=COMPONENT_ROOT set component root (default: ./) --dest=DESTINATION set destination directory (default: ./) --stdout send output to stdout --datadir=DATADIR set data directory (default: dont use data directory) --ext=EXTENSION file extension for output files (default: .html) --source generate the source component to stdout &> &> &> myghty-1.1/doc/content/modulecomponents.myt 0000644 0001750 0001750 00000127211 10501064115 020234 0 ustar malex malex <%flags>inherit='document_base.myt'%flags> <&|doclib.myt:item, name="modulecomponents", description="Module Components", &>Module components build upon the component concept as introduced and explained in the previous section, <&formatting.myt:link, path="components"&>. They represent a way of writing Myghty components using regular Python code within importable .py modules. A module component can be used to handle requests, controlling the flow of an application across one or more templates; this role is known as a "controller". Module components can also be embedded as component calls within templates just like any other component. In both cases, Module Components are the appropriate place to place code-intensive control or view logic.
Module Components, or MC's, are not a new idea, and have analogies in other environments, such as the Java Servlet class, the mod_python handler() function, or the WSGI application() callable. To suit the preferences of the both the class-oriented and the function-oriented developer, MC's can be written either as classes that subclass a specific Myghty class (similar to subclassing the Java Servlet class) or just as a regular Python function or callable object (i.e., an object instance that has a __call__ method). Additionally, individual methods upon a class instance can also be called as MC's.
When a plain Python function, callable object, or arbitrary instance method (herein will be generically referred to as a "callable") is to be called as a Module Component, the resulting component is referred to as an implicit module component. In this case, the Myghty Interpreter is given the location of the callable either via a string pattern or via passing the callable itself, and is told to execute it as a component. The Interpreter then creates a "real" component behind the scenes which proxies the Myghty argument set to the callable. The developer need not be aware of this proxying component (though it is available).
The flipside to the implicit module component is the explicit module component. Here, the developer creates a class that is a subclass of myghty.component.ModuleComponent, and implements the method do_run_component(), which satisfies the execution of the component. Like the implicit module component, the Interpreter is given its location either via a string pattern or via the Class object itself, and is told to execute it. The Interpreter, upon receiving a Class object, instantiates the class which becomes directly the component to be executed; no "proxy" component is created.
The differences between implicit and explicit module components are mostly differences in style. The explicit form allows the developer more direct access to the flags, attributes, and argument lists of the component to be called, whereas the implicit form is more sparse, lightweight and flexible. Both styles can be mixed; essentially, the Intepreter receives the object and determines the calling style based on the type of object passed to it. In all cases, the rest of a Myghty application sees just more myghty.component.Component objects, which have the same properties as any other component.
An added layer of complexity to module components involves the configuration of URI resolution, which allows the mapping of arbitrary URI's to specific module component callables or classes based on different schemes. This is required for MC's that are to be called as the top-level, request-handling component. Myghty currently includes two methods of achieving this, which are described later in this section, as well as an API to allow any user-defined mapping algorithm (part of <&formatting.myt:link, path="resolver" &>).
<&|doclib.myt:item, name="example", description="Example Module Component", &>Lets start with hello world. All we need to do is create a new .py file, called hello.py, and place the following function inside it:
<&|formatting.myt:code, syntaxtype='python' &> def helloworld(m): m.write("hello world !") &>That is the extent of the module component itself. Since it is a plain function, this is an "implicit" module component.
To call the component, the request object is given a string starting with the prefix "MODULE:", followed by the module name and name of the callable or class, separated by a colon. In a template it is one of the following:
<&|formatting.myt:code, syntaxtype='myghty' &><%text> # inline <& MODULE:hello:helloworld &> # code <%python> m.comp("MODULE:hello:helloworld") %python> %text>&>Alternatively (release 0.99b), the "MODULE:" prefix can also be an "at" sign as follows:
<&|formatting.myt:code, syntaxtype='myghty' &><%text> <& @hello:helloworld &> <%python> m.comp("@hello:helloworld") %python> %text>&>Both the module name and the callable/class name can contain any number of periods to represent sub-modules or sub-properties of the module. Suppose helloworld was a property on an object:
<&|formatting.myt:code, syntaxtype='python' &> hello = object() def doit(m): m.write("hello world !") hello.helloworld = doit &>This component can be called as:
<&|formatting.myt:code, syntaxtype='myghty' &><%text> <& MODULE:hello:hello.helloworld &> %text>&>or just:
<&|formatting.myt:code, syntaxtype='myghty' &><%text> <& @hello:hello.helloworld &> %text>&>The callable can have any argument list, and even the m variable is optional (though highly recommended). Myghty uses the inspect library to determine the desired arguments based on the callable's signature. (for the performance minded, this is done only once when the component is first loaded). Using the names present in the argument list, Myghty will determine which of the available global variables will be specified, as well as what required and optional component arguments this MC will require. The component arguments are configured in exactly the same way as a template-based component configures its <% "<%ARGS>" | h %> section.
So to our "hello world" lets add the current and optionally tomorrow's weather:
<&|formatting.myt:code, syntaxtype='python' &> def helloworld(m, today, tomorrow = None): m.write("hello world ! its a %s day today." % today) if tomorrow is None: m.write("Don't know what it is tomorrow, though.") else: m.write("But tomorrow, it'll be %s" % tomorrow) &>This component can be called like these examples:
<&|formatting.myt:code, syntaxtype='myghty' &><%text> # inline shorthand <& @hello:helloworld, today='sunny' &> # inline longhand <& MODULE:hello:helloworld, today='sunny' &> # code <%python> m.comp("MODULE:hello:helloworld", today='cloudy', tomorrow='rainy') %python> %text>&>The argument list of a module component may specify any of the standard and/or user-configured global arguments (globals were introduced in <& formatting.myt:link, path="globals" &>). All arguments are passed by name, so the ordering is not important:
<&|formatting.myt:code, syntaxtype='python' &> def handle_request(m, ARGS, r, s, **params): # ... &>The above component specifies that it will receive the global variables m, ARGS, r, and s. It also defines **params, so all remaining component arguments will be in this dictionary. A callable that defines simply **params will receive all globals and component arguments within the dictionary.
&> <&|doclib.myt:item, name="flavor", description="Flavors of Module Component", &>A summary of the various styles of MC are as follows. For each of the below examples, assume the callable exists within a module named mylib.hello:
<&|doclib.myt:item, name="function", description="Function", &> This is the most basic type of implicit module component. <&|formatting.myt:code, syntaxtype='python' &> def helloworld(m, **params): m.write("hello world!") &> Called as: <&|formatting.myt:code, syntaxtype='myghty' &><%text> <& MODULE:mylib.hello:helloworld &> %text>&> &> <&|doclib.myt:item, name="callable", description="Callable Object", &>A callable object must be instantiated, but to the outside world looks almost the same as a function:
<&|formatting.myt:code, syntaxtype='python' &> class HelloWorld: def __call__(self, m, **params): m.write("hello world!") # instantiate the class helloworld = HelloWorld() &> Called as: <&|formatting.myt:code, syntaxtype='myghty' &><%text> <& MODULE:mylib.hello:helloworld &> %text>&> Note that this is identical to the previous function example. &> <&|doclib.myt:item, name="method", description="Object Method", &> The object method is set up similarly to a callable object, the only difference being that a specific named method is called, instead of the generic __call__ method. The difference lies in how it is specified when called. <&|formatting.myt:code, syntaxtype='python' &> class HelloWorld: def doit(self, m, **params): m.write("hello world!") # instantiate the class helloworld = HelloWorld() &> Called as: <&|formatting.myt:code, syntaxtype='myghty' &><%text> <& MODULE:mylib.hello:helloworld.doit &> %text>&> One particular quirk about the object method style is that if an object instance contains multiple methods that are called as MC's, the interpreter creates a separate "proxy" component for each method.With both callable object styles, the same object instance handles many requests, including multiple simultaneous requests among different threads, if the application is running in a threaded environment. A developer should take care to store request-scoped information as attributes upon the request object and not as instance variables of the object, as well as to appropriately synchronize access to instance variables and module attributes. &> <&|doclib.myt:item, name="explicit", description="Class / Explicit Module Component", &>
This style works differently from the previously mentioned styles, in that the developer is writing a class directly against the Myghty API. In this style, the developer directly defines the class of the component that is ultimately being accessed by the outside world. No "proxying" component is created; instead, the Interpreter instantiates the specified class the first time it is referenced. This also removes the need to explicitly instantiate the class: <&|formatting.myt:code, syntaxtype='python' &> import myghty.component class HelloWorld(myghty.component.ModuleComponent): def do_run_component(self, m, **params): m.write("hello world!") &> Called as: <&|formatting.myt:code, syntaxtype='myghty' &><%text> <& MODULE:mylib.hello:HelloWorld &> %text>&>
Note that the scoping rules for this style of component are the same, i.e. the same component instance is called for many requests and must be aware of variable scope as well as concurrency issues.
The do_run_component method works similarly to the callable of an implicit component. Its argument list is dynamically inspected to determine the desired globals and component arguments, in the same way as that of implicit MC's. However, there also is the option to bypass this inspection process and name the arguments explicitly, as well as their desired scope. In previous versions of Myghty, this was the only way to define the arguments of an MC, but now its only optional. This method is described in the next section, as well as the configuration of flags and attributes for MC's. &> &> <&|doclib.myt:item, name="initialization", description="Module Component Initialization", &>
Explicit MCs as well as implicit MCs based on an object instance have an optional initialization step that is called the first time the object instance is referenced. The method is called on an explicit ModuleComponent subclass as:
def do_component_init(self)And is called on an implicit callable object as:
def do_component_init(self, component)In the second version, the argument component is an instance of myghty.component.FunctionComponent that is hosting the implicit module component's __call__ method or other method. It is important to note that an object instance with many callable methods will actually have many FunctionComponents created, each one hosting an individual methods...however, the do_component_init() method is only called once with whatever FunctionComponent was first associated with the object.
In previous versions of Myghty, the initialization phase was required for components with arguments, which had to be explicitly declared within this stage. As of version 0.98, explicit declaration of component arguments is optional, and the argument lists are by default determined from the signature of the explicit do_run_component method or the implicit callable.
Explicit specification of an MCs arguments in the init section are as follows:
<&|formatting.myt:code, syntaxtype='python'&><%text> import myghty.component as component class MyComponent(component.ModuleComponent): def do_component_init(self, **params): # component arguments self.args = ['arg1', 'arg2'] # required component arguments self.required_args = ['arg3', 'arg4'] # request-only arguments self.request_args = ['docid'] # required request-only arguments self.required_request_args = ['userid'] # subrequest or request arguments self.subrequest_args = ['foo'] # required subrequest or request arguments self.required_subrequest_args = ['bar'] %text>&>A component as above would have the do_run_component signature as follows:
<&|formatting.myt:code, syntaxtype='python'&><%text> def do_run_component( self, m, userid, arg3, arg4, bar, docid = None, arg1 = None, arg2 = None, foo = None, **params ): %text>&>Note that if a module component defines any arguments explicitly in the do_component_init method, all arguments for the do_run_component method must be specified; no automatic introspection of function arguments will occur.
Similarly, <% "<%flags>" %> and <% "<%attr>" %> sections can be achieved like this:
<&|formatting.myt:code, syntaxtype='python'&><%text> def do_component_init(self, **params): # flags self.flags = { 'autoflush':True, 'trim': 'both' } # attributes self.attr = { 'style':'green', 'docid':5843 } %text>&> &> <&|doclib.myt:item, name="controller", description="Using MCs as Controllers", &>The two most prominent features of an MC used as a controller includes that URI resolution is configured so that one or more URIs result in the component being called directly from a request, and that the component typically uses subrequests to forward execution onto a template, which serves as the view.
Here are two versions of a controller component that is used to pull documents from a database based on the request arguments, and displays them via a template called "documents.myt".
Figure 1: Implicit Style, using a Callable Object
<&|formatting.myt:code, syntaxtype='python' &><%text> class DocumentManager: def do_component_init(self, component): # load some application-wide constants via Interpreter attributes. # the Interpreter is located via the hosting component. self.document_base = component.interpreter.attributes['document_base'] self.db_string = component.interpreter.attributes['db_connect_string'] def __call__(self, m, docid = None): # if no document id, return '404 - not found' if docid is None: m.abort(404) # access a hypothetical document database docdb = get_doc_db(self.document_base, self.db_string) # load document document = docdb.find_document(docid) # couldnt find document - return '404 - not found' if document is None: m.abort(404) # run template m.subexec('documents.myt', document = document, **params) documentmanager = DocumentManager() %text>&>Figure 2: Explicit Style, with Pre-Declared Arguments
<&|formatting.myt:code, syntaxtype='python' &><%text> import myghty.component as component class DocumentManager(component.ModuleComponent): def do_component_init(self, **params): # load some application-wide constants self.document_base = self.interpreter.attributes['document_base'] self.db_string = self.interpreter.attributes['db_connect_string'] # establish the argument names we want (optional as of 0.98) self.args = ['docid'] def do_run_component(self, m, ARGS, docid = None, **params): # if no document id, return '404 - not found' if docid is None: m.abort(404) # access a hypothetical document database docdb = get_doc_db(self.document_base, self.db_string) # load document document = docdb.find_document(docid) # couldnt find document - return '404 - not found' if document is None: m.abort(404) # run template m.subexec('documents.myt', document = document, **params) %text>&>The next section describes the two methods of configuring request URIs to execute "controller" components like this one.
&> <&|doclib.myt:item, name="resolution", description="Configuring Module Component Resolution", &>Module components can be used anywhere within the request, either right at the beginning (i.e. a controller) or within the scope of other components already executing. A module component can be fetched and/or called based on its importable module name followed by a path to a callable object, or the name of a class that subclasses myghty.components.ModuleComponent. However, this doesn't work as a URL sent to a webserver. For request-level operation, MCs must be mapped to URIs. This resolution is achieved through two different configuration directives, module_components and module_root. A third option also exists which is to use the new routesresolver resolver object.
<&|doclib.myt:item, name="module_components", description="module_components", &> The module_components configuration parameter looks like this: <&|formatting.myt:code, syntaxtype="python" &> module_components = [ {r'myapplication/home/.*' : 'myapp.home:HomeHandler'}, {r'myapplication/login/.*' : 'myapp.login:LoginHandler'}, {r'.*/cart' : 'myapp.cart:process_cart'}, {r'.*' : 'myapp.home:HomeHandler'} ] &> Which in an apache configuration looks like: <&|formatting.myt:code, syntaxtype="conf" &> PythonOption MyghtyModuleComponents "[ <% "\\" %> {r'myapplication/home/.*' : 'myapp.home:HomeHandler'}, <% "\\" %> {r'myapplication/login/.*' : 'myapp.login:LoginHandler'}, <% "\\" %> {r'.*/cart' : 'myapp.cart:ShoppingCart'}, <% "\\" %> {r'.*' : 'myapp.home:HomeHandler'} <% "\\" %> ]" &>Each entry in the module_components array is a single-member hash containing a regular expression to be matched against the incoming URI, and an expression that can be resolved into a Module Component. This expression can be any of the following forms:
<&|formatting.myt:code, syntaxtype="python" &> module_components = [ # a string in the form 'Generally, its better to use the string forms since they encompass all the information needed to load the class or callable object, which allows the Myghty interpreter to dynamically reload the object when the underlying module has changed.
For module components that resolve to a Class, the Class will be instantiated by the Interpreter, and is expected to be a subclass of myghty.component.ModuleComponent. This is also known as an explicit module component. For components that resolve to a function, object instance method, or callable object (i.e. any object that has a __call__ method), a "wrapper" module component will be created automatically which adapts to the callable's argument list. This is also known as an implicit module component.
<&|doclib.myt:item, name="additional", description="Passing Resolution Arguments", &>The module_components configuration parameter also includes some methods of returning information about the actual resolution of the component at request time.
Since module_components uses regular expressions to match URIs to components, the re.Match object produced when a match occurs can be accessed via the m global variable. This example places capturing parenthesis in the regular expression to capture the additional path information:
<&|formatting.myt:code, syntaxtype="python", &> module_components = [ # place capturing parenthesis in the regexp {r'/catalog/(.*)' : 'store:Catalog'} ] &> The contents of the capturing parenthesis are available as: <&|formatting.myt:code, syntaxtype="python", &> m.resolution.match.group(1) &>User-defined arguments can also be configured which will be passed to the request object at resolution time. To use this form, a dictionary is used instead of a single string to specify the module and callable/class name of the component, and the address of the component itself is placed under the key 'component':
<&|formatting.myt:code, syntaxtype="python", &> module_components = [ # supply the component with some arguments {r'/login/' : { 'component' : 'myapp:loginmanager', 'ldap_server' : 'ldap://localhost:5678' } } ] &> The contents of the ldap_server argument are available as: <&|formatting.myt:code, syntaxtype="python", &> m.resolution.args['ldap_server'] &> &>The corresponding Resolver class for module_components is ResolveModule.
&> <&|doclib.myt:item, name="module_root", description="module_root", &>This parameter locates module components based on paths. It is similar to the <&formatting.myt:link, path="parameters", param="component_root" &> configuration parameter in that it defines one or more roots which will all be matched against the incoming URI. However, it not only traverses through directories, it also will traverse into a Python module where it attempts to locate a function or callable object instance. Currently, only the "implicit" style of module components can be used with module_root (but module_components, from the previous section, can be used with implicit or explicit MCs).
The entries in module_root take the following forms:
<&|formatting.myt:code, syntaxtype="python", &> module_root = [ # a regular file path '/web/lib/modules/', # the full file path of a Python module '/web/extra/modules/mycontroller.py', # the name of an importable Python module 'mylib.loginhandlers', ] &>Using the first path '/web/lib/modules', heres an example. Start with the following file:
<&|formatting.myt:code, syntaxtype=None, &> /web/lib/modules/admin/login.py &>This file contains the following code:
<&|formatting.myt:code, syntaxtype="python", &> def hello(m): m.write("hello world!") class _do_login: def __call__(self, m): m.write("please login") # .... def foo(self, m): m.write("this is foo") index = _do_login() _my_var = 12 &>Finally, lets have a module_root of:
<&|formatting.myt:code, syntaxtype="python", &> module_root = ['/web/lib/modules'] &>With this configuration, URLs will be resolved as follows:
<&|formatting.myt:code, syntaxtype=None &> http://mysite.com/admin/login/hello/ ---> "hello world!" (login.py:hello()) http://mysite.com/admin/login/ ---> "please login" (login.py:index.__call__()) http://mysite.com/admin/login/foo/ ---> "this is foo" (login.py:index.foo()) http://mysite.com/admin/login/lala/ ---> "please login" (login.py:index.__call__()) http://mysite.com/admin/login/_my_var/ ---> "please login" (_my_var is private and is skipped) http://mysite.com/admin/lala/ ---> 404 not found (no file named lala.py) &>The spirit of this resolver is that of the mod_python Publisher handler. Path tokens are converted into the names of .py files on the filesystem. When a file is located and it is a valid Python module, the module is loaded and further path tokens are resolved as attributes within the module itself. Attributes that start with an underscore are skipped, which is the default way to flag "private" attributes. There is also a "public" attribute marker which can be used to mark public functions instead of marking private functions, explained in the options section below. If no matching attribute exists for a path token, it looks for the attribute name "index", else returns a ComponentNotFound exception.
<&|doclib.myt:item, name="options", description="Module Root Options", &>The underlying Resolver object for the module_root parameter is called ResolvePathModule (resolver objects are described in <&formatting.myt:link, path="resolver" &>). This object also has configuration options of its own. These options may be specified to the ResolvePathModule constructor directly. They can be specified as regular Myghty configuration parameters as well as of version 0.99b:
module_root_adjust=None (release 0.99b) - a reference to a function which receives the incoming URI and returns a modified version of that URI with which to resolve. The modified URI is not propigated onto other rules in the resolution chain, so therefore it represents a "local" alternative to <&formatting.myt:link, path="parameters", param="path_translate"&>.
This parameter is also called 'adjust' in all releases, but that name conflicts with the same name in the ResolveFile resolver, so should only be used when constructing individual ResolvePathModule objects and not as a global configuration parameter.
require_publish=False - when set to True, the callable object must have an attribute publish set to True in order to mark it as publically accessible; else it will not be resolved. This effectively reverses the "negative publishing" model established via the underscore "_" syntax into a "positive publishing" model. Given this configuration:
<&|formatting.myt:code, syntaxtype="python", &> module_root = ['/web/lib/modules'] require_publish = True &>Marking functions and methods public looks like this: <&|formatting.myt:code, syntaxtype="python", &> class MyController(object): def __call__(self, m, **kwargs): # ... m.subexec('mytemplate.myt') __call__.public = True def do_stuff(self, m, **kwargs): # ... m.subexec('dostuff.myt') do_stuff.public = True def call_index(m,r, s, ARGS): # ... m.subexec('index.myt') call_index.public = True mycallable = MyController() &>
The public attribute can also be set in Python 2.4 via decorator:
<&|formatting.myt:code, syntaxtype="python", &> def mark_public(func): func.public = True return func @mark_public def mycontroller(m, **kwargs): # ... &>module_root can also be combined with dhandler resolution (described in <&formatting.myt:link, path='specialtempl_dhandler' &>), so that a file named dhandler.py in the current or parent directory serves as the "default" Python module for a path token that does not correspond to any other file. In the case of ResolvePathModule locating a dhandler.py file, the additional path tokens that normally reside within <& formatting.myt:link, path="request_members", member="dhandler_path"&> are also searched as attributes within the dhandler.py module.
The corresponding Resolver class for module_root is ResolvePathModule.
&> <&|doclib.myt:item, name="routesresolver", description="Routes Resolver", &>The Routes Resolver provides Rails-like functionality, building upon the resolution architecture described in <&formatting.myt:link, path="resolver"&>. Since it is not part of the default set of resolver objects, it must be included in the resolution chain via the <&formatting.myt:link, path="parameters", param="resolver_strategy"&> configuration parameter.
A rudimentary example of the Routes resolver can be viewed by installing the myghty_routes Paste template. Instructions for installing Paste templates are in <& formatting.myt:link, path="installation_paste"&>. The routes resolver also serves as the core resolver for the Pylons web framework which is based on Myghty, and includes more comprehensive and up-to-date examples.
&> &> <&|doclib.myt:item, name="preprocessor", description="Module Component Pre and Post processing", &>Request-handling module components can also be used to perform pre- and post-processing on a request. This means that the information about a request is modified before and/or after the main response is determined. The following two examples both wrap the main body of the request inside of a subrequest.
A module component that performs translations on incoming URI's, and then passes control onto the requested template, looks like this:
<&|formatting.myt:code, syntaxtype='python'&><%text> def translate_path(self, m, **params): path = m.get_request_path() path = re.sub('/sitedocs/john/', '/', path) m.subexec(path, **params) %text>&>A URI configuration for this component might look like:
<&|formatting.myt:code, syntaxtype="python"&><%text> module_components = [{r'/sitedocs/john/.*\.myt', 'mymodule:translate_path'}] %text>&>Path translation is also accomplished in Myghty via the <&formatting.myt:link, path="parameters", param="path_translate"&> parameter, and can be controlled in finer detail through the use of custom resolution rules, described in <&formatting.myt:link, path="resolver" &>.
An example post processing component, which filters the output of the subrequest before returning data:
<&|formatting.myt:code, syntaxtype='python' &><%text> import StringIO, re def filter(self, m, **params): # make a buffer buf = StringIO.StringIO() # create a subrequest using that buffer # our templates are located relative to the # request URI underneath '/components' subreq = m.create_subrequest('/components' + m.get_request_uri(), out_buffer = buf) # execute the subrequest ret = subreq.execute() # perform a meaningless filter operation on the content content = re.sub(r'foo', r'bar', buf.getvalue()) # write the content m.write(content) %text>&>This component might be configured as:
<&|formatting.myt:code, syntaxtype="python"&><%text> module_components = [{r'/sitedocs/john/.*\.myt', 'mymodule:filter'}] %text>&>Filtering is also built in to Myghty via the use of <% "<%filter>" %> section, described in <& formatting.myt:link, path="filtering" &>.
&> <&|doclib.myt:item, name="templates", description="Using Module Components within Templates", &>MCs can also be called from within templates. If an MC is configured to be callable against a URI using module_components or module_root, that URI can also be used within a regular <% "<& &>" | h %>-style component call. Or, the MODULE: prefix style described previously can be used.
<&|doclib.myt:item, name="formexample", description="Example: Form Visitor", &>Here is an example of a module component that is used to generate HTML forms from a data object, using the visitor pattern. Such an architecture can be used to have form information stored in a database or XML file which can then be used to automatically construct a corresponding form. This example is included in working form with the Myghty distribution.
Step 1: Data Model - The data model consists of a hierarchy of FormElement objects. Some FormElement objects can contain collections of other FormElements (the "composite" pattern):
<&|formatting.myt:code, title='form.py', syntaxtype='python'&><%text> class FormElement(object): """ abstract FormElement superclass.""" def __init__(self): pass def accept_visitor(self, visitor): """subclasses override accept_visitor to provide the appropriate type-based visitor method.""" pass class Form(FormElement): """represents a