Hi Phil,
On Mon, 12 Apr 2004, Phil Hodge wrote:
Why is '**kw' listed as an argument for setVerbose()? No keyword
argument is used, as far as I can tell, and it makes it possible to
make this simple mistake without getting any error or warning:
--> setVerbose (level=2)
It's there so you can invoke setVerbose from the command line using
the simple task syntax, e.g.
---> setVerbose 2
There are various keyword parameters that get passed to tasks. I don't
at the moment recall them all, but I think they include $nargs, maybe
the current iraf package, the redirection keywords Stdin/Stdout/Stderr,
_save (discussed below), and others? To make a Python function usable
as a task, it has to accept all these keywords. But just accepting
**kw without check for erroneous values is indeed very lazy of me.
Probably the right approach here would be to make setVerbose a
hidden function and to wrap it as an IrafPythonTask?. That would
provide the proper task interface and would also check for bad
parameters. It would also check the level parameter for correct
values. I think Warren knows how to do the wrapping (I've almost
forgotten myself.)
There are other similar task-like functions that also ought to
be turned into IrafPythonTasks?. That's been on my to-do list
for a really long time... They may not all be as lazy as setVerbose,
but it would reduce duplicated code to pull out all the stuff
the creates task behavior from individual functions.
In the getParam() method of IrafTask?, the default for prompt is true,
but it only prompts when the parameter is in the par file for the
task, e.g.:
# this prompts:
print iraf.fxheader.getParam("fits_file")
# this doesn't prompt:
print iraf.images.getParam("fxheader.fits_file")
Hmm, seems like the prompt parameter is not getting passed on when
the parameter is nested. Do you know how the CL handles this?
I guess this is bug if the CL prompts in this case.
# exact=1, prompt=1:
--> print iraf.images.getParam("tlcol.t", exact=1, prompt=1)
l61hm1a30_asn.fits[1]
Hmm, so here would you expect the exact flag to be propagated
as well? I guess we get to choose the behavior we want since
the CL has no equivalent of the exact flag.
--> print iraf.tlcol.getParam("t", exact=1, prompt=1)
Traceback (innermost last):
File "<console>", line 1, in ?
IrafError?: Unknown parameter requested: t
--> print iraf.tlcol.getParam("t", exact=0, prompt=1)
name of table ('l61hm1a30_asn.fits[1]'):
l61hm1a30_asn.fits[1]
These are both correct, right?
setParam() updates the running par list (if it exists), but the copy in the
uparm directory does not always get updated. In general, I find the various
par lists rather confusing; I don't know for sure what par list in PyRAF
corresponds to what in IRAF. Default I understand (probably). I thought
the running par list was the one in memory that was held until after a task
ran successfully, and the current par list was the uparm file. But there
are times when the uparm par file is not updated. Here's an example where
uparm$imslistaa.par (and, apparently, at least one of the various par lists)
was not updated:
# uparm par file was not updated:
--> iraf.listarea ("x.fits[1][371:375,290:281]")
Image: x.fits[1][371:375,290:281]
...
--> lpar listarea
input = l61h0000r_03185154012_flt_a.fits[1][8203:8207,519:516] > input image(s)
(pformat = f7.1) > format for printing values
(pagewidth = 132) > page width if output is redirected
(mode = al)
# uparm par file was updated as expected:
--> listarea x.fits[1][371:375,290:281]
Image: x.fits[1][371:375,290:281]
...
--> lpar listarea
input = x.fits[1][371:375,290:281] > input image(s)
(pformat = f7.1) > format for printing values
(pagewidth = 132) > page width if output is redirected
(mode = al)
This one at least I understand and think is correct! There is another one
of those special task keyword parameters, _save, which specifies whether
the parameters are to be saved in the uparm file or not. It is off by
default because when CL tasks are called by other tasks the uparm file is
*not* updated. The command-line interpreter automatically adds _save=1 to
every task call. If you change the first call to:
--> iraf.listarea ("x.fits[1][371:375,290:281]", _save=1)
you will find that the uparm file gets updated as expected. Remember that
you can run in verbose CL compatibility mode to see the Python equivalent
of any CL command:
--> clCompatibilityMode 1 # I always type cl<tab> to figure out the name
Entering CL-compatibility (verbose) mode...
cl>imhead dev$pix
dev$pix[512,512][short]: m51 B 600s
----- Python -----
iraf.imhead('dev$pix', _save=1)
------------------
. and there is the magic _save parameter.
Your description of the various parameter lists is basically correct.
_defaultParList Default parameter values (what you get when you do
unlearn)
_runningParList Parameter values being used for actively running task.
When the task completes this gets copied to _currentParList
and saved to uparm if _save is true. Otherwise it is
discarded.
_currentParList Current values (the defaults that you get when you don't
specify a value for a parameter.)
The _currentParList is generally what is found in the uparm file,
although it is possible to make it disagree with the uparm values. If
you set a parameter explicitly and then exit without running the task,
the uparm file is not changed:
--> iraf.imhead.long = yes
--> lpar imhead
images = dev$pix image names
(imlist = *.imh,*.fits,*.pl,*.qp,*.hhh) default image names
(longheader = yes) print header in multi-line format
(userfields = yes) print the user fields (instrument parameters)
(mode = al)
--> .exit
% pyraf
--> lpar imhead
images = dev$pix image names
(imlist = *.imh,*.fits,*.pl,*.qp,*.hhh) default image names
(longheader = no) print header in multi-line format
(userfields = yes) print the user fields (instrument parameters)
(mode = al)
You do have to work pretty hard to make this uparm mismatch a problem.
If you actually run the task from the command line, things get into
sync again. But if you run it from inside another CL script, it uses
the _currentParList value but does not update uparm. I think that the
CL's behavior in this case is actual very similar if not identical.
I would agree this set of multiple par lists is a bit confusing, but I
think this is the minimally complicated way to replicate the CL's
behavior.
Cheers,
Rick
Hi Phil,
On Mon, 12 Apr 2004, Phil Hodge wrote:
--> setVerbose (level=2)
It's there so you can invoke setVerbose from the command line using
the simple task syntax, e.g.:
---> setVerbose 2
This uses a keyword argument? I thought it would use the value argument.
The signature is 'def setVerbose(value=1, **kw)'.
No, this gets translated to:
iraf.setVerbose(2, _save=1)
So the **kw argument is needed not for the value argument but for the
_save keyword in this case. Similarly, here is another translation:
---> setVerbose 2 > dev$null
becomes:
iraf.setVerbose(2, _save=1, Stdout='dev$null')
# this doesn't prompt:
print iraf.images.getParam("fxheader.fits_file")
Hmm, seems like the prompt parameter is not getting passed on when
the parameter is nested. Do you know how the CL handles this?
I guess this is bug if the CL prompts in this case.
The cl doesn't have this option. I asked for a parameter from fxheader,
using getParam() for an instance of another task. (That was a typo of
mine, though. I meant to specify a task such as imcopy, but I used the
images package name instead.) It's a curious feature to be able to get
a parameter from task x via task y. I expected to be prompted, since
prompt=1, but if that's not the way you want it to work, we can just
say so in the write-up.
I agree that's pretty weird, but I think it must be there because each
task needs a way to get parameter values either from it's own parameter
list or from other tasks. I personally think that it ought to
pass the 'exact' and 'prompt' keywords on to the task in question.
--> print iraf.images.getParam("tlcol.t", exact=1, prompt=1)
l61hm1a30_asn.fits[1]
Hmm, so here would you expect the exact flag to be propagated
as well? I guess we get to choose the behavior we want since
the CL has no equivalent of the exact flag.
It was just a surprise, since I had specified exact=1. I don't understand
why you have this argument and then ignore it.
Well, I don't ignore it for accesses to parameters of this task. But I
do consider it a bug not to pass it on.
This one at least I understand and think is correct! There is another one
of those special task keyword parameters, _save, which specifies whether
the parameters are to be saved in the uparm file or not. It is off by
default because when CL tasks are called by other tasks the uparm file is
*not* updated. The command-line interpreter automatically adds _save=1 to
every task call. If you change the first call to: ...
I recall seeing the _save keyword parameter for the run() method, but I
didn't realize that run() was invoked directly when a task was run using
Python syntax. (more below)
You do have to work pretty hard to make this uparm mismatch a problem.
If you actually run the task from the command line, things get into
sync again.
If I use setParam() to set a parameter in a pset (e.g. pltpar for sgraph),
the new value shows up when I 'lpar pltpar', and it is used correctly
when sgraph is run, but uparm$sttpltpar.par still shows the old value.
That's correct.
But if you run it from inside another CL script, it uses
the _currentParList value but does not update uparm. I think that the
CL's behavior in this case is actual very similar if not identical.
I don't think this is the CL behavior. (but I'd better check) The trick
that the CL pulls on us is that when a task is run as a background job,
any statement that would ordinarily change a task parameter does not
affect the value in the uparm directory. It isn't being in a script that
counts; it's the fact that it's in the background. The reason is to
allow multiple background jobs without collisions, in case one job calls
a task without specifying all the parameters. That's a good reason, but
it doesn't solve the problem (one can have multiple CL sessions just by
using different windows), and it results in obscure and silent failures
in some tasks. For example, if a task runs imgets and then reads the
value from the 'value' parameter, this works fine when run interactively
or from a CL script, but if the script is run in the background the step
to read the value from 'value' simply gets whatever happens to be in the
par file at that time and may have nothing to do with what was in the
image header. I consider this a serious bug in the CL, and I'm not happy
to hear that you are trying to emulate it in PyRAF.
But being in a script does matter too. E.g. if in a CL script you call
imhead('myfile.fits'), then do 'lpar imhead' you will find that the images
parameter for imhead has not been changed. No parameters are learned when
tasks are called from CL scripts. The only learning is at the command line.
(Maybe there are some settings of the mode parameter that change this, I'm
not certain about that.)
It is very hard not to emulate this general behavior in PyRAF. I think
loads of scripts would break if we start learning all the parameters. On
the other hand, maybe it would be possible to have some sort of behavior
where at least the task parameters in memory are allowed to be changed even
if the uparm files do not. This would be a big change and would require
a lot of thought and testing, I think.
Rick