Python Web Service API

The web service API is a collection of Python functions meant to help write web service scripts in as “Pythonic” a way as possible. The functionality is divided into severul areas: core services for generally useful utilities; HTTP interaction, for manipulating request headers, retrieving request bodies, and formatting errors; and web service utilities to supercharge Python services.

Core Services

tangelo.log([context, ]msg)

Writes a message msg to the log file. The optional context is a descriptive tag that will be prepended to the message within the log file (defaulting to “TANGELO” if omitted). Common context tags used internally in Tangelo include “TANGELO” (to describe startup/shutdown activities), and “ENGINE” (which describes actions being taken by CherryPy). This function may be useful for debugging or otherwise tracking a service’s activities as it runs.

tangelo.log_info([context, ]msg)

Variant of tangelo.log() that writes out messages in purple. Informational messages are those that simply declare a helpful description of what the system is doing at the moment. For example, when a plugin is about to perform initialization, a call like tangelo.log_info("FOOBAR", "About to initialize...") may be appropriate.

tangelo.log_warning([context, ]msg)

Variant of tangelo.log() that writes out messages in yellow. Warnings are messages indicating that something did not work out as expected, but not so bad as to compromise the continued running of the system. For example, if Tangelo is unable to load a plugin for any reason, Tangelo itself is able to continue running - this constitutes a warning about the failed plugin loading.

tangelo.log_error([context, ]msg)

Variant of tangelo.log() that writes out messages in red. Errors describe conditions that prevent the further functioning of the system. Generally, you will not need to call this function.

tangelo.log_success([context, ]msg)

Variant of tangelo.log() that writes out messages in green. This is meant to declare that some operation went as expected. It is generally not needed because the absence of errors and warnings can generally be regarded as a success condition.

tangelo.abspath(webpath)

Takes a “web path” and computes a disk path to the referenced file, if it references a location within Tangelo’s legal web space.

The path, passed into argument webpath, must be an absolute web path; i.e., it must begin with a slash. If the second character of the path is a tilde, it will be converted to a user home directory path, while non-tilde paths will resolve to a location within Tangelo’s web root directory.

Path components such as . and .. are resolved to yield a possible absolute disk path; if this path lies outside of the legal web space, then the function returns None; otherwise, it returns this path.

This function is useful for preventing errant paths from allowing a Tangelo service to manipulate files that it shouldn’t, while yielding access to files that are allowed.

For example, /~troi/libs would yield something like /home/troi/tangelo_html/lib, and /section31/common/ would yield something like /srv/tangelo/section31/common because both paths refer to subdirectories of an allowed directory - one in a user’s home directory, and the other under the web root. However, /~picard/../../libs would yield None, since it does not refer to any file accessible via Tangelo.

HTTP Interaction

tangelo.content_type([type])

Returns the content type for the current request, as a string. If type is specified, also sets the content type to the specified string.

tangelo.http_status(code[, message])

Sets the HTTP status code for the current request’s response. code should be an integer; optional message can give a concise description of the code. Omitting it results in a standard message; for instance, tangelo.http_status(404) will send back a status of 404 Not Found.

This function can be called before returning, e.g., a dict describing in detail what went wrong. Then, the response will indicate the general error while the body contains error details, which may be informational for the client, or useful for debugging.

tangelo.header(header_name[, new_value])

Returns the value associated to header_name in the HTTP headers, or None if the header is not present.

If new_value is supplied, the header value will additionally be replaced by that value.

tangelo.request_header(header_name)

Returns the value associated to header_name in the request headers, or None if the header is not present.

tangelo.request_path()

Returns the path of the current request. This is generally the sequence of path components following the domain and port number in a URL.

tangelo.request_body()

Returns a filelike object that streams out the body of the current request. This can be useful, e.g., for retrieving data submitted in the body for a POST request.

tangelo.session(key[, value])

Returns the value currently associated to the session key key, or None if there is no such key. If value is given, it will become newly associated to key.

Web Services Utilities

tangelo.paths(paths)

Augments the Python system path with the list of web directories specified in paths. Each path must be within the web root directory or within a user’s web home directory (i.e., the paths must be legal with respect to tangelo.legal_path()).

This function can be used to let web services access commonly used functions that are implemented in their own Python modules somewhere in the web filesystem.

After a service calling this function returns, the system path will be restored to its original state. This requires calling tangelo.paths() in every function wishing to change the path, but prevents shadowing of expected locations by modules with the same name in other directories, and the uncontrolled growth of the sys.path variable.

tangelo.config()

Returns a copy of the service configuration dictionary (see Configuring Web Services).

@tangelo.restful

Marks a function in a Python service file as being part of that service’s RESTful API. This prevents accidental exposure of unmarked support functions as part of the API, and also enables the use of arbitrary words as REST verbs (so long as those words are also valid Python function names). An example usage might look like the following, which uses a both a standard verb (“GET”) and a custom one (“NORMALIZE”).

import tangelo

@tangelo.restful
def get(foo, bar, baz=None):
    pass

@tangelo.restful
def normalize():
    pass

Note that Tangelo automatically converts the verb used by the web client to all lowercase letters before searching the Python module for a matching function to call.

@tangelo.types(arg1=type1, ..., argN=typeN)

Decorates a service by converting it from a function of several string arguments to a function taking typed arguments. Each argument to tangelo.types() is a function that converts strings to some other type - the standard Python functions int(), float(), and json.loads() are good examples. The functions are passed in as keyword arguments, with the keyword naming an argument in the decorated function. For example, the following code snippet

import tangelo

def stringfunc(a, b):
    return a + b

@tangelo.types(a=int, b=int)
def intfunc(a, b):
    return a + b

print stringfunc("3", "4")
print intfunc("3", "4")

will print:

34
7

stringfunc() performs string concatentation, while intfunc() performs addition on strings that have been converted to integers.

Though the names of the built-in conversion functions make this decorator look like it accepts “types” as arguments, any function that maps strings to any type can be used. For instance, a string representing the current time could be consumed by a function that parses the string and returns a Python datetime object, or, as mentioned above, json.loads() could be used to convert arbitrary JSON data into Python objects.

If an exception is raised by any of the conversion functions, its error message will be passed back to the client via a tangelo.HTTPStatusCode object.

@tangelo.return_type(type)

Similarly to how tangelo.types() works, this decorator can be used to provide a function to convert the return value of a service function to some other type or form. By default, return values are converted to JSON via the standard json.dumps() function. However, this may not be sufficient in certain cases. For example, the bson.dumps() is a function provided by PyMongo that can handle certain types of objects that json.dumps() cannot, such as datetime objects. In such a case, the service module can provide whatever functions it needs (e.g., by importing an appropriate module or package) then naming the conversion function in this decorator.