Myghty Documentation
Version: 1.2 Last Updated: 07/07/10 12:55:17
View: Paged  |  One Page

This section illustrates how to link the Myghty interpreter to a Python application. If you already have a basic configuration running and want to jump into programming templates, skip ahead to Embedding Python in HTML.

The central request-handling unit within Myghty is called the Interpreter. When an application is set up to handle a request and pass control onto the Interpreter, it is referred to as an external controller. In the model-view-controller paradigm, the application is the controller, the template called by the Interpreter is the view, and whatever data is passed from the controller to the template is the model.

Currently, all Myghty installations, except for mod_python, require at least a rudimentary external controller, which serves as the place for configuration directives to be set up and specified to the Myghty environment. Since a lot of configuration directives reference datastructures or functions themselves, a Python module is the most natural place for this to happen.

A more elaborate external controller may be the point at which an application passes control from its application code and business logic onto a view layer, served by a Myghty Interpreter and corresponding template files. This may be appropriate for an application that is already handling the details of its HTTP environment, if any, or any application that just needs basic template support.

In contrast to the "external controller" concept is the internal controller, which is Python code that executes after the Interpreter begins handling the request, forwarding data onto template-driven components at the end of its request cycle. Myghty provides a construct for this kind of controller described in Module Components. It is recommended that an application that aims to be designed in a full MVC (model-view-controller) style, particularly one that runs in an HTTP environment, place its controller code into Module Components, and only application configuration code and externally-dependent code into a single external controller module. That way the majority of an application's controller code is written in an environment-neutral fashion, and also has the full benefits of the Myghty resolution and request environment available to it.

The two general categories of external controller are:

Chaining to HTTPHandler

For applications running in an HTTP environment, chaining to HTTPHandler is the usual method. An HTTPHandler object has awareness of HTTP requests for any of four different environments, which are WSGI, CGI, mod_python, and the standalone handler. It can construct the appropriate HTTP-aware environment to be delivered to the Interpreter and ultimately onto templates, which then receive an implementation-neutral interface to that environment via the r global object.

All HTTP-based Myghty configurations utilize a subclass of myghty.http.HTTPHandler.HTTPHandler to serve requests. Each HTTP environment has its own module: myghty.http.ApacheHandler, myghty.http.CGIHandler, myghty.http.HTTPServerHandler and myghty.http.WSGIHandler, containing the classes ApacheHandler, CGIHandler, HSHandler, and WSGIHandler, respectively.

As of version 0.98, the recommended way to chain to an HTTPHandler is to first get an instance to a handler via the function get_handler(), and then execute a request on that handler via the method handle(). In previous versions, a single function handle() is used which combines the argument sets of both functions; this function is still available.

The get_handler function retrieves a handler from a registry based on the given interpreter_name, which defaults to 'main' or in the case of Apache uses the http.conf variable "MyghtyInterpreterName". Application-scoped configuration variables are sent to this method which are used to create the initial HTTPHandler object. Once created, subsequent calls with the same interpreter_name will return the same HTTPHandler instance.

HTTPHandler then supplies the method handle() to handle requests, which accepts configurational parameters on a per request basis. Common per-request parameters include the component path or object to serve, the request arguments, and out_buffer to capture component output.

Each handler module has a slightly different calling signature, illustrated below.

ApacheHandler

The ApacheHandler handles mod_python requests. It retrieves configuration via directives found in the host's httpd.conf file in the manner detailed in mod_python, and by default serves the component referenced by the request.uri data member. Configuration parameters sent programmatically override those found in the Apache configuration.

In the example below, a file "myghty_handler.py" is created, which contains a very simple mod_python handler that "chains" to the myghty ApacheHandler.

myghty_handler.py
import myghty.http.ApacheHandler as ApacheHandler
from mod_python import apache

def handle(request):
    handler = ApacheHandler.get_handler(request)
    return handler.handle(request)

A configuration for the above file is similar to a straight Apache configuration. Since the ApacheHandler created in the myghty_handler.py file contains no configuration at all, all of its options will come from the httpd.conf directives:

AddHandler mod_python .myt
PythonHandler myghty_handler::handle
PythonPath "sys.path+[r'/path/to/my/libraries']"
PythonOption MyghtyComponentRoot r"/path/to/htdocs"
PythonOption MyghtyDataDir r"/path/to/writeable/data/directory/"

When we take the above handler file and add configuration directives programmatically, they will override those named in the httpd.conf file:

myghty_handler.py
import myghty.http.ApacheHandler as ApacheHandler
from mod_python import apache

