5 Running Tasks in Python Mode

If that's all there was to it, using PyRAF would be very simple. But we would be missing much of the point of using it, because from CL emulation mode we can't access many of the powerful programming features of the Python language. CL emulation mode may be comfortable for IRAF users, but when the time comes to write new scripts you should learn how to run IRAF tasks using native Python syntax.

Currently there are a number of ways of running tasks and setting parameters. The system is still under development, and depending on user feedback, we may decide to eliminate some of them. Below we identify our preferred methods, which we do not intend to eliminate and which we recommend for writing scripts.

5.1 The PyRAF Interpreter Environment

When the PyRAF system is started using the pyraf command as described previously, the user's commands are actually being passed to an enhanced interpreter environment that allows use of IRAF CL emulation and provides other capabilities beyond those provided by the standard Python interpreter. In fact, when pyraf is typed, a special interpreter is run which is a front end to the Python interpreter. This front-end interpreter handles the translation of CL syntax to Python, command logging, filename completion, shell escapes and the like which are not available in the default Python interpreter.

It is also possible to use PyRAF from a standard Python session, which is typically started by simply typing python at the Unix shell prompt. In that case the simple CL syntax for calling tasks is not available and tab-completion, logging, etc., are not active. For interactive use, the conveniences that come with the PyRAF interpreter are valuable and we expect that most users will use PyRAF in this mode.

One important thing to understand is that the alternate syntax supported by the PyRAF front end interpreter is provided purely for interactive convenience. When such input is logged, it is logged in its translated, Python form. Scripts should always use the normal Python form of the syntax. The advantage of this requirement is that such scripts need no preprocessing to be executed by Python, and so they can be freely mixed with any other Python programs. In summary, if one runs PyRAF in its default mode, the short-cut syntax can be used; but when PyRAF is being used from scripts or from the standard Python interpreter, one must use standard Python syntax (not CL-like syntax) to run IRAF tasks.

Even in Python mode, task and parameter names can be abbreviated and, for the most part, the minimum matching used by IRAF still applies. As described above, when an IRAF task name is identical to a reserved keyword in Python, it is necessary to prepend a 'PY' to the IRAF task name (i.e., use iraf.PYlambda, not iraf.lambda). In Python mode, when task parameters conflict with keywords, they must be similarly modified. The statement iraf.imcalc(in="filename") will generate a syntax error and must be changed either to iraf.imcalc(PYin="filename") or to iraf.imcalc(input="filename"). This keyword/parameter conflict is handled automatically in CL emulation mode.

Some of the differences between the PyRAF interpreter and the regular Python interpreter besides the availability of CL emulation mode:

  PyRAF interpreter  Python default interpreter 
prompt --> >>>
print interpreter help .help n/a
exit interpreter .exit EOF (control-D) or sys.exit()
start logging input .logfile filename n/a
append to log file .logfile filename append n/a
stop logging input .logfile n/a
run system command ! command os.system('command')
start a subshell !! os.system('/bin/sh')

5.2 Example with Standard Python Syntax

This example mirrors the sequence for the example given above in the discussion of CL emulation (§2). In the discussion that follows we explain and illustrate some variants.

% pyraf
--> iraf.imheader("dev$pix", long=yes)
dev$pix[512,512][short]: m51  B  600s
No bad pixels, min=-1., max=19936.
Line storage mode, physdim [512,512], length of user area 1621 s.u.
Created Mon 23:54:13 31-Mar-1997, Last modified Mon 23:54:14 31-Mar-1997
Pixel file "HDR$pix.pix" [ok]
'KPNO-IRAF'           /
'31-03-97'            /
IRAF-MAX=           1.993600E4  /  DATA MAX
IRAF-MIN=          -1.000000E0  /  DATA MIN
IRAF-BPX=                   16  /  DATA BITS/PIXEL
IRAFTYPE= 'SHORT   '            /  PIXEL TYPE
HISTORY '24-04-87'
HISTORY 'KPNO-IRAF'           /
HISTORY '08-04-92'            /
--> iraf.imstat('dev$pix')
#               IMAGE      NPIX      MEAN    STDDEV       MIN       MAX
              dev$pix    261626     105.1     75.86       -1.     1000.
--> iraf.imcopy("dev$pix","mycopy.fits")
--> iraf.stsdas()
      |       Space Telescope Science Data Analysis System         |
      |          STSDAS Version 2.1, September 29, 1999            |
      |                                                            |
      |   Space Telescope Science Institute, Baltimore, Maryland   |
      |         For help, send e-mail to            |
 analysis/      examples        hst_calib/      sobsolete/
 contrib/       fitsio/         playpen/        toolbox/
 describe       graphics/       problems
--> iraf.fitsio()
--> iraf.catfits("mycopy.fits")

0     mycopy.fits                               512x512    16    m51  B  600s
--> iraf.imhead('dev$pix',long=yes,Stdout='devpix.header')

The mapping of IRAF CL syntax to Python syntax is generally quite straightforward. The most notable requirements are:

