Chapter 19. Using Python

Python commands can be used where A-A-P commands are not sufficient. This includes conditionally executing of commands, repeating commands for a list of items and much more.

PYTHON EXPRESSION:

Python expressions can be embedded in many places.  They are specified in
backticks.

The result should be a string or a list of strings.  A list is automatically
converted to a white-separated string of all list items.

A Python expression cannot be used for the variable name in an assignment.
This doesn't work:

	`varname` = value

Use this instead:

	@eval(varname + ' = "value"')

When using a function from a module, it must be imported first.  Example:

	@from glob import glob
	SOURCE = `glob('*.c')`

However, for your convenience these things are imported for you already:
	from glob import glob

A backtick in the Python expression has to be doubled to avoid it being
recognized as the end of the expression:

	CMD = `my_func("``grep -l foo *.c``")`

contains the Python expression:

	my_func("`grep -l foo *.c`")

Note that a following attribute is only attached to the last item resulting
from the Python expression.

	SOURCE = `glob('*.c')` {check = md5}

Can be equivalent to:

	SOURCE = foo.c bar.c {check = md5}

To apply it to all items, use parenthesis

	SOURCE = (`glob('*.c')`) {check = md5}

Can be equivalent to:

	SOURCE = (foo.c bar.c) {check = md5}
or:
	SOURCE = foo.c {check = md5} bar.c {check = md5}


Backtick expressions and $VAR can be used inside a string:

	DIR = /home/foo /home/bar
	:print "`DIR + "/fi le"`"
results in:
	"/home/foo /home/bar/fi le"

Compare this to:
	:print "$*DIR/fi le"
which results in:

In the result of the Python expression a $ is changed to $$, so that it's not
used for a variable name.  The $$ is reduced to $ again when evaluating the
whole expression.


USEFUL PYTHON ITEMS:

	VAR = `os.environ.get('VAR', 'default')`

Obtain environment variable $VAR.  If it is not set use "default".

	@os.environ["PATH"] = mypath

Set an environment variable.

	files = `glob("*.ext")`

Obtain a list of files matching "*.ext".  A-A-P will take care of turning the
list that glob() returns into a string, using quotes where needed.

	choice = `raw_input("Enter the value: ")`

Prompt the user to enter a value.

	tempfile = `tempfname()`

Get a file name to use for temporary files.  The file will not exist.  If you
create it you need to make sure it is deleted afterwards.


AAP PYTHON FUNCTIONS:

These functions can be used in Python code:

aap_sufreplace(from, to, expr)
			Returns "expr" with all occurences of the suffix
			"from" changed to "to".
			When "from" is empty any suffix is changed to "to".
			"expr" can be a list of file names.
			Example:
				OBJECT = `aap_sufreplace("", OBJSUF, SOURCE)`

aap_abspath(expr)	Returns "expr" with all file names turned into
			absolute paths.  Prepends the current directory to
			each item in "expr" which isn't an absolute path name.
			Example:
				:print `aap_abspath("foo bar")`
			results in:
				/home/mool/test/foo /home/mool/test/bar

string = src2obj(dict, source)
			Transform a string, which is a list of source files,
			into the corresponding list of object files.  Each
			item in "source" is change by prepending $BDIR and
			changing or appending the suffix to $OBJSUF.
			"dict" is used to obtain the value of $BDIR and
			$OBJSUF from, normally "globals()" can be used:

				OBJECT = `src2obj(globals(), SOURCE)`

program_path(name)
			Returns the path for program "name".  This uses the
			$PATH environment variable or os.defpath if it isn't
			set.
			On MS-Windows and OS/2 also checks with these
			extensions added: ".exe", ".com", ".bat", ".cmd".
			When "name" includes a suffix (a dot in the last
			component) adding extensions is not done.
			Returns the first program found.
			Returns None when "name" could not be found.
			Optional arguments:
			path		search path to use instead of $PATH;
					when a string items are separated with
					os.pathsep
			pathext		extensions to try; when a string
					items are separated with os.pathsep
			skip		name of directory to skip searching
			Example, search for program "foo.py" and "foo.sh":

		p = `program_path("foo", pathext = [ '.py', '.sh' ])`

redir_system(recdict, cmd [, use_tee])
			Execute shell commands "cmd" and return two items: a
			number indicating success and the stdout.  The
			"recdict" argument should be obtained with
			"globals()".  By default "tee" is used to display the
			output as well as redirecting it.  When no output is
			desired set "use_tee" to zero.  Example:

			  ok, text = redir_system(globals(), "ls", 0)
			  if ok:
			       print "ls output: %s" % text
			  else:
			       print "ls failed"

list = sort_list(list)
			sorts a list and returns the list.  Example:

				INP = `sort_list(glob("*.inp"))`

list = var2list(var)	Turns a variable with a string value into a list of
			items.  Attributes are ignored.  Example:

				source = file1 file2 file3
				@for fname in var2list(source):
					:sys prog $fname

list = var2dictlist(var)
			Turns a variable with a string value into a list of
			dictionaries.  Each dictionary has a "name" entry for
			item itself and other entries are attributes.
			Example:

				source = file1 {force} file2 file3
				@for item in var2dictlist(source):
				@    if item.get("force"):
					:print forced item: `item["name"]`

string = file2string(fname [, dict])
			Reads the file "fname" and concatenates the lines into
			one string.  Lines starting with a '#' are ignored.
			One space is inserted in between joined lines, other
			white space at the start and end of a line is removed.
			When "fname" doesn't exist or can't be read an error
			message is given and an empty string is returned.
			"dict" is used to obtain the value for $MESSAGE.
			The default is None.

has_target(dict, target)
			Returns:
				0	no dependency for "target"
				1	dependency for "target" exists
				2	dependency for "target" exists and has
					build commands
			"dict" is the dictionary of the environment, normally
			globals():

				@if not has_target(globals(), "fetch"):

tempfname()		Returns the name of a file which does not exist and
			can be used temporarily.


PYTHON BLOCK:

A block of Python commands is started with a ":python" command.  Optionally
a terminator string may be specified.  This cannot contain white space.  A
comment may follow.  If no terminator string is specified the python code ends
where the indent is equal to or less than the ":python" command.  Otherwise
the Python block continues until the terminator string is found in a line by
itself.  It may be preceded and followed by white space and a comment may
follow.
 
	SOURCE = foo.c bar.c
	:python
	    for i in items:
		SOURCE = SOURCE + " " + i
	...
	:python EOF
    INCLUDE = glob("include/*.c")
    		EOF