Code Documentation

Introduction

This chapter covers important functions, methods and classes in Douglas. When in doubt, read the code.

Douglas

__version__

Douglas version as a string. Conforms to PEP-386.

For example "0.1".

douglas.app

class douglas.app.Douglas(config, environ, data=None)

Main class for Douglas functionality. It handles initialization, defines default behavior, and also pushes the request through all the steps until the output is rendered and we’re complete.

cleanup()

This cleans up Douglas after a run.

This should be called when Douglas has done everything it needs to do before exiting.

get_request()

Returns the Request object for this Douglas instance.

get_response()

Returns the Response object associated with this Request.

initialize()

The initialize step further initializes the Request by setting additional information in the data dict, registering plugins, and entryparsers.

run(compiling=False)

This is the main loop for Douglas. This method will run the handle callback to allow registered handlers to handle the request. If nothing handles the request, then we use the default_blosxom_handler.

Parameters:compiling – True if Douglas should execute in compiling mode and False otherwise.
run_collectstatic()

Collects static files and copies them to compiledir

run_compile(incremental=False)

Compiles the blog into an HTML site.

This will go through all possible things in the blog and compile the blog to the compiledir specified in the config file.

This figures out all the possible path_info settings and calls self.run() a bazillion times saving each file.

Parameters:incremental – Whether (True) or not (False) to compile incrementally. If we’re incrementally compiling, then only the urls that are likely to have changed get re-compiled.
run_render_one(url, headers)

Renders a single page from the blog.

Parameters:
  • url – the url to render–this has to be relative to the base url for this blog.
  • headers – True if you want headers to be rendered and False if not.
class douglas.app.EnvDict(request, env)

Wrapper arround a dict to provide a backwards compatible way to get the form with syntax as:

request.get_http()['form']

instead of:

request.get_form()
class douglas.app.Request(config, environ, data)

This class holds the Douglas request. It holds configuration information, HTTP/CGI information, and data that we calculate and transform over the course of execution.

There should be only one instance of this class floating around and it should get created by douglas.cgi and passed into the Douglas instance which will do further manipulation on the Request instance.

add_configuration(newdict)

Takes in a dict and adds/overrides values in the existing configuration dict with the new values.

add_data(d)

Takes in a dict and adds/overrides values in the existing data dict with the new values.

add_http(d)

Takes in a dict and adds/overrides values in the existing http dict with the new values.

buffer_input_stream()

Buffer the input stream in a StringIO instance. This is done to have a known/consistent way of accessing incomming data. For example the input stream passed by mod_python does not offer the same functionallity as sys.stdin.

get_configuration()

Returns the actual configuration dict. The configuration dict holds values that the user sets in their config.py file.

Modifying the contents of the dict will affect all downstream processing.

get_data()

Returns the actual data dict. Holds run-time data which is created and transformed by douglas during execution.

Modifying the contents of the dict will affect all downstream processing.

get_form()

Returns the form data submitted by the client. The form instance is created only when requested to prevent overhead and unnecessary consumption of the input stream.

Returns:a cgi.FieldStorage instance.
get_http()

Returns the actual http dict. Holds HTTP/CGI data derived from the environment of execution.

Modifying the contents of the dict will affect all downstream processing.

get_response()

Returns the Response for this request.

get_theme()

Returns the user-requested theme.

set_response(response)

Sets the Response object.

class douglas.app.Response(request)

Response class to handle all output related tasks in one place.

This class is basically a wrapper arround a StringIO instance. It also provides methods for managing http headers.

add_header(key, value)

Populates the HTTP header with lines of text. Sets the status code on this response object if the given argument list containes a ‘Status’ header.

Example:

>>> resp.add_header("Content-type", "text/plain")
>>> resp.add_header("Content-Length", "10500")
Raises:ValueError – This happens when the parameters are not correct.
get_headers()

Returns the headers.

get_status()

Returns the status code and message of this response.

send_body(out)

Send the response body to the given output stream.

Parameters:out – the file-like object to print the body to.
send_headers(out)

Send HTTP Headers to the given output stream.

Note

