HomePython softwarell.scriptsrul4

ll.scripts.rul4

Script for rendering UL4 templates with database content

Purpose

rul4 is a script that can be used for rendering UL4 templates. Templates have access to Oracle, MySQL, SQLite and Redis databases and can execute system commands.

Options

rul4 supports the following options:

templates

One or more template files. A file named - will be treated as standard input. The first file in the list is the main template, i.e. the one that gets rendered. All templates will be available in the main template as the templates dictionary. The keys are the base names of the files (i.e. foo.ul4 will be templates.foo; stdin will be templates.stdin).

--oracle (false, no, 0, true, yes or 1)

Provide the object oracle to the template or not (see below)?

--sqlite (false, no, 0, true, yes or 1)

Provide the object sqlite to the template or not (see below)?

--mysql (false, no, 0, true, yes or 1)

Provide the object mysql to the template or not (see below)?

--redis (false, no, 0, true, yes or 1)

Provide the object redis to the template or not (see below)?

--system (false, no, 0, true, yes or 1)

Provide the object system to the template or not (see below)?

--load (false, no, 0, true, yes or 1)

Provide the function load to the template or not (see below)?

--compile (false, no, 0, true, yes or 1)

Provide the function compile to the template or not (see below)?

-e, --encoding

The encoding of the templates files (default utf-8)

-w, --whitespace (keep, strip, or smart)

Specifies how to handle whitespace in the template

-D, --define

Defines an additional value that will be available inside the template. -D can be specified multiple times. The following formats are supported:

var

Defines var as an empty string;

var=value

Defines var as the string value;

var:type

Defines var as an empty variable of the type type;

var:type=value

Defines var as a variable of the type type with the value value.

type can be any of the following:

int

value is an integer value.

float

value is a float value.

bool

value is a boolean value. 0, no, false, False or the empty string will be recognized as false and 1, yes, true or True will be recognized as true.

str

value is a string.

oracle

value will be a connection to an Oracle database, e.g.:

-Ddb:oracle=user/pwd@database
sqlite

value is a connection to an SQLite database.

mysql

value is a connection to a MySQL database.

redis

value will be a connection to an Redis database, e.g.:

-Ddb:redis=192.168.123.1:6379/42

The port (i.e. the 6379 in the above value) is optional and defaults to 6379. The database number (i.e. the 42 in the above value) is also optional and defaults to 0.

Template variables

Inside the template the following variables are available (if enabled via the matching options):

templates

A dictionary containing all the templates specified on the command line.

encoding

The output encoding.

system

An object with an execute method that executes system commands and returns their output, e.g. the template:

<?print system.execute("whoami")?>

will output the user name.

oracle

An object with a connect method that returns a connection to an oracle database.

mysql

An object with a connect method that return a MySQL connection for the MySQL connect strings passed in. A MySQL connect string is a string of the form user/pwd@host/db.

sqlite

An object with a connect method that return a SQLite connection for the connect strings passed in. The connect string will be passed directly to sqlite3.connect.

redis

An object with a connect method that return a Redis connection for the connect strings passed in. The connectstring is of the form hostname:port/db. port and db are optional.

load

load is a function that reads a file from disk and returns the content. Its first parameter is the filename and its second parameter is the encoding of the file. The encoding parameter is optional and defaults to "utf-8":

<?code data = load("/home/user/data.txt", "iso-8859-1")?>
compile

compile is a function that compiles a string into an UL4 template. The signature is:

compile(source, name=None, whitespace="keep",
        signature=None, startdelim="<?", enddelim="?>")
error

error is a function that can be called to output an error message and abort template execution. The signature is:

error(message, ast=None)

message is the error message and ast can be an AST node from an UL4 template syntax tree to print an error message that originates from that node.