def handle(request):
    handler = ApacheHandler.get_handler(request,
            data_dir='/usr/local/web/data',
            component_root=[
                {'components':'/usr/local/web/components'},
                {'templates':'/usr/local/web/templates'}
            ])
    return handler.handle(request)

Another example, overriding the application's data directory, and also the request's component path and request arguments:

import myghty.http.ApacheHandler as ApacheHandler
from mod_python import apache

def handle(request):
    handler = ApacheHandler.get_handler(
        request, interpreter_name = 'mainhandler', data_dir = '/data'
    )
    return handler.handle(request, 
        component = 'mypage.myt', request_args = {'foo' : 'bar'}
    )

The above example also specifies the interpreter_name configuration parameter which identifies which ApacheHandler is returned by get_handler. If this parameter is not specified, it defaults to "main".

back to section top
CGIHandler

The CGI handler retreives its environment information via the cgi.FieldStorage() method as well as os.environ. Configuration parameters sent programmatically override those found in the CGI environment. By default, CGIHandler serves the component indicated by the environment variable PATH_INFO.

CGI application chaining to CGIHandler.handle() function
#!/usr/local/bin/python

import myghty.http.CGIHandler as CGIHandler

# serve the component based on PATH_INFO
CGIHandler.get_handler(
        component_root='/path/to/htdocs',
        data_dir='/path/to/datadirectory'
).handle()
back to section top
WSGIHandler

WSGIHandler works similarly to CGIHandler. Its r object maintains a reference to both the environ and start_response members. These members are used to extract the core data members of the r object, such as headers_in, method, etc.

When running under WSGI, the environ and start_response variables are available via:

# WSGI environment variables

r.environ
r.start_response

WSGI application chaining to WSGIHandler.handle() method
import myghty.http.WSGIHandler as WSGIHandler

def application(environ, start_response):
    return WSGIHandler.get_handler(
        component_root='/path/to/htdocs', 
        data_dir='/path/to/datadirectory').handle(environ, start_response)

Also supported with WSGI is the standard application(environ, start_response) function, which takes in all application and request-scoped configuration parameters via the environ argument:

WSGI application via application()
import myghty.http.WSGIHandler as WSGIHandler

params = dict(
    interpreter_name='main_wsgi',
    component_root='/path/to/htdocs', 
    data_dir='/path/to/datadirectory'
)

def application(environ, start_response):
    environ['myghty.application'] = params
    environ['myghty.request'] = {'component' : 'mycomponent.myt'}
    return WSGIHandler.application(environ, start_response)
back to section top
Chaining to Interpreter

The Myghty Interpreter object is the underlying engine that creates Myghty requests and executes them, supplying the necessary services each request needs. The Interpreter can be programmatically instantiated with a full set of configuration parameters and used directly.

While the advantage of using an HTTPHandler in an application is that Myghty components are aware of HTTP-specific information, such as the mod_python request object, HTTP headers, the httpd.conf configuration, etc., an application can also bypass all this by chaining directly to the Interpreter, if templates do not need HTTP awareness and the configuration can be programatically specified.

mod_python handler chaining to Interpreter
import myghty.interp as interp
from mod_python import apache

# set up a singleton instance of Interpreter
interpreter = interp.Interpreter(
        data_dir = './cache',
        component_root = './doc/components',
    )

def handle(request):
    # set up some data to send to the template
    data = {
        'foo': 'bar',
        'info' : get_info()
    }

    # call a template
    interpreter.execute('mytemplate.myt', request_args = data, out_buffer = request)

In the above approach, Myghty components are unaware of the HTTP environment, meaning there is no r global variable, and also can't make HTTP return calls or location redirects. A greater amount of responsibility is placed within the controller.

Configuring a Standalone Application

Chaining to the Interpreter directly also allows Myghty to run outside of a web context completely, within any Python application. It doesnt really need much configuration to run in "barebones" mode; the two most common features are the component root, which specifies one or more roots to search for input files, and the optional data directory, where it will store compiled python modules. Without the data directory, the compiled python modules are created in memory only.

A standlone application to run Myghty templates looks like this:

#!/usr/local/bin/python

import myghty.interp as interp
import sys

interpreter = interp.Interpreter(
        data_dir = './cache',
        component_root = './doc/components',
        out_buffer = sys.stdout
    )

# component name is relative to component_root
interpreter.execute('/index.myt')

The execute method of Intepreter takes optional parameters and sends them off to a newly created Request object. You can specify any of the constructor arguments used by Request or its embedded helper object RequestImpl in the execute call of Interpreter, which will override the values given in the constructor to Interpreter. The below example sends a buffer to each request with which to capture output, via the out_buffer parameter:

file = open('index.html', 'w')
interpreter.execute('/index.myt', out_buffer = file)
file.close()
back to section top