This prints the headers and then the \n\n that separates headers from the body.

Parameters:out – The file-like object to print headers to.
set_status(status)

Sets the status code for this response. The status should be a valid HTTP response status.

Examples:

>>> resp.set_status("200 OK")
>>> resp.set_status("404 Not Found")
Parameters:status – the status string.
douglas.app.blosxom_entry_parser(filename, request)

Parses a .txt entry file.

The first line becomes the title of the entry. Lines after the first line that start with # are metadata lines. After the metadata lines, the remaining lines are the body of the entry.

Parameters:
  • filename – a filename to extract data and metadata from
  • request – a standard request object
Returns:

dict containing parsed data and meta data with the particular file (and plugin)

douglas.app.blosxom_file_list_handler(args)

This is the default handler for getting entries. It takes the request object in and figures out which entries based on the default behavior that we want to show and generates a list of EntryBase subclass objects which it returns.

Parameters:args – dict containing the incoming Request object
Returns:the content we want to render
douglas.app.blosxom_handler(request)

This is the default blosxom handler.

It calls the renderer callback to get a renderer. If there is no renderer, it uses the blosxom renderer.

It calls the pathinfo callback to process the path_info http variable.

It calls the filelist callback to build a list of entries to display.

It calls the prepare callback to do any additional preparation before rendering the entries.

Then it tells the renderer to render the entries.

Parameters:request – the request object.
douglas.app.blosxom_process_path_info(args)

Process HTTP PATH_INFO for URI according to path specifications, fill in data dict accordingly.

The paths specification looks like this:

  • /foo.html and /cat/foo.html - file foo.* in / and /cat
  • /cat - category
  • /2002 - category (if that’s a directory)
  • /2002 - year index
  • /2002/02 - year/month index
  • /2002/02/04 - year/month/day index
Parameters:args – dict containing the incoming Request object
douglas.app.blosxom_sort_list_handler(args)

Sorts the list based on _mtime attribute such that most recently written entries are at the beginning of the list and oldest entries are at the end.

Parameters:args – args dict with request object and entry_list list of entries
Returns:the sorted entry_list
douglas.app.blosxom_truncate_list_handler(args)

If config["num_entries"] is not 0 and data["truncate"] is not 0, then this truncates args["entry_list"] by config["num_entries"].

Parameters:args – args dict with request object and entry_list list of entries
Returns:the truncated entry_list.
douglas.app.douglas_app_factory(global_config, **local_config)

App factory for paste.

Returns:WSGI application
douglas.app.run_cgi(cfg)

Executes Douglas as a CGI script.

douglas.tools

exception douglas.tools.ConfigSyntaxErrorException

Thrown for convert_configini_values syntax errors.

douglas.tools.convert_configini_values(configini)

Takes a dict containing config.ini style keys and values, converts the values, and returns a new config dict.

Parameters:confini – dict containing the config.ini style keys and values
Raises:ConfigSyntaxErrorException – when there’s a syntax error
Returns:new config dict
douglas.tools.create_entry(datadir, category, filename, mtime, title, metadata, body)

Creates a new entry in the blog.

This is primarily used by the testing system, but it could be used by scripts and other tools.

Parameters:
  • datadir – the datadir
  • category – the category the entry should go in
  • filename – the name of the blog entry (filename and extension–no directory)
  • mtime – the mtime (float) for the entry in seconds since the epoch
  • title – the title for the entry
  • metadata – dict of key/value metadata pairs
  • body – the body of the entry
Raises:

IOError – if the datadir + category directory exists, but isn’t a directory

douglas.tools.escape_text(s)

Takes in a string and converts:

  • & to &
  • > to >
  • < to &lt;
  • " to &quot;
  • ' to &#x27;
  • / to &#x2F;

Note: if s is None, then we return None.

1
2
3
4
5
6
7
8
>>> escape_text(None)
None
>>> escape_text("")
""
>>> escape_text("a'b")
"a&#x27;b"
>>> escape_text('a"b')
"a&quot;b"
douglas.tools.filestat(config, filename)

Returns the filestat on a given file.