All variables defined via the -D/--define option will also be available. (Note that you can't overwrite any of the predefined variables).

Database connections

All connection objects (except redis) have a query method that executes the query passed in and returns an iterator over the resulting records. This query method requires at least one positional argument. Arguments alternate between fragments of the SQL query and parameters that will be embedded in the query. For example:

<?code db = oracle.connect("user/pwd@db")?>
<?code name = "Bob"?>
<?for p in db.query("select * from person where firstname=", name, " or lastname=", name)?>
   ...

The records returned from query are dict-like objects mapping field names to field values.

Connection objects also have an execute method that supports the same parameters as query but doesn't return an iterable result. This can be used to call functions or procedures.

Calling functions or procedures with out parameters can be done with variable objects that can be created with the methods int, number, str, clob and date. The resulting value of the out parameter is available from the value attribute of the variable object. The following example creates a function, calls it to get at the result and drops it again:

<?code db = oracle.connect('user/pwd@database')?>
<?code db.execute('''
   create or replace function ul4test(p_arg integer)
   return integer
   as
   begin
      return 2*p_arg;
   end;
''')?>
<?code vout = db.int()?>
<?code db.execute('begin ', vout, ' := ul4test(42); end;')?>
<?print vout.value?>
<?code db.execute('drop function ul4test')?>

Redis connections have a get and a put method:

<?code db = redis.connect("192.168.123.42/1")?>
<?code value = db.get("key")?>
<?if isnone(value)?>
   <?code value = "foobar"?>
   <?code db.put("key", value, timedelta(seconds=10*60))?>
<?end if?>

The timeout value in the put method is optional. Without it the value will be stored indefinitely.

Example

This example shows how to connect to an Oracle database and output the content of a person table into an XML file.

Suppose we have a database table that looks like this:

create table person
(
   id integer not null,
   firstname varchar2(200),
   lastname varchar2(200)
);

Then we can use the following template to output the table into an XML file:

<?xml version='1.0' encoding='utf-8'?>
<?code db = oracle.connect("user/pwd@database')?>
<persons>
   <?for p in db.query("select id, firstname, lastname from person order by 2, 1")?>
      <person id="<?printx p.id?>">
         <firstname><?printx p.firstname?></firstname>
         <lastname><?printx p.lastname?></lastname>
      </person>
   <?end for?>
</persons>

If we put the template into the file person.ul4 we can call rul4 like this:

rul4 person.ul4 >person.xml

We could also pass the connection to our database via the -D option and disallow the script to make any database connections itself or execute any system commands:

rul4 person.ul4 -Ddb:oracle=user/pwd@database --oracle=0 --sqlite=0 --mysql=0 --redis=0 --system=0 >person.xml

Then the template could use the Oracle connection object db directly.

class System​(object):

def execute​(self, cmd):

def load​(filename, encoding='utf-8'):

def compile​(source, name=None, whitespace='keep', signature=None, startdelim='<?', enddelim='?>'):

def error​(message, ast=None):

class Var​(object):

def __init__​(self, value=None):

def ul4setattr​(self, name, value):

def makevar​(self, *args, **kwargs):

class Connection​(object):

def __init__​(self, connection):

def _execute​(self, cursor, queryparts):

def query​(self, *queryparts):

def execute​(self, *queryparts):

def str​(self, *args, **kwargs):

def clob​(self, *args, **kwargs):

def int​(self, *args, **kwargs):

def number​(self, *args, **kwargs):

def date​(self, *args, **kwargs):

class OracleConnection​(Connection):

class IntVar​(Var):

def makevar​(self, c):

class NumberVar​(Var):

def makevar​(self, c):

class StrVar​(Var):

def makevar​(self, c):

class CLOBVar​(Var):

def makevar​(self, c):

class DateVar​(Var):

def makevar​(self, c):

def __repr__​(self):

def str​(self, value=None):

def clob​(self, value=None):

def int​(self, value=None):

def number​(self, value=None):

def date​(self, value=None):

class Oracle​(object):

def connect​(self, connectstring):

class SQLite​(object):

def connect​(self, connectstring):

class MySQL​(object):

def connect​(self, connectstring):

class RedisConnection​(object):

def __init__​(self, host, port, db):

def get​(self, key):

def set​(self, key, data, timeout=None):

class Redis​(object):

def connect​(self, connectstring):

def fixname​(name):

def define​(arg):

def main​(args=None):

Alternate versions   Text   XIST   Python