Another change is that boolean keywords cannot be set using appended + or - symbols. Instead, it is necessary to use the more verbose keyword=value form (e.g., long=yes in the example above). We have defined Python variables yes and no for convenience, but you can also simply say long=1 to set the (abbreviated) longheader keyword to true.

Emulating pipes in Python mode is also relatively simple. If a parameter Stdout=1 is passed to a task, the task output is captured and returned as a list of Python strings, with one string for each line of output. This list can then be processed using Python's sophisticated string utilities, or it can be passed to another task using the Stdin parameter:

--> s = iraf.imhead("dev$pix", long=yes, Stdout=1)
--> print s[0]
dev$pix[512,512][short]: m51  B  600s
--> iraf.head(nl=3, Stdin=s)
dev$pix[512,512][short]: m51  B  600s
No bad pixels, min=-1., max=19936.
Line storage mode, physdim [512,512], length of user area 1621 s.u.

Stdin and Stdout can also be set to a filename or a Python filehandle object to redirect output to or from a file. Stderr is also available for redirection. Note the capital 'S' in these names - it is used to eliminate possible conflicts with task parameter names, but in the future we may decide to simplify these names by eliminating the uppercase 'S'.

5.3 Setting IRAF Task or Package Parameters

Currently there are multiple ways of setting parameters. The most familiar is simply to provide parameters as positional arguments to the task function. For example

--> iraf.imcopy("dev$pix","mycopy.fits")

Alternatively, one can set the same parameters using keyword syntax:

--> iraf.imcopy(input="dev$pix",output="mycopy.fits")

Hidden parameters can only be set in the argument list this way (analogous to IRAF). As in the IRAF CL, the parameter values are learned for non-hidden parameters (depending on the mode parameter settings) but are not learned (i.e., are not persistent) for hidden parameters.

But parameters can also be set by setting task attributes. For example:

--> iraf.imcopy.input = "dev$pix"
--> iraf.imcopy.output = "mycopy.fits"
--> iraf.imcopy()  # run the task with the new values

These attribute names can be abbreviated (don't expect this behavior for most Python objects, it is special for IRAF task objects):

--> iraf.imcopy.inp = "dev$pix"
--> iraf.imcopy.o = "mycopy.fits"

PyRAF is flexible about the types used to specify the parameter so long as the conversion is sensible. For example, one can specify a floating point parameter in any of the following ways:

--> iraf.imstat.binwidth = "33.0"
--> iraf.imstat.binwidth = "33"
--> iraf.imstat.bin      = 33.0
--> iraf.imstat.bin      = 33

but if the following is typed:

--> iraf.imstat.bin = "cow"
Traceback (innermost last):
  File "<console>", line 1, in ?
ValueError: Illegal float value 'cow' for parameter binwidth

An error traceback results. When running in the PyRAF interpreter, a simplified version of the traceback is shown that omits functions that are part of the pyraf package. The .fulltraceback command (which can be abbreviated as can all the executive commands) will print the entire detailed traceback; it will probably only be needed for PyRAF system developers. Python tracebacks can initially appear confusing, but they are very informative once you learn to read them. The entire stack of function calls is shown from top to bottom, with the most recently called function (where the error occurred) listed last. The line numbers and lines of Python code that generated the error are also given.

One can list the parameters for a task using one of the following commands (in addition to the usual IRAF lpar imcopy):

--> iraf.imcopy.lParam()
--> iraf.lpar(iraf.imcopy)      # Note there are no quotation marks
--> iraf.lpar('imcopy')

For those who have encountered object-oriented programming, iraf.imcopy is an 'IRAF task object' that has a method named lParam that lists task parameters. On the other hand, iraf.lpar is a function (in the iraf module) that takes either an IRAF task object or a string name of a task as a parameter. It finds the task object and invokes the .lParam() method.

One can start the EPAR utility for the task using a parallel set of commands:

--> iraf.imcopy.eParam()
--> iraf.epar(iraf.imcopy)
--> iraf.epar('imcopy')

Tasks appear as attributes of packages, with nested packages also found. For example, if you load the stsdas package and the restore subpackage, then the mem task can be accessed through several different means: iraf.mem, iraf.stsdas.mem, or iraf.restore.mem will all work. Ordinarily the simple iraf.mem is used, but if tasks with the same name appear in different packages, it may be necessary to add a package name to ensure the proper version of the task is found.

5.4 Other Ways of Running IRAF Tasks

One way of reducing the typing burden (interactively or in scripts, though perhaps it isn't such a good idea for scripts) is to define an alias for the iraf module after it is loaded. One can simply type:

--> i = iraf
--> i.imcopy('dev$pix','mycopy.fits')
--> i.imstat('mycopy.fits')

But don't use i for a counter variable and then try doing the same! E.g.,

--> i = 1
--> i.imcopy('dev$pix','mycopy.fits')

will give you the following error message

  AttributeError: 'int' object has no attribute 'imcopy'

since the integer '1' has no imcopy attribute.

Questions or comments? Contact
Documented updated on 2002 May 3