This returns the mtime of the file (same as returned by time.localtime()) – tuple of 9 ints.

Parameters:
  • config – config
  • filename – the file name of the file to stat
Returns:

the filestat (tuple of 9 ints) on the given file

douglas.tools.get_entries(cfg, root, recurse=0)

Returns a list of all the entries in the root

This only pulls extensions that are registered with entryparsers. This uses the entries callback.

Allows plugins to remove and add items.

FIXME - fix docs

douglas.tools.get_static_files(cfg)

Return a list of (root, file_path) tuples for all static files found.

Parameters:cfg – configuration
Returns:list of (root, file_path) tuples
douglas.tools.importname(modulename, name)

Safely imports modules for runtime importing.

Parameters:
  • modulename – the package name of the module to import from
  • name – the name of the module to import
Returns:

the module object or None if there were problems importing.

douglas.tools.pwrap(s)

Wraps the text and prints it.

douglas.tools.pwrap_error(s)

Wraps an error message and prints it to stderr.

douglas.tools.render_url(cfg, pathinfo, querystring='')

Takes a url and a querystring and renders the page that corresponds with that by creating a Request and a Douglas object and passing it through. It then returns the resulting Response.

Parameters:
  • cfg – the config.py dict
  • pathinfo – the PATH_INFO string; example: /dev/douglas/firstpost.html
  • querystring – the querystring (if any); example: debug=yes
Returns:

a douglas Response object.

douglas.tools.render_url_statically(cfg, url, querystring)

Renders a url and saves the rendered output to the filesystem.

Parameters:
  • cfg – config dict
  • url – url to render
  • querystring – querystring of the url to render or “”
douglas.tools.run_callback(chain, input, mappingfunc=<function <lambda>>, donefunc=<function <lambda>>, defaultfunc=None, cache_key=None)

Executes a callback chain on a given piece of data. passed in is a dict of name/value pairs. Consult the documentation for the specific callback chain you’re executing.

Callback chains should conform to their documented behavior. This function allows us to do transforms on data, handling data, and also callbacks.

The difference in behavior is affected by the mappingfunc passed in which converts the output of a given function in the chain to the input for the next function.

If this is confusing, read through the code for this function.

Returns the transformed input dict.

Parameters:
  • chain – the name of the callback chain to run
  • input – dict with name/value pairs that gets passed as the args dict to all callback functions
  • mappingfunc – the function that maps output arguments to input arguments for the next iteration. It must take two arguments: the original dict and the return from the previous function. It defaults to returning the original dict.
  • donefunc – this function tests whether we’re done doing what we’re doing. This function takes as input the output of the most recent iteration. If this function returns True then we’ll drop out of the loop. For example, if you wanted a callback to stop running when one of the registered functions returned a 1, then you would pass in: donefunc=lambda x: x .
  • defaultfunc – if this is set and we finish going through all the functions in the chain and none of them have returned something that satisfies the donefunc, then we’ll execute the defaultfunc with the latest version of the input dict.
  • cache_key – If the return value for this callback with these arguments can be cached, then this is a function that takes the original input args dict and returns the cache key.
Returns:

varies

douglas.tools.urlencode_text(s)

Calls urllib.quote on the string s.

Note: if s is None, then we return None.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
>>> urlencode_text(None)
None
>>> urlencode_text("")
""
>>> urlencode_text("a c")
"a%20c"
>>> urlencode_text("a&c")
"a%26c"
>>> urlencode_text("a=c")
"a%3Dc"
douglas.tools.walk(request, root='.', recurse=0, pattern='', return_folders=0)

This function walks a directory tree starting at a specified root folder, and returns a list of all of the files (and optionally folders) that match our pattern(s). Taken from the online Python Cookbook and modified to own needs.

It will look at the config “ignore_directories” for a list of directories to ignore. It uses a regexp that joins all the things you list. So the following:

config.py["ignore_directories"] = ["CVS", "dev/douglas"]

turns into the regexp:

.*?(CVS|dev/douglas)$

It will also skip all directories that start with a period.

