10. Migrating from Karrigell 2.x to 3.y

Although version 3 is a complete rewriting of Karrigell core modules, it is almost fully compatible with previous versions. The two main changes are the way user-defined modules are imported, by a built-in function Import(module_url) ; and the resolution of relative paths in the file system

1 - Configuration

1.1 The configuration files are Python scripts instead of a single .ini file : one for the server, and one for each host. Most configuration options are the same, except that all names have been normalized : lowercase, with underscore between words. For instance, rootDir becomes root_dir - but to reduce incompatibility, "old" names will still be recognized

1.2 The only option that can be configured on the command line is the path of the folder of the server configuration script. All other options like the server port are set in the server or host configuration scripts

1.3 the equivalent of "protected" is not yet implemented

2 - Syntax

2.1 Relative file names

  • os.getcwd() is NOT modified by the framework as in previous versions, because its value is not stable in a multi-threaded environment : you can't rely on it inside scripts
  • the built-in string CWD is the full path of the current script directory
  • the built-in function REL(filename) converts a relative file name to the absolute file name, based on the current script directory
  • for convenience and compatibility with previous versions, the Python built-ins open() and file() convert relative path names to absolute path names based on the current script directory

2.2 Imports

  • to import Python modules located in the standard distribution, use the usual import statement
  • you can also use import for modules located in the directory karrigell/package
  • for user-defined modules inside the application, import can't work reliably in a multi-threaded environment where the value of sys.path can be modified by scripts, and because the sharing of sys.modules at the interpreter level can lead to confusion on module names. Use the built-in function Import() :

    module = Import(url_to_user_defined_module)

  • to make migration simpler, the command-line script karrigell/core/migrate_2_to_3.py will check scripts and report all the cases when import is used to import modules outside of the Python distribution currently installed on the computer

2.3 Include

In Karrigell 2.x, with Include(url), a relative url was resolved relatively to the full url, including function name in ks scripts, arguments etc

In version 3 the resolution is relative to the script url, regardless of any element following it in the url

For instance, in the script ks_script.ks :

Include("header.html")
def myfunc(**kw):
    Include("info.txt")

When the url host/folder/ks_script.ks/myfunc?arg1=val1 is called, the resolution is relative to the script url host/folder/ks_script.ks. Thus :

  • the relative url header.html is resolved to the absolute url host/folder/header.html
  • the relative url info.txt is resolved to the absolute url host/folder/info.txt

2.4 Outputs

  • when a script is executed, it can give specific values to response headers such as Content-type, Set-Cookie etc, and it usually returns data to be printed by the user agent. The HTTP response returned by the server consists of the response line, response headers and data
  • for this reason, sys.stdout can't be used directly inside a script to send the response to the user agent, because the result would be sent BEFORE the response line and headers. The built-in function print can be used for that ; it is internally translated into the built-in function PRINT() which can also be used directly : PRINT(data) is the same as print data
  • internally, this function PRINT accumulates data in a buffer ; when the request is completed, the servers sends the response line, then the response headers, and finally the buffer content
  • to avoid whitespace and line breaks introduced by print or PRINT, use the built-in function STDOUT()

2.5 Environment

A built-in dictionary, ENVIRON, holds the same information as os.environ for CGI scripts

2.6 User management

The built-in function Logout() now erases the session cookies and redirects to the requested page (by default, the script where the function is called). In previous versions it returned a string with a link to the logout script

You must replace all lines like :

if Role():
    print Logout()

with something like:

if Role():
    print '<a href="logout">Logout</a>'

and add a function logout() like this

def logout():
    Logout()

3 - Implementation

3.1 Threading server

The default web server, launched by python Karrigell.py, is a multithreaded server, able to serve long-running scripts without blocking other requests

An alternative, multiprocess server also gives excellent performance

3.2 Session management

Sessions are stored on disk, except if the option persistent_session is set to False (this will not work reliably in multi-threaded environments : if you need this feature, use the asynchronous or monoprocess versions of the server). The life duration of a session in the session database can be configured

3.3 Data types

HEADERS and RESP_HEADERS are instances of email.Message (behave very much like case-insensitive dictionaries)

4 - Web 2.0

4.1 editarea

The Javascript library EditArea is included, to allow on-line script edition. It is used in the Script Editor in the Administration menu, and in case of error or exception in a script, the Debug button gives access to a page where the script can be edited on line

4.2 jQuery

The lightweight JavaScript libraries jQuery and jQueryFileTree are also included. They are used in the Script Editor application in the Administration menu, to browse files without having to reload the whole page