Parameters:
  • request – Request
  • root – the root directory to walk
  • recurse – the depth of recursion; defaults to 0 which goes all the way down
  • pattern – the regexp object for matching files; defaults to ‘’ which causes douglas to return files with file extensions that match those the entryparsers handle
  • return_folders – True if you want only folders, False if you want files AND folders
Returns:

a list of file paths.

douglas.tools.what_ext(extensions, filepath)

Takes in a filepath and a list of extensions and tries them all until it finds the first extension that works.

Parameters:
  • extensions – the list of extensions to test
  • filepath – the complete file path (minus the extension) to test and find the extension for
Returns:

the extension (string) of the file or None.

douglas.renderers.base

The is the base renderer module. If you were to dislike the blosxom renderer and wanted to build a renderer that used a different templating system, you would extend the RendererBase class and implement the functionality required by the other rendering system.

For examples, look at the BlosxomRenderer and the Renderer in the debug module.

class douglas.renderers.base.Renderer(request, stdoutput=<open file '<stdout>', mode 'w'>)

This is a null renderer.

class douglas.renderers.base.RendererBase(request, stdoutput=<open file '<stdout>', mode 'w'>)

Douglas core handles the Input and Process of the system and passes the result of the process to the Renderers for output. All renderers are child classes of RendererBase. RenderBase will contain the public interfaces for all Renderer onject.

add_header(*args)

Populates the HTTP header with lines of text

Parameters:args – Paired list of headers
Raises:ValueError – This happens when the parameters are not correct
get_content()

Return the content field

This is exposed for blosxom callbacks.

Returns:content
render(render_headers=True)

Do final rendering.

Parameters:render_headers – whether (True) or not (False) to render the headers
set_content(content)

Sets the content. The content can be any of the following:

  • dict
  • list of entries
Parameters:content – the content to be displayed
show_headers()

Updated the headers of the Response<douglas.douglas.Response> instance.

This is here for backwards compatibility.

write(data)

Convenience method for programs to use instead of accessing self._out.write()

Other classes can override this if there is a unique way to write out data, for example, a two stream output, e.g. one output stream and one output log stream.

Another use for this could be a plugin that writes out binary files, but because renderers and other frameworks may probably not want you to write to stdout directly, this method assists you nicely. For example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
def cb_start(args):
    req = args['request']
    renderer = req['renderer']

    if reqIsGif and gifFileExists(theGifFile):
        # Read the file
        data = open(theGifFile).read()

        # Modify header
        renderer.add_header('Content-type', 'image/gif')
        renderer.add_header('Content-Length', len(data))
        renderer.show_headers()

        # Write to output
        renderer.write(data)

        # Tell douglas not to render anymore as data is
        # processed already
        renderer.rendered = 1

This simple piece of pseudocode explains what you could do with this method, though I highly don’t recommend this, unless douglas is running continuously.

Parameters:data – Piece of string you want printed

douglas.entries.base

This module contains the base class for all the Entry classes. The EntryBase class is essentially the API for entries in douglas. Reading through the comments for this class will walk you through building your own EntryBase derivatives.

This module also holds a generic generate_entry function which will generate a BaseEntry with data that you provide for it.

class douglas.entries.base.EntryBase(request)

EntryBase is the base class for all the Entry classes. Each instance of an Entry class represents a single entry in the weblog, whether it came from a file, or a database, or even somewhere off the InterWeeb.

EntryBase derivatives are dict-like.

get_id()

This should return an id that’s unique enough for caching purposes.

Override this.

Returns:string id
set_time(timetuple)

This takes in a given time tuple and sets all the magic metadata variables we have according to the items in the time tuple.

Parameters:timetuple – the timetuple to use to set the data with–this is the same thing as the mtime/atime portions of an os.stat. This time is expected to be local time, not UTC.
douglas.entries.base.generate_entry(request, properties, data, mtime=None)

Takes a properties dict and a data string and generates a generic entry using the data you provided.

Parameters:
  • request – the Request object
  • properties – the dict of properties for the entry
  • data – the data content for the entry
  • mtime – the mtime tuple (as given by time.localtime()). if you pass in None, then we’ll use localtime.