Package pyraf :: Module iraffunctions
[hide private]
[frames] | no frames]

Source Code for Module pyraf.iraffunctions

   1  """module iraffunctions.py -- IRAF emulation tasks and functions 
   2   
   3  This is not usually used directly -- the relevant public classes and 
   4  functions get included in iraf.py.  The implementations are kept here 
   5  to avoid possible problems with name conflicts in iraf.py (which is the 
   6  home for all the IRAF task and package names.)  Private routines have 
   7  names beginning with '_' and do not get imported by the iraf module. 
   8   
   9  The exception is that iraffunctions can be used directly for modules 
  10  that must be compiled and executed early, before the pyraf module 
  11  initialization is complete. 
  12   
  13  $Id: iraffunctions.py 1463 2011-06-24 22:58:30Z stsci_embray $ 
  14   
  15  R. White, 2000 January 20 
  16  """ 
  17  from __future__ import division 
  18   
  19  # define INDEF, yes, no, EOF, Verbose, IrafError, userIrafHome 
  20   
  21  from stsci.tools.irafglobals import * 
  22  from subproc import SubprocessError 
23 24 # ----------------------------------------------------- 25 # setVerbose: set verbosity level 26 # ----------------------------------------------------- 27 28 -def setVerbose(value=1, **kw):
29 """Set verbosity level when running tasks. 30 Level 0 (default) prints almost nothing. 31 Level 1 prints warnings. 32 Level 2 prints info on progress. 33 This accepts **kw so it can be used on the PyRAF command-line. This 34 cannot avail itself of the decorator which wraps redirProcess since it 35 needs to be defined here up front. 36 """ 37 if isinstance(value,(str,unicode)): 38 try: 39 value = int(value) 40 except ValueError: 41 pass 42 Verbose.set(value)
43
44 -def _writeError(msg):
45 """Write a message to stderr""" 46 _sys.stdout.flush() 47 _sys.stderr.write(msg) 48 if msg[-1:] != "\n": _sys.stderr.write("\n")
49 50 51 # ----------------------------------------------------- 52 # now it is safe to import other iraf modules 53 # ----------------------------------------------------- 54 55 import sys, os, string, re, math, struct, types, time, fnmatch, glob, tempfile 56 import linecache 57 from stsci.tools import minmatch, irafutils, teal 58 import numpy 59 import subproc, wutil 60 import irafnames, irafinst, iraftask, irafpar, irafexecute, cl2py 61 import iraf 62 import gki 63 import irafecl 64 try: 65 import sscanf 66 except: 67 if 0==sys.platform.find('win'): # not on win*, but IS on darwin & cygwin 68 sscanf = None 69 else: 70 raise 71 72 try: 73 import cPickle 74 pickle = cPickle 75 except ImportError: 76 import pickle 77 78 try: 79 import cStringIO 80 StringIO = cStringIO 81 del cStringIO 82 except ImportError: 83 import StringIO 84 85 # hide these modules so we can use 'from iraffunctions import *' 86 _sys = sys 87 _os = os 88 _string = string 89 _re = re 90 _math = math 91 _struct = struct 92 _types = types 93 _time = time 94 _fnmatch = fnmatch 95 _glob = glob 96 _tempfile = tempfile 97 _linecache = linecache 98 _StringIO = StringIO 99 _pickle = pickle 100 101 _numpy = numpy 102 _minmatch = minmatch 103 _teal = teal 104 _subproc = subproc 105 _wutil = wutil 106 107 _irafnames = irafnames 108 _irafutils = irafutils 109 _irafinst = irafinst 110 _iraftask = iraftask 111 _irafpar = irafpar 112 _irafexecute = irafexecute 113 _cl2py = cl2py 114 115 del sys, os, string, re, math, struct, types, time, fnmatch, glob, linecache 116 del StringIO, pickle, tempfile 117 del numpy, minmatch, subproc, teal, wutil 118 del irafnames, irafutils, irafinst, iraftask, irafpar, irafexecute, cl2py 119 120 # Number of bits per long 121 BITS_PER_LONG = _struct.calcsize('l') * 8 # is 64 on a 64-bit machine 122 123 # FP_EPSILON is the smallest number such that: 1.0 + epsilon > 1.0; Use None 124 # in the finfo ctor to make it use the default precision for a Python float. 125 FP_EPSILON = _numpy.finfo(None).eps 126 127 # ----------------------------------------------------- 128 # private dictionaries: 129 # 130 # _varDict: dictionary of all IRAF cl variables (defined with set name=value) 131 # _tasks: all IRAF tasks (defined with task name=value) 132 # _mmtasks: minimum-match dictionary for tasks 133 # _pkgs: min-match dictionary for all packages (defined with 134 # task name.pkg=value) 135 # _loaded: loaded packages 136 # ----------------------------------------------------- 137 138 # Will want to enhance this to allow a "bye" function that unloads packages. 139 # That might be done using a stack of definitions for each task. 140 141 _varDict = {} 142 _tasks = {} 143 _mmtasks = _minmatch.MinMatchDict() 144 _pkgs = _minmatch.MinMatchDict() 145 _loaded = {} 146 147 # ----------------------------------------------------- 148 # public variables: 149 # 150 # loadedPath: list of loaded packages in order of loading 151 # Used as search path to find fully qualified task name 152 # ----------------------------------------------------- 153 154 loadedPath = [] 155 156 # cl is the cl task pointer (frequently used because cl parameters 157 # are always available) 158 159 cl = None 160 161 162 # ----------------------------------------------------- 163 # help: implemented in irafhelp.py 164 # ----------------------------------------------------- 165 166 from irafhelp import help
167 168 # ----------------------------------------------------- 169 # Init: basic initialization 170 # ----------------------------------------------------- 171 172 # This could be executed automatically when the module first 173 # gets imported, but that would not allow control over output 174 # (which is available through the doprint and hush parameters.) 175 176 -def Init(doprint=1,hush=0,savefile=None):
177 """Basic initialization of IRAF environment""" 178 global _pkgs, cl 179 if savefile is not None: 180 restoreFromFile(savefile,doprint=doprint) 181 return 182 if len(_pkgs) == 0: 183 try: 184 iraf = _os.environ['iraf'] 185 arch = _os.environ['IRAFARCH'] 186 except KeyError: 187 # iraf or IRAFARCH environment variable not defined 188 # try to get them from cl startup file 189 try: 190 d = _getIrafEnv() 191 for key, value in d.items(): 192 if not _os.environ.has_key(key): 193 _os.environ[key] = value 194 iraf = _os.environ['iraf'] 195 arch = _os.environ['IRAFARCH'] 196 except IOError: 197 raise SystemExit(""" 198 Your iraf and IRAFARCH environment variables are not defined and could not 199 be determined from /usr/local/bin/cl. Before starting pyraf, define them 200 by doing (for example) 201 setenv iraf /usr/local/iraf/ 202 setenv IRAFARCH redhat 203 at the Unix command line. The values will depend on your IRAF installation. 204 """) 205 206 #stacksize problem on linux 207 208 if arch == 'redhat' or \ 209 arch == 'linux' or \ 210 arch == 'linuxppc' or \ 211 arch == 'suse': 212 import resource 213 if resource.getrlimit(resource.RLIMIT_STACK)[1]==-1 : 214 resource.setrlimit(resource.RLIMIT_STACK,(-1,-1)) 215 else: 216 pass 217 else: 218 pass 219 220 # ensure trailing slash is present 221 iraf = _os.path.join(iraf,'') 222 host = _os.environ.get('host', _os.path.join(iraf,'unix','')) 223 hlib = _os.environ.get('hlib', _os.path.join(host,'hlib','')) 224 tmp = _os.environ.get('tmp', '/tmp/') 225 set(iraf = iraf) 226 set(host = host) 227 set(hlib = hlib) 228 set(tmp = tmp) 229 if arch and arch[0] != '.': arch = '.' + arch 230 set(arch = arch) 231 global userIrafHome 232 set(home = userIrafHome) 233 234 # define initial symbols 235 if _irafinst.EXISTS: 236 clProcedure(Stdin='hlib$zzsetenv.def') 237 238 # define clpackage 239 global clpkg 240 clpkg = IrafTaskFactory('', 'clpackage', '.pkg', 'hlib$clpackage.cl', 241 'clpackage', 'bin$') 242 243 # add the cl as a task, because its parameters are sometimes needed, 244 # but make it a hidden task 245 # cl is implemented as a Python task 246 cl = IrafTaskFactory('','cl','','cl$cl.par','clpackage','bin$', 247 function=_clProcedure) 248 cl.setHidden() 249 250 # load clpackage 251 clpkg.run(_doprint=0, _hush=hush, _save=1) 252 253 if access('login.cl'): 254 fname = _os.path.abspath('login.cl') 255 elif access('home$login.cl'): 256 fname = 'home$login.cl' 257 elif not _irafinst.EXISTS: 258 fname = _irafinst.getNoIrafClFor('login.cl', useTmpFile=True) 259 else: 260 fname = None 261 262 if fname: 263 # define and load user package 264 userpkg = IrafTaskFactory('', 'user', '.pkg', fname, 265 'clpackage', 'bin$') 266 userpkg.run(_doprint=0, _hush=hush, _save=1) 267 else: 268 _writeError("Warning: no login.cl found") 269 270 # make clpackage the current package 271 loadedPath.append(clpkg) 272 if doprint: listTasks('clpackage')
273
274 -def _getIrafEnv(file='/usr/local/bin/cl',vars=('IRAFARCH','iraf')):
275 """Returns dictionary of environment vars defined in cl startup file""" 276 if not _irafinst.EXISTS: 277 return {'iraf': '/iraf/is/not/here/', 'IRAFARCH': 'arch_is_unused'} 278 if not _os.path.exists(file): 279 raise IOError("CL startup file %s does not exist" % file) 280 lines = open(file,'r').readlines() 281 # replace commands that exec cl with commands to print environment vars 282 pat = _re.compile(r'^\s*exec\s+') 283 newlines = [] 284 nfound = 0 285 for line in lines: 286 if pat.match(line): 287 nfound += 1 288 for var in vars: 289 newlines.append('echo "%s=$%s"\n' % (var, var)) 290 newlines.append('exit 0\n') 291 else: 292 newlines.append(line) 293 if nfound == 0: 294 raise IOError("No exec statement found in script %s" % file) 295 # write new script to temporary file 296 (fd, newfile) = _tempfile.mkstemp() 297 _os.close(fd) 298 f = open(newfile, 'w') 299 f.writelines(newlines) 300 f.close() 301 _os.chmod(newfile,0700) 302 # run new script and capture output 303 fh = _StringIO.StringIO() 304 status = clOscmd(newfile,Stdout=fh) 305 if status: 306 raise IOError("Execution error in script %s (derived from %s)" % 307 (newfile, file)) 308 _os.remove(newfile) 309 result = fh.getvalue().split('\n') 310 fh.close() 311 # extract environment variables from the output 312 d = {} 313 for entry in result: 314 if entry.find('=') >= 0: 315 key, value = entry.split('=',1) 316 d[key] = value 317 return d
318 319 # module variables that don't get saved (they get 320 # initialized when this module is imported) 321 322 unsavedVars = [ 323 'BITS_PER_LONG', 324 'EOF', 325 'FP_EPSILON', 326 'IrafError', 327 'SubprocessError', 328 '_NullFileList', 329 '_NullPath', 330 '__builtins__', 331 '__doc__', 332 '__package__', 333 '__file__', 334 '__name__', 335 '__re_var_match', 336 '__re_var_paren', 337 '_badFormats', 338 '_backDir', 339 '_clearString', 340 '_denode_pat', 341 '_exitCommands', 342 '_nscan', 343 '_fDispatch', 344 '_radixDigits', 345 '_re_taskname', 346 '_reFormat', 347 '_sttyArgs', 348 '_tmpfileCounter', 349 '_clExecuteCount', 350 '_unsavedVarsDict', 351 'IrafTask', 352 'IrafPkg', 353 'cl', 354 'division', 355 'epsilon', 356 'iraf', 357 'no', 358 'yes', 359 'userWorkingHome', 360 ] 361 _unsavedVarsDict = {} 362 for v in unsavedVars: _unsavedVarsDict[v] = 1 363 del unsavedVars, v
364 365 # there are a few tricky things here: 366 # 367 # - I restore userIrafHome, which therefore can be inconsistent with 368 # with the IRAF environment variable. 369 # 370 # - I do not restore userWorkingHome, so it always tells where the 371 # user actually started this pyraf session. Is that the right thing 372 # to do? 373 # 374 # - I am restoring the INDEF object, which means that there could be 375 # multiple versions of this supposed singleton floating around. 376 # I changed the __cmp__ method for INDEF so it produces 'equal' 377 # if the two objects are both INDEFs -- I hope that will take care 378 # of any possible problems. 379 380 -def saveToFile(savefile, **kw):
381 """Save IRAF environment to pickle file 382 383 savefile may be a filename or a file handle. 384 Set clobber keyword (or CL environment variable) to overwrite an 385 existing file. 386 """ 387 if hasattr(savefile, 'write'): 388 fh = savefile 389 390 if hasattr(savefile, 'name'): 391 savefile = fh.name 392 doclose = 0 393 else: 394 # if clobber is not set, do not overwrite file 395 savefile = Expand(savefile) 396 if (not kw.get('clobber')) and envget("clobber","") != yes and _os.path.exists(savefile): 397 raise IOError("Output file `%s' already exists" % savefile) 398 # open binary pickle file 399 fh = open(savefile,'wb') 400 doclose = 1 401 # make a shallow copy of the dictionary and edit out 402 # functions, modules, and objects named in _unsavedVarsDict 403 gdict = globals().copy() 404 for key in gdict.keys(): 405 item = gdict[key] 406 if isinstance(item, (_types.FunctionType, _types.ModuleType)) or \ 407 _unsavedVarsDict.has_key(key): 408 del gdict[key] 409 # print('\n\n\n',gdict.keys()) # DBG: debug line 410 # save just the value of Verbose, not the object 411 global Verbose 412 gdict['Verbose'] = Verbose.get() 413 p = _pickle.Pickler(fh,1) 414 p.dump(gdict) 415 if doclose: 416 fh.close()
417
418 419 -def restoreFromFile(savefile, doprint=1, **kw):
420 """Initialize IRAF environment from pickled save file (or file handle)""" 421 if hasattr(savefile, 'read'): 422 fh = savefile 423 if hasattr(savefile, 'name'): 424 savefile = fh.name 425 doclose = 0 426 else: 427 savefile = Expand(savefile) 428 fh = open(savefile, 'rb') 429 doclose = 1 430 u = _pickle.Unpickler(fh) 431 dict = u.load() 432 if doclose: 433 fh.close() 434 435 # restore the value of Verbose 436 437 global Verbose 438 Verbose.set(dict['Verbose']) 439 del dict['Verbose'] 440 441 # replace the contents of loadedPath 442 global loadedPath 443 loadedPath[:] = dict['loadedPath'] 444 del dict['loadedPath'] 445 446 # update the values 447 globals().update(dict) 448 449 # replace INDEF everywhere we can find it 450 # this does not replace references in parameters, unfortunately 451 INDEF = dict['INDEF'] 452 from stsci.tools import irafglobals 453 import __main__ 454 import pyraf 455 import iraf, irafpar, cltoken 456 for module in (__main__, pyraf, iraf, irafpar, irafglobals, cltoken): 457 if hasattr(module,'INDEF'): module.INDEF = INDEF 458 459 # replace cl in the iraf module (and possibly other locations) 460 global cl 461 _addTask(cl) 462 463 if doprint: listCurrent()
464
465 466 # ----------------------------------------------------- 467 # _addPkg: Add an IRAF package to the pkgs list 468 # ----------------------------------------------------- 469 470 -def _addPkg(pkg):
471 """Add an IRAF package to the packages list""" 472 global _pkgs 473 name = pkg.getName() 474 _pkgs.add(name,pkg) 475 # add package to global namespaces 476 _irafnames.strategy.addPkg(pkg) 477 # packages are tasks too, so add to task lists 478 _addTask(pkg)
479
480 481 # ----------------------------------------------------- 482 # _addTask: Add an IRAF task to the tasks list 483 # ----------------------------------------------------- 484 485 -def _addTask(task, pkgname=None):
486 """Add an IRAF task to the tasks list""" 487 global _tasks, _mmtasks 488 name = task.getName() 489 if not pkgname: pkgname = task.getPkgname() 490 fullname = pkgname + '.' + name 491 _tasks[fullname] = task 492 _mmtasks.add(name,fullname) 493 # add task to global namespaces 494 _irafnames.strategy.addTask(task) 495 # add task to list for its package 496 getPkg(pkgname).addTask(task,fullname)
497
498 499 # -------------------------------------------------------------------------- 500 # Use decorators to consolidate repeated code used in command-line functions. 501 # (09/2009) 502 # These decorator functions are not the simplest form in that they each also 503 # define a function (the actual wrapper) and return that function. This 504 # is needed to get to both the before and after parts of the target. This 505 # approach was performance tested to ensure that PyRAF functionality would 506 # not suffer for the sake of code maintainability. The results showed (under 507 # Python 2.4/.5/.6) that performance can be degraded (by 65%) for only the very 508 # simplest target function (e.g. "pass"), but that for functions which take 509 # any amount of time to do their work (e.g. taking 0.001 sec), the performance 510 # degradation is effectively unmeasurable. This same approach can be done 511 # with a decorator class instead of a decorator function, but the performance 512 # degradation is always greater by a factor of at least 3. 513 # 514 # These decorators could all be combined into a single function with arguments 515 # deciding their different capabilities, but that would add another level (i.e. 516 # a function within a function within a function) and for the sake of simplicity 517 # and robustness as we move into Py3K, we'll write them out separately for now. 518 # -------------------------------------------------------------------------- 519 520 -def handleRedirAndSaveKwds(target):
521 """ This decorator is used to consolidate repeated code used in 522 command-line functions, concerning standard pipe redirection. 523 Typical 'target' functions will: take 0 or more positional arguments, 524 take NO keyword args (except redir's & _save), and return nothing. 525 """ 526 # create the wrapper function here which handles the redirect keywords, 527 # and return it so it can replace 'target' 528 def wrapper(*args, **kw): 529 # handle redirection and save keywords 530 redirKW, closeFHList = redirProcess(kw) 531 if kw.has_key('_save'): del kw['_save'] 532 if len(kw): 533 raise TypeError('unexpected keyword argument: ' + `kw.keys()`) 534 resetList = redirApply(redirKW) 535 try: 536 # call 'target' to do the interesting work of this function 537 target(*args) 538 finally: 539 rv = redirReset(resetList, closeFHList) 540 return rv
541 # return wrapper so it can replace 'target' 542 return wrapper 543
544 -def handleRedirAndSaveKwdsPlus(target):
545 """ This decorator is used to consolidate repeated code used in 546 command-line functions, concerning standard pipe redirection. 547 Typical 'target' functions will: take 0 or more positional arguments, 548 take AT LEAST ONE keyword arg (not including redir's & _save), and 549 return nothing. 550 """ 551 # create the wrapper function here which handles the redirect keywords, 552 # and return it so it can replace 'target' 553 def wrapper(*args, **kw): 554 # handle redirection and save keywords 555 redirKW, closeFHList = redirProcess(kw) 556 if kw.has_key('_save'): del kw['_save'] 557 # the missing check here on len(kw) is the main difference between 558 # this and handleRedirAndSaveKwds (also the sig. of target()) 559 resetList = redirApply(redirKW) 560 try: 561 # call 'target' to do the interesting work of this function 562 target(*args, **kw) 563 finally: 564 rv = redirReset(resetList, closeFHList) 565 return rv
566 # return wrapper so it can replace 'target' 567 return wrapper 568
569 570 # ----------------------------------------------------- 571 # addLoaded: Add an IRAF package to the loaded pkgs list 572 # ----------------------------------------------------- 573 574 # This is public because Iraf Packages call it to register 575 # themselves when they are loaded. 576 577 -def addLoaded(pkg):
578 """Add an IRAF package to the loaded pkgs list""" 579 global _loaded 580 _loaded[pkg.getName()] = len(_loaded)
581
582 # ----------------------------------------------------- 583 # load: Load an IRAF package by name 584 # ----------------------------------------------------- 585 586 -def load(pkgname,args=(),kw=None,doprint=1,hush=0,save=1):
587 """Load an IRAF package by name""" 588 if isinstance(pkgname,_iraftask.IrafPkg): 589 p = pkgname 590 else: 591 p = getPkg(pkgname) 592 if kw is None: kw = {} 593 if not kw.has_key('_doprint'): kw['_doprint'] = doprint 594 if not kw.has_key('_hush'): kw['_hush'] = hush 595 if not kw.has_key('_save'): kw['_save'] = save 596 apply(p.run, tuple(args), kw)
597
598 # ----------------------------------------------------- 599 # run: Run an IRAF task by name 600 # ----------------------------------------------------- 601 602 -def run(taskname,args=(),kw=None,save=1):
603 """Run an IRAF task by name""" 604 if isinstance(taskname,_iraftask.IrafTask): 605 t = taskname 606 else: 607 t = getTask(taskname) 608 if kw is None: kw = {} 609 if not kw.has_key('_save'): kw['_save'] = save 610 ## if not kw.has_key('_parent'): kw['parent'] = "'iraf.cl'" 611 apply(t.run, tuple(args), kw)
612
613 614 # ----------------------------------------------------- 615 # getAllTasks: Get list of all IRAF tasks that match partial name 616 # ----------------------------------------------------- 617 618 -def getAllTasks(taskname):
619 """Returns list of names of all IRAF tasks that may match taskname""" 620 return _mmtasks.getallkeys(taskname, [])
621
622 623 # ----------------------------------------------------- 624 # getAllPkgs: Get list of all IRAF pkgs that match partial name 625 # ----------------------------------------------------- 626 627 -def getAllPkgs(pkgname):
628 """Returns list of names of all IRAF pkgs that may match pkgname""" 629 return _pkgs.getallkeys(pkgname, [])
630
631 632 # ----------------------------------------------------- 633 # getTask: Find an IRAF task by name 634 # ----------------------------------------------------- 635 -def getTask(taskname, found=0):
636 """Find an IRAF task by name using minimum match 637 638 Returns an IrafTask object. Name may be either fully qualified 639 (package.taskname) or just the taskname. taskname is also allowed 640 to be an IrafTask object, in which case it is simply returned. 641 Does minimum match to allow abbreviated names. If found is set, 642 returns None when task is not found; default is to raise exception 643 if task is not found. 644 """ 645 646 if isinstance(taskname,_iraftask.IrafTask): 647 return taskname 648 elif not isinstance(taskname, (str,unicode)): 649 raise TypeError("Argument to getTask is not a string or IrafTask instance") 650 651 # undo any modifications to the taskname 652 taskname = _irafutils.untranslateName(taskname) 653 654 # Try assuming fully qualified name first 655 656 task = _tasks.get(taskname) 657 if task is not None: 658 if Verbose>1: print 'found',taskname,'in task list' 659 return task 660 661 # Look it up in the minimum-match dictionary 662 # Note _mmtasks.getall returns list of full names of all matching tasks 663 664 fullname = _mmtasks.getall(taskname) 665 if not fullname: 666 if found: 667 668 return None 669 else: 670 raise KeyError("Task "+taskname+" is not defined") 671 if len(fullname) == 1: 672 # unambiguous match 673 task = _tasks[fullname[0]] 674 if Verbose>1: print 'found',task.getName(),'in task list' 675 return task 676 677 # Ambiguous match is OK only if taskname is the full name 678 # or if all matched tasks have the same task name. For example, 679 # (1) 'mem' matches package 'mem0' and task 'restore.mem' -- return 680 # 'restore.mem'. 681 # (2) 'imcal' matches tasks named 'imcalc' in several different 682 # packages -- return the most recently loaded version. 683 # (3) 'imcal' matches several 'imcalc's and also 'imcalculate'. 684 # That is an error. 685 686 # look for exact matches, <pkg>.<taskname> 687 trylist = [] 688 pkglist = [] 689 for name in fullname: 690 sp = name.split('.') 691 if sp[-1] == taskname: 692 trylist.append(name) 693 pkglist.append(sp[0]) 694 # return a single exact match 695 if len(trylist) == 1: return _tasks[trylist[0]] 696 697 if not trylist: 698 # no exact matches, see if all tasks have same name 699 sp = fullname[0].split('.') 700 name = sp[-1] 701 pkglist = [ sp[0] ] 702 for i in xrange(len(fullname)-1): 703 sp = fullname[i+1].split('.') 704 if name != sp[-1]: 705 if len(fullname)>3: 706 fullname[3:] = ['...'] 707 if found: 708 return None 709 else: 710 raise _minmatch.AmbiguousKeyError( 711 "Task `%s' is ambiguous, could be %s" % 712 (taskname, ', '.join(fullname))) 713 pkglist.append(sp[0]) 714 trylist = fullname 715 716 # trylist has a list of several candidate tasks that differ 717 # only in package. Search loaded packages in reverse to find 718 # which one was loaded most recently. 719 for i in xrange(len(loadedPath)): 720 pkg = loadedPath[-1-i].getName() 721 if pkg in pkglist: 722 # Got it at last 723 j = pkglist.index(pkg) 724 return _tasks[trylist[j]] 725 # None of the packages are loaded? This presumably cannot happen 726 # now, but could happen if package unloading is implemented. 727 if found: 728 return None 729 else: 730 raise KeyError("Task "+taskname+" is not in a loaded package")
731
732 733 # ----------------------------------------------------- 734 # getPkg: Find an IRAF package by name 735 # ----------------------------------------------------- 736 737 -def getPkg(pkgname,found=0):
738 """Find an IRAF package by name using minimum match 739 740 Returns an IrafPkg object. pkgname is also allowed 741 to be an IrafPkg object, in which case it is simply 742 returned. If found is set, returns None when package 743 is not found; default is to raise exception if package 744 is not found. 745 """ 746 try: 747 if isinstance(pkgname,_iraftask.IrafPkg): 748 return pkgname 749 if not pkgname: 750 raise TypeError("Bad package name `%s'" % `pkgname`) 751 # undo any modifications to the pkgname 752 pkgname = _irafutils.untranslateName(pkgname) 753 return _pkgs[pkgname] 754 except _minmatch.AmbiguousKeyError, e: 755 # re-raise the error with a bit more info 756 raise e.__class__("Package "+pkgname+": "+str(e)) 757 except KeyError, e: 758 if found: return None 759 raise KeyError("Package `%s' not found" % (pkgname,))
760
761 762 # ----------------------------------------------------- 763 # Miscellaneous access routines: 764 # getTaskList: Get list of names of all defined IRAF tasks 765 # getPkgList: Get list of names of all defined IRAF packages 766 # getLoadedList: Get list of names of all loaded IRAF packages 767 # getVarList: Get list of names of all defined IRAF variables 768 # ----------------------------------------------------- 769 770 -def getTaskList():
771 """Returns list of names of all defined IRAF tasks""" 772 return _tasks.keys()
773
774 -def getTaskObjects():
775 """Returns list of all defined IrafTask objects""" 776 return _tasks.values()
777
778 -def getPkgList():
779 """Returns list of names of all defined IRAF packages""" 780 return _pkgs.keys()
781
782 -def getLoadedList():
783 """Returns list of names of all loaded IRAF packages""" 784 return _loaded.keys()
785
786 -def getVarDict():
787 """Returns dictionary all IRAF variables""" 788 return _varDict
789
790 -def getVarList():
791 """Returns list of names of all IRAF variables""" 792 return _varDict.keys()
793
794 # ----------------------------------------------------- 795 # listAll, listPkg, listLoaded, listTasks, listCurrent, listVars: 796 # list contents of the dictionaries 797 # ----------------------------------------------------- 798 799 @handleRedirAndSaveKwds 800 -def listAll(hidden=0):
801 """List IRAF packages, tasks, and variables""" 802 print 'Packages:' 803 listPkgs() 804 print 'Loaded Packages:' 805 listLoaded() 806 print 'Tasks:' 807 listTasks(hidden=hidden) 808 print 'Variables:' 809 listVars()
810
811 @handleRedirAndSaveKwds 812 -def listPkgs():
813 """List IRAF packages""" 814 keylist = getPkgList() 815 if len(keylist) == 0: 816 print 'No IRAF packages defined' 817 else: 818 keylist.sort() 819 # append '/' to identify packages 820 for i in xrange(len(keylist)): keylist[i] = keylist[i] + '/' 821 _irafutils.printCols(keylist)
822
823 @handleRedirAndSaveKwds 824 -def listLoaded():
825 """List loaded IRAF packages""" 826 keylist = getLoadedList() 827 if len(keylist) == 0: 828 print 'No IRAF packages loaded' 829 else: 830 keylist.sort() 831 # append '/' to identify packages 832 for i in xrange(len(keylist)): keylist[i] = keylist[i] + '/' 833 _irafutils.printCols(keylist)
834
835 @handleRedirAndSaveKwdsPlus 836 -def listTasks(pkglist=None, hidden=0, **kw):
837 """List IRAF tasks, optionally specifying a list of packages to include 838 839 Package(s) may be specified by name or by IrafPkg objects. 840 """ 841 keylist = getTaskList() 842 if len(keylist) == 0: 843 print 'No IRAF tasks defined' 844 return 845 # make a dictionary of pkgs to list 846 if pkglist is None: 847 pkgdict = _pkgs 848 else: 849 pkgdict = {} 850 if isinstance(pkglist, (str,unicode,_iraftask.IrafPkg)): 851 pkglist = [ pkglist ] 852 for p in pkglist: 853 try: 854 pthis = getPkg(p) 855 if pthis.isLoaded(): 856 pkgdict[pthis.getName()] = 1 857 else: 858 _writeError('Package %s has not been loaded' % 859 pthis.getName()) 860 except KeyError, e: 861 _writeError(str(e)) 862 if not len(pkgdict): 863 print 'No packages to list' 864 return 865 866 # print each package separately 867 keylist.sort() 868 lastpkg = '' 869 tlist = [] 870 for tname in keylist: 871 pkg, task = tname.split('.') 872 tobj = _tasks[tname] 873 if hidden or not tobj.isHidden(): 874 if isinstance(tobj,_iraftask.IrafPkg): 875 task = task + '/' 876 elif isinstance(tobj,_iraftask.IrafPset): 877 task = task + '@' 878 if pkg == lastpkg: 879 tlist.append(task) 880 else: 881 if len(tlist) and pkgdict.has_key(lastpkg): 882 print lastpkg + '/:' 883 _irafutils.printCols(tlist) 884 tlist = [task] 885 lastpkg = pkg 886 if len(tlist) and pkgdict.has_key(lastpkg): 887 print lastpkg + '/:' 888 _irafutils.printCols(tlist)
889
890 @handleRedirAndSaveKwds 891 -def listCurrent(n=1, hidden=0):
892 """List IRAF tasks in current package (equivalent to '?' in the cl) 893 If parameter n is specified, lists n most recent packages.""" 894 if len(loadedPath): 895 if n > len(loadedPath): n = len(loadedPath) 896 plist = n*[None] 897 for i in xrange(n): 898 plist[i] = loadedPath[-1-i].getName() 899 listTasks(plist,hidden=hidden) 900 else: 901 print 'No IRAF tasks defined'
902
903 @handleRedirAndSaveKwdsPlus 904 -def listVars(prefix="", equals="\t= "):
905 """List IRAF variables""" 906 keylist = getVarList() 907 if len(keylist) == 0: 908 print 'No IRAF variables defined' 909 else: 910 keylist.sort() 911 for word in keylist: 912 print "%s%s%s%s" % (prefix, word, equals, envget(word))
913
914 @handleRedirAndSaveKwds 915 -def gripes():
916 """ Hide the system call - direct the user to support """ 917 print "Please email your concern directly to support@stsci.edu"
918 gripe = gripes
919 920 @handleRedirAndSaveKwds 921 -def which(*args):
922 """ Emulate the which function in IRAF. """ 923 for arg in args: 924 try: 925 print getTask(arg).getPkgname() 926 # or: getTask(arg).getPkgname()+"."+getTask(arg).getName() 927 except _minmatch.AmbiguousKeyError, e: 928 print str(e) 929 except (KeyError, TypeError): 930 if deftask(arg): 931 print 'language' # handle, e.g. 'which which', 'which cd' 932 else: 933 _writeError(arg+": task not found.")
934
935 @handleRedirAndSaveKwds 936 -def whereis(*args):
937 """ Emulate the whereis function in IRAF. """ 938 for arg in args: 939 matches = _mmtasks.getall(arg) 940 if matches: 941 matches.reverse() # this reverse isn't necessary - they arrive 942 # in the right order, but CL seems to do this 943 print " ".join(matches) 944 else: 945 _writeError(arg+": task not found.")
946
947 948 @handleRedirAndSaveKwds 949 -def taskinfo(*args):
950 ''' 951 show information about task definitions 952 953 taskinfo [ pattern(s) ] 954 955 pattern is a glob pattern describing the package or task 956 name that you are interested in. 957 958 The output is a hierarchical view of the task definitions 959 that match the input pattern. Each line shows the task 960 name, the file name, pkgbinary and class. 961 962 pkgbinary is a list of where you look for the file if it 963 is not where you expect. 964 965 class is the type of task definition from iraftask.py 966 967 At this point, this is not exactly friendly for an end-user, 968 but an SE could use it or ask the user to run it and send in 969 the output. 970 ''' 971 972 for x in args : 973 _iraftask.showtasklong( x )
974
975 976 # ----------------------------------------------------- 977 # IRAF utility functions 978 # ----------------------------------------------------- 979 980 # these do not have extra keywords because they should not 981 # be called as tasks 982 983 -def clParGet(paramname,pkg=None,native=1,mode=None,prompt=1):
984 """Return value of IRAF parameter 985 986 Parameter can be a cl task parameter, a package parameter for 987 any loaded package, or a fully qualified (task.param) parameter 988 from any known task. 989 """ 990 if pkg is None: pkg = loadedPath[-1] 991 # if taskname is '_', use current package as task 992 if paramname[:2] == "_.": 993 paramname = pkg.getName() + paramname[1:] 994 return pkg.getParam(paramname,native=native,mode=mode,prompt=prompt)
995
996 -def envget(var,default=None):
997 """Get value of IRAF or OS environment variable""" 998 try: 999 return _varDict[var] 1000 except KeyError: 1001 try: 1002 return _os.environ[var] 1003 except KeyError: 1004 if default is not None: 1005 return default 1006 elif var == 'TERM': 1007 # Return a default value for TERM 1008 # TERM gets caught as it is found in the default 1009 # login.cl file setup by IRAF. 1010 print "Using default TERM value for session." 1011 return 'xterm' 1012 else: 1013 raise KeyError("Undefined environment variable `%s'" % var)
1014 1015 _tmpfileCounter = 0
1016 1017 -def mktemp(root):
1018 """Make a temporary filename starting with root""" 1019 global _tmpfileCounter 1020 basename = root + `_os.getpid()` 1021 while 1: 1022 _tmpfileCounter = _tmpfileCounter + 1 1023 if _tmpfileCounter <= 26: 1024 # use letters to start 1025 suffix = chr(ord("a")+_tmpfileCounter-1) 1026 else: 1027 # use numbers once we've used up letters 1028 suffix = "_" + `_tmpfileCounter-26` 1029 file = basename + suffix 1030 if not _os.path.exists(Expand(file)): 1031 return file
1032 1033 _NullFileList = ["dev$null", "/dev/null"] 1034 _NullPath = None
1035 1036 -def isNullFile(s):
1037 """Returns true if this is the CL null file""" 1038 global _NullFileList, _NullPath 1039 if s in _NullFileList: return 1 1040 sPath = Expand(s) 1041 if _NullPath is None: 1042 _NullPath = Expand(_NullFileList[0]) 1043 _NullFileList.append(_NullPath) 1044 if sPath == _NullPath: 1045 return 1 1046 else: 1047 return 0
1048
1049 -def substr(s,first,last):
1050 """Return sub-string using IRAF 1-based indexing""" 1051 if s == INDEF: return INDEF 1052 # If the first index is zero, always return a zero-length string 1053 if first == 0: return '' 1054 return s[first-1:last]
1055
1056 -def strlen(s):
1057 """Return length of string""" 1058 if s == INDEF: return INDEF 1059 return len(s)
1060
1061 -def isindef(s):
1062 """Returns true if argument is INDEF""" 1063 if s == INDEF: 1064 return 1 1065 else: 1066 return 0
1067
1068 -def stridx(test, s):
1069 """Return index of first occurrence of any of the characters in 'test' 1070 that are in 's' using IRAF 1-based indexing""" 1071 if INDEF in (s,test): return INDEF 1072 _pos2 = len(s) 1073 for _char in test: 1074 _pos = s.find(_char) 1075 if _pos != -1: 1076 _pos2 = min(_pos2, _pos) 1077 if _pos2 == len(s): 1078 return 0 1079 else: 1080 return _pos2+1
1081
1082 -def strldx(test, s):
1083 """Return index of last occurrence of any of the characters in 'test' 1084 that are in 's' using IRAF 1-based indexing""" 1085 if INDEF in (s,test): return INDEF 1086 _pos2 = -1 1087 for _char in test: 1088 _pos = s.rfind(_char) 1089 if _pos != -1: 1090 _pos2 = max(_pos2, _pos) 1091 return _pos2+1
1092
1093 -def strlwr(s):
1094 """Return string converted to lower case""" 1095 if s == INDEF: return INDEF 1096 return s.lower()
1097
1098 -def strupr(s):
1099 """Return string converted to upper case""" 1100 if s == INDEF: return INDEF 1101 return s.upper()
1102
1103 -def strstr(str1,str2):
1104 """Search for first occurrence of 'str1' in 'str2', returns index 1105 of the start of 'str1' or zero if not found. IRAF 1-based indexing""" 1106 if INDEF in (str1,str2): return INDEF 1107 return str2.find(str1)+1
1108
1109 -def strlstr(str1,str2):
1110 """Search for last occurrence of 'str1' in 'str2', returns index 1111 of the start of 'str1' or zero if not found. IRAF 1-based indexing""" 1112 if INDEF in (str1, str2): return INDEF 1113 return str2.rfind(str1)+1
1114
1115 -def trim(str, trimchars=None):
1116 """Trim any of the chars in 'trimchars' (default = whitesspace) from 1117 both ends of 'str'.""" 1118 if INDEF in (str, trimchars): return INDEF 1119 return str.strip(trimchars)
1120
1121 -def triml(str, trimchars=None):
1122 """Trim any of the chars in 'trimchars' (default = whitesspace) from 1123 the left side of 'str'.""" 1124 if INDEF in (str, trimchars): return INDEF 1125 return str.lstrip(trimchars)
1126
1127 -def trimr(str, trimchars=None):
1128 """Trim any of the chars in 'trimchars' (default = whitesspace) from 1129 the right side of 'str'.""" 1130 if INDEF in (str, trimchars): return INDEF 1131 return str.rstrip(trimchars)
1132
1133 -def frac(x):
1134 """Return fractional part of x""" 1135 if x == INDEF: return INDEF 1136 frac_part, int_part = _math.modf(x) 1137 return frac_part
1138
1139 -def real(x):
1140 """Return real/float representation of x""" 1141 if x == INDEF: 1142 return INDEF 1143 elif isinstance(x, (str,unicode)): 1144 x = x.strip() 1145 if x.find(':') >= 0: 1146 #...handle the special a:b:c case here... 1147 if x[0] in ["-", "+"]: 1148 if x[0] == "-": 1149 sign = -1. 1150 x = x[1:] 1151 else: 1152 sign = 1. 1153 m = _re.search(r"[^0-9:.]", x) 1154 if m: 1155 x = x[0:m.start()] 1156 f = map(float,x.split(":")) 1157 f = map(abs, f) 1158 return sign*clSexagesimal(*f) 1159 else: 1160 x = _re.sub("[EdD]", "e", x, count=1) 1161 m = _re.search(r"[^0-9.e+-]", x) 1162 if m: 1163 x = x[0:m.start()] 1164 return float(x) 1165 else: 1166 return float(x)
1167
1168 -def integer(x):
1169 """Return integer representation of x""" 1170 if x==INDEF: 1171 return INDEF 1172 elif isinstance(x, (str,unicode)): 1173 x = x.strip() 1174 i = 0 1175 j = len(x) 1176 if x[0] in ["+", "-"]: 1177 i = 1 1178 x = _re.sub("[EdD]", "e", x, count=1) 1179 m = _re.search(r"[^0-9.e+-]", x[i:]) 1180 if m: 1181 j = i + m.start() 1182 return int(float(x[:j])) 1183 else: 1184 return int(x)
1185
1186 -def mod(a, b):
1187 """Return a modulo b""" 1188 if INDEF in (a,b): return INDEF 1189 return (a % b)
1190
1191 -def nint(x):
1192 """Return nearest integer of x""" 1193 if x == INDEF: return INDEF 1194 return int(round(x))
1195 1196 _radixDigits = list(_string.digits+_string.ascii_uppercase)
1197 1198 -def radix(value, base=10, length=0):
1199 """Convert integer value to string expressed using given base 1200 1201 If length is given, field is padded with leading zeros to reach length. 1202 Note that if value is negative, this routine returns the actual 1203 bit-pattern of the twos-complement integer (even for base 10) rather 1204 than a signed value. This is consistent with IRAF's behavior. 1205 """ 1206 if INDEF in (value,base,length): return INDEF 1207 if not (2 <= base <= 36): 1208 raise ValueError("base must be between 2 and 36 (inclusive)") 1209 ivalue = int(value) 1210 if ivalue == 0: 1211 # handle specially so don't have to worry about it below 1212 return "%0*d" % (length, ivalue) 1213 # convert to an unsigned long integer 1214 hexIvalue = hex(ivalue) # hex() can return a string for an int or a long 1215 isLong = hexIvalue[-1] == 'L' 1216 if not isLong: hexIvalue += 'L' 1217 lvalue = eval(hexIvalue) 1218 outdigits = [] 1219 while lvalue > 0 or lvalue < -1: 1220 lvalue, digit = divmod(lvalue, base) 1221 outdigits.append(int(digit)) 1222 outdigits = map(lambda index: _radixDigits[index], outdigits) 1223 # zero-pad if needed (automatically do so for negative numbers) 1224 if ivalue < 0: 1225 maxlen = 32 1226 if isLong: maxlen = BITS_PER_LONG 1227 outdigits.extend((maxlen-len(outdigits))*["1"]) 1228 if length>len(outdigits): 1229 outdigits.extend((length-len(outdigits))*["0"]) 1230 outdigits.reverse() 1231 return ''.join(outdigits)
1232
1233 -def rad(value):
1234 """Convert arg in degrees to radians""" 1235 if value==INDEF: 1236 return INDEF 1237 else: 1238 return _math.radians(value)
1239
1240 -def deg(value):
1241 """Convert arg in radians to degrees""" 1242 if value==INDEF: 1243 return INDEF 1244 else: 1245 return _math.degrees(value)
1246
1247 -def sin(value):
1248 """Trigonometric sine function. Input in radians.""" 1249 if value==INDEF: 1250 return INDEF 1251 else: 1252 return _math.sin(value)
1253
1254 -def asin(value):
1255 """Trigonometric arc sine function. Result in radians.""" 1256 if value==INDEF: 1257 return INDEF 1258 else: 1259 return _math.asin(value)
1260
1261 -def cos(value):
1262 """Trigonometric cosine function. Input in radians.""" 1263 if value==INDEF: 1264 return INDEF 1265 else: 1266 return _math.cos(value)
1267
1268 -def acos(value):
1269 """Trigonometric arc cosine function. Result in radians.""" 1270 if value==INDEF: 1271 return INDEF 1272 else: 1273 return _math.acos(value)
1274
1275 -def tan(value):
1276 """Trigonometric tangent function. Input in radians.""" 1277 if value==INDEF: 1278 return INDEF 1279 else: 1280 return _math.tan(value)
1281
1282 -def atan2(x,y):
1283 """Trigonometric 2-argument arctangent function. Result in radians.""" 1284 if INDEF in (x,y): 1285 return INDEF 1286 else: 1287 return _math.atan2(x,y)
1288
1289 -def dsin(value):
1290 """Trigonometric sine function. Input in degrees.""" 1291 if value==INDEF: 1292 return INDEF 1293 else: 1294 return _math.sin(_math.radians(value))
1295
1296 -def dasin(value):
1297 """Trigonometric arc sine function. Result in degrees.""" 1298 if value==INDEF: 1299 return INDEF 1300 else: 1301 return _math.degrees(_math.asin(value))
1302
1303 -def dcos(value):
1304 """Trigonometric cosine function. Input in degrees.""" 1305 if value==INDEF: 1306 return INDEF 1307 else: 1308 return _math.cos(_math.radians(value))
1309
1310 -def dacos(value):
1311 """Trigonometric arc cosine function. Result in degrees.""" 1312 if value==INDEF: 1313 return INDEF 1314 else: 1315 return _math.degrees(_math.acos(value))
1316
1317 -def dtan(value):
1318 """Trigonometric tangent function. Input in degrees.""" 1319 if value==INDEF: 1320 return INDEF 1321 else: 1322 return _math.tan(_math.radians(value))
1323
1324 -def datan2(x,y):
1325 """Trigonometric 2-argument arctangent function. Result in degrees.""" 1326 if INDEF in (x,y): 1327 return INDEF 1328 else: 1329 return _math.degrees(_math.atan2(x,y))
1330
1331 -def exp(value):
1332 """Exponential function""" 1333 if value==INDEF: 1334 return INDEF 1335 else: 1336 return _math.exp(value)
1337
1338 -def log(value):
1339 """Natural log function""" 1340 if value==INDEF: 1341 return INDEF 1342 else: 1343 return _math.log(value)
1344
1345 -def log10(value):
1346 """Base 10 log function""" 1347 if value==INDEF: 1348 return INDEF 1349 else: 1350 return _math.log10(value)
1351
1352 -def sqrt(value):
1353 """Square root function""" 1354 if value==INDEF: 1355 return INDEF 1356 else: 1357 return _math.sqrt(value)
1358
1359 -def absvalue(value):
1360 """Absolute value function""" 1361 if value==INDEF: 1362 return INDEF 1363 else: 1364 return abs(value)
1365
1366 -def minimum(*args):
1367 """Minimum of list of arguments""" 1368 if INDEF in args: 1369 return INDEF 1370 else: 1371 return min(*args)
1372
1373 -def maximum(*args):
1374 """Maximum of list of arguments""" 1375 if INDEF in args: 1376 return INDEF 1377 else: 1378 return max(*args)
1379
1380 -def hypot(x,y):
1381 """Return the Euclidean distance, sqrt(x*x + y*y).""" 1382 if INDEF in (x,y): 1383 return INDEF 1384 else: 1385 return _math.hypot(x,y)
1386
1387 -def sign(value):
1388 """Sign of argument (-1 or 1)""" 1389 if value==INDEF: return INDEF 1390 if value>=0.0: 1391 return 1 1392 else: 1393 return -1
1394
1395 -def clNot(value):
1396 """Bitwise boolean NOT of an integer""" 1397 if value==INDEF: return INDEF 1398 return ~(int(value))
1399
1400 -def clAnd(x,y):
1401 """Bitwise boolean AND of two integers""" 1402 if INDEF in (x,y): return INDEF 1403 return x&y
1404
1405 -def clOr(x,y):
1406 """Bitwise boolean OR of two integers""" 1407 if INDEF in (x,y): return INDEF 1408 return x|y
1409
1410 -def clXor(x,y):
1411 """Bitwise eXclusive OR of two integers""" 1412 if INDEF in (x,y): return INDEF 1413 return x^y
1414
1415 -def osfn(filename):
1416 """Convert IRAF virtual path name to OS pathname""" 1417 1418 # Try to emulate the CL version closely: 1419 # 1420 # - expands IRAF virtual file names 1421 # - strips blanks around path components 1422 # - if no slashes or relative paths, return relative pathname 1423 # - otherwise return absolute pathname 1424 1425 if filename == INDEF: return INDEF 1426 ename = Expand(filename) 1427 dlist = [s.strip() for s in ename.split(_os.sep)] 1428 if len(dlist)==1 and dlist[0] not in [_os.curdir,_os.pardir]: 1429 return dlist[0] 1430 1431 # I use string.join instead of os.path.join here because 1432 # os.path.join("","") returns "" instead of "/" 1433 1434 epath = _os.sep.join(dlist) 1435 fname = _os.path.abspath(epath) 1436 # append '/' if relative directory was at end or filename ends with '/' 1437 if fname[-1] != _os.sep and dlist[-1] in ['', _os.curdir,_os.pardir]: 1438 fname = fname + _os.sep 1439 return fname
1440
1441 -def clSexagesimal(d, m, s=0):
1442 """Convert d:m:s value to float""" 1443 return (d+(m+s/60.0)/60.0)
1444
1445 -def clDms(x,digits=1,seconds=1):
1446 """Convert float to d:m:s.s 1447 1448 Number of decimal places on seconds is set by digits. 1449 If seconds is false, prints just d:m.m (omits seconds). 1450 """ 1451 if x<0: 1452 sign = '-' 1453 x = -x 1454 else: 1455 sign = '' 1456 if seconds: 1457 d = int(x) 1458 x = 60*(x-d) 1459 m = int(x) 1460 s = 60*(x-m) 1461 # round to avoid printing (e.g.) 60.0 seconds 1462 digits = max(digits, 0) 1463 if s+0.5/10**digits >= 60: 1464 s = 0.0 1465 m = m+1 1466 if seconds and m==60: 1467 m = 0 1468 d = d+1 1469 if digits==0: 1470 secform = "%02d" 1471 else: 1472 secform = "%%0%d.%df" % (digits+3, digits) 1473 if seconds: 1474 return ("%s%2d:%02d:"+secform) % (sign, d, m, s) 1475 else: 1476 return ("%s%02d:"+secform) % (sign, m, s)
1477
1478 -def defpar(paramname):
1479 """Returns true if parameter is defined""" 1480 if paramname == INDEF: return INDEF 1481 try: 1482 value = clParGet(paramname,prompt=0) 1483 return 1 1484 except IrafError, e: 1485 # treat all errors (including ambiguous task and parameter names) 1486 # as a missing parameter 1487 return 0
1488
1489 -def access(filename):
1490 """Returns true if file exists""" 1491 if filename == INDEF: return INDEF 1492 filename = _denode(filename) 1493 # Magic values that trigger special behavior 1494 magicValues = { "STDIN": 1, "STDOUT": 1, "STDERR": 1} 1495 return magicValues.has_key(filename) or _os.path.exists(Expand(filename))
1496
1497 -def fp_equal(x, y):
1498 """Floating point compare to within machine precision. This logic is 1499 taken directly from IRAF's fp_equald function.""" 1500 # Check the easy answers first 1501 if INDEF in (x,y): return INDEF 1502 if x==y: return True 1503 1504 # We can't normalize zero, so handle the zero operand cases first. 1505 # Note that the case where 0 equals 0 is handled above. 1506 if x==0.0 or y==0.0: return False 1507 1508 # Now normalize the operands and do an epsilon comparison 1509 normx, ex = _fp_norm(x) 1510 normy, ey = _fp_norm(y) 1511 1512 # Here is an easy false check 1513 if ex != ey: return False 1514 1515 # Finally compare the values 1516 x1 = 1.0 + abs(normx-normy) 1517 x2 = 1.0 + (32.0 * FP_EPSILON) 1518 return x1 <= x2
1519
1520 -def _fp_norm(x):
1521 """Normalize a floating point number x to the value normx, in the 1522 range [1-10). expon is returned such that: 1523 x = normx * (10.0 ** expon) 1524 This logic is taken directly from IRAF's fp_normd function.""" 1525 # See FP_EPSILON description elsewhere. 1526 tol = FP_EPSILON * 10.0 1527 absx = abs(x) 1528 expon = 0 1529 1530 if absx > 0: 1531 while absx < (1.0-tol): 1532 absx *= 10.0 1533 expon -= 1 1534 if absx == 0.0: # check for underflow to zero 1535 return 0, 0 1536 while absx >= (10.0+tol): 1537 absx /= 10.0 1538 expon += 1 1539 1540 if x < 0: 1541 normx = -absx 1542 else: 1543 normx = absx 1544 1545 return normx, expon
1546 1547 _denode_pat = _re.compile(r'[^/]*!')
1548 1549 -def _denode(filename):
1550 """Remove IRAF "node!" specification from filename""" 1551 mm = _denode_pat.match(filename) 1552 if mm is None: 1553 return filename 1554 else: 1555 return filename[len(mm.group()):]
1556
1557 -def _imextn():
1558 """Returns list of image types and extensions 1559 1560 The return value is (ktype, globlist) where ktype is 1561 the image kernel (oif, fxf, etc.) and globlist is a list 1562 of glob-style patterns that match extensions. 1563 """ 1564 # imextn environment variable has list (or use default) 1565 s = envget("imextn", "oif:imh fxf:fits,fit plf:pl qpf:qp stf:hhh,??h") 1566 fields = s.split() 1567 extlist = [] 1568 for f in fields: 1569 ilist = f.split(":") 1570 if len(ilist) != 2: 1571 raise IrafError("Illegal field `%s' in IRAF variable imextn" % f) 1572 exts = ilist[1].split(",") 1573 extlist.append((ilist[0], exts)) 1574 return extlist
1575
1576 -def _checkext(ext, extlist):
1577 """Returns image type if ext is in extlist, else returns None 1578 1579 Assumes ext starts with a '.' (as returned by os.path.split) and 1580 that null extensions can't match. 1581 """ 1582 if not ext: return None 1583 ext = ext[1:] 1584 for ktype, elist in extlist: 1585 for pat in elist: 1586 if _fnmatch.fnmatch(ext, pat): 1587 return ktype 1588 return None
1589
1590 -def _searchext(root, extlist):
1591 """Returns image type if file root.ext is found (ext from extlist)""" 1592 for ktype, elist in extlist: 1593 for pat in elist: 1594 flist = _glob.glob(root + '.' + pat) 1595 if flist: 1596 return ktype 1597 return None
1598
1599 -def imaccess(filename):
1600 """Returns true if image matching name exists and is readable""" 1601 1602 if filename == INDEF: return INDEF 1603 # See if the filename contains any wildcard characters. 1604 # First strip any extension or section specification. 1605 tfilename = filename 1606 i = tfilename.find('[') 1607 if i>=0: 1608 tfilename = filename[:i] 1609 if '*' in tfilename or '?' in tfilename: 1610 return 0 1611 # Edge case not handled below: 1612 if filename.find('[]') != -1: 1613 return 0 1614 # If we get this far, use imheader to test existence. 1615 # Any error output is taken to mean failure. 1616 sout = _StringIO.StringIO() 1617 serr = _StringIO.StringIO() 1618 iraf.imhead(filename, Stdout=sout, Stderr=serr) 1619 errstr = serr.getvalue().lower() 1620 outstr = sout.getvalue().lower() 1621 if errstr: 1622 # Handle exceptional cases: 1623 # 1) ambiguous files (imaccess accepts this) 1624 # 2) non specification of extension # for multi-extension fits files 1625 # (imaccess doesn't require) 1626 # This approach, while adaptable, is brittle in its dependency on 1627 # IRAF error strings 1628 if ((errstr.find('must specify which fits extension') >= 0) or 1629 (errstr.find('ambiguous')) >= 0): 1630 return 1 1631 else: 1632 return 0 1633 elif outstr: 1634 # If the filename string is blank(s), imhead writes "no images found" 1635 # to Stdout 1636 if (outstr.find('no images found') >= 0): 1637 return 0 1638 else: 1639 return 1
1640
1641 -def defvar(varname):
1642 """Returns true if CL variable is defined""" 1643 if varname == INDEF: return INDEF 1644 return _varDict.has_key(varname) or _os.environ.has_key(varname)
1645
1646 -def deftask(taskname):
1647 """Returns true if CL task is defined""" 1648 if taskname == INDEF: return INDEF 1649 try: 1650 import iraf 1651 t = getattr(iraf, taskname) 1652 return 1 1653 except AttributeError, e: 1654 # treat all errors (including ambiguous task names) as a missing task 1655 return 0
1656
1657 -def defpac(pkgname):
1658 """Returns true if CL package is defined and loaded""" 1659 if pkgname == INDEF: return INDEF 1660 try: 1661 t = getPkg(pkgname) 1662 return t.isLoaded() 1663 except KeyError, e: 1664 # treat all errors (including ambiguous package names) as a missing pkg 1665 return 0
1666
1667 -def curpack():
1668 """Returns name of current CL package""" 1669 if loadedPath: 1670 return loadedPath[-1].getName() 1671 else: 1672 return ""
1673
1674 -def curPkgbinary():
1675 """Returns name pkgbinary directory for current CL package""" 1676 if loadedPath: 1677 return loadedPath[-1].getPkgbinary() 1678 else: 1679 return ""
1680
1681 # utility functions for boolean conversions 1682 1683 -def bool2str(value):
1684 """Convert IRAF boolean value to a string""" 1685 if value in [None, INDEF]: 1686 return "INDEF" 1687 elif value: 1688 return "yes" 1689 else: 1690 return "no"
1691
1692 1693 -def boolean(value):
1694 """Convert Python native types (string, int, float) to IRAF boolean 1695 1696 Accepts integer/float values 0,1 or string 'yes','no' 1697 Also allows INDEF as value 1698 """ 1699 if value in [0,1]: 1700 return value 1701 elif value in [INDEF, "", None]: 1702 return INDEF 1703 if isinstance(value, (str,unicode)): 1704 v2 = _irafutils.stripQuotes(value.strip()) 1705 if v2 == "INDEF": 1706 return INDEF 1707 ff = v2.lower() 1708 if ff == "no": 1709 return 0 1710 elif ff == "yes": 1711 return 1 1712 elif isinstance(value,float): 1713 # try converting to integer 1714 try: 1715 ival = int(value) 1716 if (ival == value) and (ival == 0 or ival == 1): 1717 return ival 1718 except (ValueError, OverflowError): 1719 pass 1720 raise ValueError("Illegal boolean value %s" % `value`)
1721 1722 1723 # ----------------------------------------------------- 1724 # scan functions 1725 # Abandon all hope, ye who enter here 1726 # ----------------------------------------------------- 1727 1728 _nscan = 0
1729 1730 -def fscan(locals, line, *namelist, **kw):
1731 """fscan function sets parameters from a string or list parameter 1732 1733 Uses local dictionary (passed as first argument) to set variables 1734 specified by list of following names. (This is a bit 1735 messy, but it is by far the cleanest approach I've thought of. 1736 I'm literally using call-by-name for these variables.) 1737 1738 Accepts an additional keyword argument strconv with names of 1739 conversion functions for each argument in namelist. 1740 1741 Returns number of arguments set to new values, which may be 1742 fewer than the number of variables if an unexpected character 1743 is encountered in 'line'. If there are too few space-delimited 1744 arguments on the input line, it does not set all the arguments. 1745 Returns EOF on end-of-file. 1746 """ 1747 # get the value of the line (which may be a variable, string literal, 1748 # expression, or an IRAF list parameter) 1749 global _nscan 1750 try: 1751 line = eval(line, {'iraf': iraf}, locals) 1752 except EOFError: 1753 _weirdEOF(locals, namelist) 1754 _nscan = 0 1755 return EOF 1756 f = line.split() 1757 n = min(len(f),len(namelist)) 1758 # a tricky thing -- null input is OK if the first variable is 1759 # a struct 1760 if n==0 and namelist and _isStruct(locals, namelist[0]): 1761 f = [''] 1762 n = 1 1763 if kw.has_key('strconv'): 1764 strconv = kw['strconv'] 1765 del kw['strconv'] 1766 else: 1767 strconv = n*[None] 1768 if len(kw): 1769 raise TypeError('unexpected keyword argument: ' + `kw.keys()`) 1770 n_actual = 0 # this will be the actual number of values converted 1771 for i in range(n): 1772 # even messier: special handling for struct type variables, which 1773 # consume the entire remaining string 1774 if _isStruct(locals, namelist[i]): 1775 if i < len(namelist)-1: 1776 raise TypeError("Struct type param `%s' must be the final" 1777 " argument to scan" % namelist[i]) 1778 # ultramessy -- struct needs rest of line with embedded whitespace 1779 if i==0: 1780 iend = 0 1781 else: 1782 # construct a regular expression that matches the line so far 1783 pat = [r'\s*']*(2*i) 1784 for j in range(i): pat[2*j+1] = f[j] 1785 # a single following whitespace character also gets removed 1786 # (don't blame me, this is how IRAF does it!) 1787 pat.append(r'\s') 1788 pat = ''.join(pat) 1789 mm = _re.match(pat, line) 1790 if mm is None: 1791 raise RuntimeError("Bug: line '%s' pattern '%s' failed" % 1792 (line, pat)) 1793 iend = mm.end() 1794 if line[-1:] == '\n': 1795 cmd = namelist[i] + ' = ' + `line[iend:-1]` 1796 else: 1797 cmd = namelist[i] + ' = ' + `line[iend:]` 1798 elif strconv[i]: 1799 cmd = namelist[i] + ' = ' + strconv[i] + '(' + `f[i]` + ')' 1800 else: 1801 cmd = namelist[i] + ' = ' + `f[i]` 1802 try: 1803 exec cmd in locals 1804 n_actual += 1 1805 except ValueError: 1806 break 1807 _nscan = n_actual 1808 return n_actual
1809
1810 -def fscanf(locals, line, format, *namelist, **kw):
1811 """fscanf function sets parameters from a string/list parameter with format 1812 1813 Implementation is similar to fscan but is a bit simpler because 1814 special struct handling is not needed. Does not allow strconv keyword. 1815 1816 Returns number of arguments set to new values, which may be 1817 fewer than the number of variables if an unexpected character 1818 is encountered in 'line'. If there are too few space-delimited 1819 arguments on the input line, it does not set all the arguments. 1820 Returns EOF on end-of-file. 1821 """ 1822 # get the value of the line (which may be a variable, string literal, 1823 # expression, or an IRAF list parameter) 1824 global _nscan 1825 try: 1826 line = eval(line, {'iraf': iraf}, locals) 1827 # format also needs to be evaluated 1828 format = eval(format, locals) 1829 except EOFError: 1830 _weirdEOF(locals, namelist) 1831 _nscan = 0 1832 return EOF 1833 if sscanf == None: 1834 raise RuntimeError("fscanf is not supported on this platform") 1835 f = sscanf.sscanf(line, format) 1836 n = min(len(f),len(namelist)) 1837 # if list is null, add a null string 1838 # ugly but should be right most of the time 1839 if n==0 and namelist: 1840 f = [''] 1841 n = 1 1842 if len(kw): 1843 raise TypeError('unexpected keyword argument: ' + `kw.keys()`) 1844 n_actual = 0 # this will be the actual number of values converted 1845 for i in range(n): 1846 cmd = namelist[i] + ' = ' + `f[i]` 1847 try: 1848 exec cmd in locals 1849 n_actual += 1 1850 except ValueError: 1851 break 1852 _nscan = n_actual 1853 return n_actual
1854
1855 -def _weirdEOF(locals, namelist):
1856 # Replicate a weird IRAF behavior -- if the argument list 1857 # consists of a single struct-type variable, and it does not 1858 # currently have a defined value, set it to the null string. 1859 # (I warned you to abandon hope!) 1860 if namelist and _isStruct(locals, namelist[0], checklegal=1): 1861 if len(namelist) > 1: 1862 raise TypeError("Struct type param `%s' must be the final" 1863 " argument to scan" % namelist[0]) 1864 # it is an undefined struct, so set it to null string 1865 cmd = namelist[0] + ' = ""' 1866 exec cmd in locals
1867
1868 -def _isStruct(locals, name, checklegal=0):
1869 """Returns true if the variable `name' is of type struct 1870 1871 If checklegal is true, returns true only if variable is struct and 1872 does not currently have a legal value. 1873 """ 1874 c = name.split('.') 1875 if len(c)>1: 1876 # must get the parameter object, not the value 1877 c[-1] = 'getParObject(%s)' % `c[-1]` 1878 fname = '.'.join(c) 1879 try: 1880 par = eval(fname, locals) 1881 except KeyboardInterrupt: 1882 raise 1883 except: 1884 # assume all failures mean this is not an IrafPar 1885 return 0 1886 if (isinstance(par, _irafpar.IrafPar) and par.type == 'struct'): 1887 if checklegal: 1888 return (not par.isLegal()) 1889 else: 1890 return 1 1891 else: 1892 return 0
1893
1894 -def scan(locals, *namelist, **kw):
1895 """Scan function sets parameters from line read from stdin 1896 1897 This can be used either as a function or as a task (it accepts 1898 redirection and the _save keyword.) 1899 """ 1900 # handle redirection and save keywords 1901 # other keywords are passed on to fscan 1902 redirKW, closeFHList = redirProcess(kw) 1903 if kw.has_key('_save'): del kw['_save'] 1904 resetList = redirApply(redirKW) 1905 try: 1906 line = _irafutils.tkreadline() 1907 # null line means EOF 1908 if line == "": 1909 _weirdEOF(locals, namelist) 1910 global _nscan 1911 _nscan = 0 1912 return EOF 1913 else: 1914 return apply(fscan, (locals, `line`) + namelist, kw) 1915 finally: 1916 # note return value not used here 1917 rv = redirReset(resetList, closeFHList)
1918
1919 -def scanf(locals, format, *namelist, **kw):
1920 """Formatted scan function sets parameters from line read from stdin 1921 1922 This can be used either as a function or as a task (it accepts 1923 redirection and the _save keyword.) 1924 """ 1925 # handle redirection and save keywords 1926 # other keywords are passed on to fscan 1927 redirKW, closeFHList = redirProcess(kw) 1928 if kw.has_key('_save'): del kw['_save'] 1929 resetList = redirApply(redirKW) 1930 try: 1931 line = _irafutils.tkreadline() 1932 # null line means EOF 1933 if line == "": 1934 _weirdEOF(locals, namelist) 1935 global _nscan 1936 _nscan = 0 1937 return EOF 1938 else: 1939 return apply(fscanf, (locals, `line`, format) + namelist, kw) 1940 finally: 1941 # note return value not used here 1942 rv = redirReset(resetList, closeFHList)
1943
1944 -def nscan():
1945 """Return number of items read in last scan function""" 1946 global _nscan 1947 return _nscan
1948
1949 # ----------------------------------------------------- 1950 # IRAF utility procedures 1951 # ----------------------------------------------------- 1952 1953 # these have extra keywords (redirection, _save) because they can 1954 # be called as tasks 1955 1956 @handleRedirAndSaveKwdsPlus 1957 -def set(*args, **kw):
1958 """Set IRAF environment variables""" 1959 if len(args) == 0: 1960 if len(kw) != 0: 1961 # normal case is only keyword,value pairs 1962 msg = [] 1963 for keyword, value in kw.items(): 1964 keyword = _irafutils.untranslateName(keyword) 1965 svalue = str(value) 1966 if keyword == "erract": 1967 irafecl.erract.adjust(svalue) 1968 else: 1969 # add keyword:svalue to the dict, but first check for '#' 1970 if svalue.find('#') > 0 and svalue.find("'") < 0 and \ 1971 svalue.find('"') < 0: 1972 # this can happen when translating .cl scripts with 1973 # vars with sequential commented-out continuation lines 1974 svalue = svalue[0:svalue.find('#')] 1975 _varDict[keyword] = svalue 1976 msg.append("set %s=%s\n" % (keyword, svalue)) 1977 _irafexecute.processCache.setenv("".join(msg)) 1978 else: 1979 # set with no arguments lists all variables (using same format 1980 # as IRAF) 1981 listVars(" ", "=") 1982 else: 1983 # The only other case allowed is the peculiar syntax 1984 # 'set @filename', which only gets used in the zzsetenv.def file, 1985 # where it reads extern.pkg. That file also gets read (in full cl 1986 # mode) by clpackage.cl. I get errors if I read this during 1987 # zzsetenv.def, so just ignore it here... 1988 # 1989 # Flag any other syntax as an error. 1990 if len(args) != 1 or len(kw) != 0 or \ 1991 (not isinstance(args[0],(str,unicode))) or args[0][:1] != '@': 1992 raise SyntaxError("set requires name=value pairs")
1993 1994 # currently do not distinguish set from reset 1995 # this will change when keep/bye/unloading are implemented 1996 1997 reset = set
1998 1999 @handleRedirAndSaveKwds 2000 -def show(*args):
2001 """Print value of IRAF or OS environment variables""" 2002 if len(args) and args[0].startswith("erract"): 2003 print irafecl.erract.states() 2004 else: 2005 if args: 2006 for arg in args: 2007 print envget(arg) 2008 else: 2009 # print them all 2010 listVars(" ", "=")
2011
2012 @handleRedirAndSaveKwds 2013 -def unset(*args):
2014 """Unset IRAF environment variables. 2015 This is not a standard IRAF task, but it is obviously useful. 2016 It makes the resulting variables undefined. It silently ignores 2017 variables that are not defined. It does not change the os environment 2018 variables. 2019 """ 2020 for arg in args: 2021 if _varDict.has_key(arg): 2022 del _varDict[arg]
2023
2024 @handleRedirAndSaveKwds 2025 -def time():
2026 """Print current time and date""" 2027 print _time.strftime('%a %H:%M:%S %d-%b-%Y')
2028
2029 # Note - we really should not give this a default (should require an int), 2030 # because why run "sleep 0"?, but some legacy .cl scripts call it that way. 2031 @handleRedirAndSaveKwds 2032 -def sleep(seconds=0):
2033 """Sleep for specified time""" 2034 _time.sleep(float(seconds))
2035
2036 -def beep(**kw):
2037 """Beep to terminal (even if output is redirected)""" 2038 # just ignore keywords 2039 _sys.__stdout__.write("") 2040 _sys.__stdout__.flush()
2041
2042 -def clOscmd(s, **kw):
2043 """Execute a system-dependent command in the shell, returning status""" 2044 2045 # handle redirection and save keywords 2046 redirKW, closeFHList = redirProcess(kw) 2047 if kw.has_key('_save'): del kw['_save'] 2048 if len(kw): 2049 raise TypeError('unexpected keyword argument: ' + `kw.keys()`) 2050 resetList = redirApply(redirKW) 2051 try: 2052 # if first character of s is '!' then force to Bourne shell 2053 if s[:1] == '!': 2054 shell = "/bin/sh" 2055 s = s[1:] 2056 else: 2057 # otherwise use default shell 2058 shell=None 2059 2060 # ignore null commands 2061 if not s: return 0 2062 2063 # use subshell to execute command so wildcards, etc. are handled 2064 status = _subproc.subshellRedir(s, shell=shell) 2065 return status 2066 2067 finally: 2068 rv = redirReset(resetList, closeFHList) 2069 return rv
2070 2071 _sttyArgs = _minmatch.MinMatchDict({ 2072 'terminal': None, 2073 'baud': 9600, 2074 'ncols': 80, 2075 'nlines': 24, 2076 'show': no, 2077 'all': no, 2078 'reset': no, 2079 'resize': no, 2080 'clear': no, 2081 'ucasein': no, 2082 'ucaseout': no, 2083 'login': None, 2084 'logio': None, 2085 'logout': None, 2086 'playback': None, 2087 'verify': no, 2088 'delay': 500, 2089 })
2090 2091 @handleRedirAndSaveKwdsPlus 2092 -def stty(terminal=None, **kw):
2093 """IRAF stty command (mainly not implemented)""" 2094 expkw = _sttyArgs.copy() 2095 if terminal is not None: expkw['terminal'] = terminal 2096 for key, item in kw.items(): 2097 if _sttyArgs.has_key(key): 2098 expkw[key] = item 2099 else: 2100 raise TypeError('unexpected keyword argument: '+key) 2101 if terminal is None and len(kw) == 0: 2102 # will need default values for the next step; try _wutil for them 2103 dftNcol = '80' 2104 dftNlin = '24' 2105 try: 2106 if _sys.stdout.isatty(): 2107 nlines,ncols = _wutil.getTermWindowSize() 2108 dftNcol = str(ncols) 2109 dftNlin = str(nlines) 2110 except: pass # No error message here - may not always be available 2111 # no args: print terminal type and size 2112 print '%s ncols=%s nlines=%s' % (envget('terminal','undefined'), 2113 envget('ttyncols',dftNcol), envget('ttynlines',dftNlin)) 2114 elif expkw['resize'] or expkw['terminal'] == "resize": 2115 # resize: sets CL env parameters giving screen size; show errors 2116 if _sys.stdout.isatty(): 2117 nlines,ncols = _wutil.getTermWindowSize() 2118 set(ttyncols=str(ncols), ttynlines=str(nlines)) 2119 elif expkw['terminal']: 2120 set(terminal=expkw['terminal']) 2121 # They are setting the terminal type. Let's at least try to 2122 # get the dimensions if not given. This is more than the CL does. 2123 if (not kw.has_key('nlines')) and (not kw.has_key('ncols')) and \ 2124 _sys.stdout.isatty(): 2125 try: 2126 nlines,ncols = _wutil.getTermWindowSize() 2127 set(ttyncols=str(ncols), ttynlines=str(nlines)) 2128 except: pass # No error msg here - may not always be available 2129 elif expkw['playback'] is not None: 2130 _writeError("stty playback not implemented")
2131
2132 @handleRedirAndSaveKwds 2133 -def eparam(*args):
2134 """Edit parameters for tasks. Starts up epar GUI.""" 2135 for taskname in args: 2136 try: # maybe it is an IRAF task 2137 taskname.eParam() 2138 except AttributeError: 2139 try: # maybe it is an IRAF task name 2140 getTask(taskname).eParam() 2141 except (KeyError, TypeError): 2142 try: # maybe it is a task which uses .cfg files 2143 _wrapTeal(taskname) 2144 except _teal.cfgpars.NoCfgFileError: 2145 _writeError('Warning: Could not find task "'+taskname+'"')
2146
2147 -def _wrapTeal(taskname):
2148 """ Wrap the call to TEAL. Try to use focus switching here. """ 2149 # place focus on gui 2150 oldFoc = _wutil.getFocalWindowID() 2151 _wutil.forceFocusToNewWindow() 2152 # pop up TEAL 2153 try: 2154 # use simple-auto-close mode (like EPAR) by no return dict 2155 _teal.teal(taskname, returnDict=False, errorsToTerm=True, 2156 raiseUnfound=True) 2157 # put focus back on terminal, even if there is an exception 2158 finally: 2159 _wutil.setFocusTo(oldFoc)
2160
2161 @handleRedirAndSaveKwds 2162 -def tparam(*args):
2163 """Edit parameters for tasks. Starts up epar GUI.""" 2164 for taskname in args: 2165 try: 2166 taskname.tParam() 2167 except AttributeError: 2168 # try: 2169 getTask(taskname).tParam()
2170 # except (KeyError, TypeError):
2171 # _writeError("Warning: Could not find task %s for tpar\n" % 2172 # taskname) 2173 2174 @handleRedirAndSaveKwds 2175 -def lparam(*args):
2176 """List parameters for tasks""" 2177 for taskname in args: 2178 try: 2179 taskname.lParam() 2180 except AttributeError: 2181 try: 2182 getTask(taskname).lParam() 2183 except (KeyError, TypeError): 2184 _writeError("Warning: Could not find task %s for lpar\n" % 2185 taskname)
2186
2187 @handleRedirAndSaveKwdsPlus 2188 -def dparam(*args, **kw):
2189 """Dump parameters for task in executable form""" 2190 # only keyword: pyraf-specific 'cl=' used to specify CL or Python syntax 2191 cl = 1 2192 if kw.has_key('cl'): 2193 cl = kw['cl'] 2194 del kw['cl'] 2195 if len(kw): 2196 raise TypeError('unexpected keyword argument: ' + `kw.keys()`) 2197 for taskname in args: 2198 try: 2199 taskname.dParam(cl=cl) 2200 except AttributeError: 2201 try: 2202 getTask(taskname).dParam(cl=cl) 2203 except (KeyError, TypeError): 2204 _writeError("Warning: Could not find task %s for dpar\n" % 2205 taskname)
2206
2207 @handleRedirAndSaveKwds 2208 -def update(*args):
2209 """Update task parameters on disk""" 2210 for taskname in args: 2211 try: 2212 getTask(taskname).saveParList() 2213 except KeyError, e: 2214 _writeError("Warning: Could not find task %s for update" % 2215 taskname)
2216
2217 @handleRedirAndSaveKwdsPlus 2218 -def unlearn(*args, **kw):
2219 """Unlearn task parameters -- restore to defaults""" 2220 force = False 2221 if 'force' in kw: 2222 force = kw['force'] in (True, '+', 'yes') 2223 del kw['force'] 2224 if len(kw): 2225 raise TypeError('unexpected keyword argument: ' + `kw.keys()`) 2226 for taskname in args: 2227 try: # maybe it is an IRAF task name 2228 getTask(taskname).unlearn() 2229 except KeyError, e: 2230 try: # maybe it is a task which uses .cfg files 2231 flist = _teal.cfgpars.getUsrCfgFilesForPyPkg(taskname) 2232 if flist == None or len(flist) == 0: 2233 pass # no need to be verbose 2234 elif len(flist) == 1: 2235 _os.remove(flist[0]) # don't be chatty here either 2236 else: 2237 if force: 2238 for f in flist: 2239 _os.remove(f) # don't be chatty 2240 else: 2241 _writeError('Error: multiple user-owned files found'+ \ 2242 ' to unlearn for task "'+taskname+ \ 2243 '".\nNone were deleted. Please review and move/'+ \ 2244 'delete these files:\n\t'+\ 2245 '\n\t'.join(flist)+ \ 2246 '\n\nor type "unlearn '+taskname+' force=yes"') 2247 except _teal.cfgpars.NoCfgFileError: 2248 _writeError("Warning: Could not find task %s to unlearn" % 2249 taskname)
2250
2251 2252 @handleRedirAndSaveKwdsPlus 2253 -def teal(taskArg, **kw):
2254 """ Synonym for epar. Open the TEAL GUI but keep logic in eparam. 2255 There is no return dict.""" 2256 eparam(taskArg, **kw)
2257
2258 @handleRedirAndSaveKwds 2259 -def edit(*args):
2260 """Edit text files""" 2261 editor = envget('editor') 2262 margs = map(Expand, args) 2263 _os.system(' '.join([editor,]+margs))
2264 2265 _clearString = None
2266 2267 @handleRedirAndSaveKwds 2268 -def clear(*args):
2269 """Clear screen if output is terminal""" 2270 global _clearString 2271 if not _os.path.exists('/usr/bin/tput'): 2272 _clearString = '' 2273 if _clearString is None: 2274 # get the clear command by running system clear 2275 fh = _StringIO.StringIO() 2276 try: 2277 clOscmd('/usr/bin/tput clear', Stdout=fh) 2278 _clearString = fh.getvalue() 2279 except SubprocessError: 2280 _clearString = "" 2281 fh.close() 2282 del fh 2283 if _sys.stdout == _sys.__stdout__: 2284 _sys.stdout.write(_clearString) 2285 _sys.stdout.flush()
2286
2287 @handleRedirAndSaveKwds 2288 -def flprcache(*args):
2289 """Flush process cache. Takes optional list of tasknames.""" 2290 apply(_irafexecute.processCache.flush, args) 2291 if Verbose>0: print "Flushed process cache"
2292
2293 @handleRedirAndSaveKwds 2294 -def prcacheOff():
2295 """Disable process cache. No process cache will be employed 2296 for the rest of this session.""" 2297 _irafexecute.processCache.setSize(0) 2298 if Verbose>0: print "Disabled process cache"
2299
2300 @handleRedirAndSaveKwds 2301 -def prcacheOn():
2302 """Re-enable process cache. A process cache will again be employed 2303 for the rest of this session. This may be useful after prcacheOff().""" 2304 _irafexecute.processCache.resetSize() 2305 if Verbose>0: print "Enabled process cache"
2306
2307 @handleRedirAndSaveKwds 2308 -def prcache(*args):
2309 """Print process cache. If args are given, locks tasks into cache.""" 2310 if args: 2311 apply(_irafexecute.processCache.lock, args) 2312 else: 2313 _irafexecute.processCache.list()
2314
2315 @handleRedirAndSaveKwds 2316 -def gflush():
2317 """Flush any buffered graphics output.""" 2318 import gki 2319 gki.kernel.flush()
2320
2321 @handleRedirAndSaveKwdsPlus 2322 -def pyexecute(filename, **kw):
2323 """Execute python code in filename (which may include IRAF path). 2324 This is callable from within CL scripts. There is a corresponding 2325 pyexecute.cl task that runs outside the PyRAF environment and just 2326 prints a warning. 2327 """ 2328 # these keyword parameters are relevant only outside PyRAF 2329 for keyword in ['_save', 'verbose', 'tasknames']: 2330 if kw.has_key(keyword): 2331 del kw[keyword] 2332 # get package info 2333 if kw.has_key('PkgName'): 2334 pkgname = kw['PkgName'] 2335 del kw['PkgName'] 2336 else: 2337 pkgname = curpack() 2338 if kw.has_key('PkgBinary'): 2339 pkgbinary = kw['PkgBinary'] 2340 del kw['PkgBinary'] 2341 else: 2342 pkgbinary = curPkgbinary() 2343 # fix illegal package names 2344 spkgname = pkgname.replace('.', '_') 2345 if spkgname != pkgname: 2346 _writeError("Warning: `.' illegal in task name, changing " 2347 "`%s' to `%s'" % (pkgname, spkgname)) 2348 pkgname = spkgname 2349 if len(kw): 2350 raise TypeError('unexpected keyword argument: ' + `kw.keys()`) 2351 # execute code in a new namespace (including PkgName, PkgBinary) 2352 efilename = Expand(filename) 2353 namespace = {'PkgName': pkgname, 'PkgBinary': pkgbinary, 2354 '__file__': efilename} 2355 execfile(efilename, namespace)
2356
2357 # history routines 2358 2359 @handleRedirAndSaveKwds 2360 -def history(n=20):
2361 """Print history. 2362 Does not replicate the IRAF behavior of changing default number of 2363 lines to print. (That seems fairly useless to me.) 2364 """ 2365 # Seems like there ought to be a way to do this using readline, but I have 2366 # not been able to figure out any readline command that lists the history 2367 import __main__ 2368 try: 2369 n = abs(int(n)) 2370 __main__._pycmdline.printHistory(n) 2371 except (NameError,AttributeError): 2372 pass
2373
2374 @handleRedirAndSaveKwds 2375 -def ehistory(*args):
2376 """Dummy history function""" 2377 print 'ehistory command not required: Use arrow keys to recall commands' 2378 print 'or ctrl-R to search for a string in the command history.'
2379
2380 # dummy routines (must allow *args and **kw) 2381 2382 @handleRedirAndSaveKwdsPlus 2383 -def clNoBackground(*args, **kw):
2384 """Dummy background function""" 2385 _writeError('Background jobs not implemented')
2386 2387 jobs = service = kill = wait = clNoBackground
2388 2389 # dummy (do-nothing) routines 2390 2391 -def clDummy(*args, **kw):
2392 """Dummy do-nothing function""" 2393 # just ignore keywords and arguments 2394 pass
2395 2396 bye = keep = logout = clbye = cache = language = clDummy
2397 2398 # unimplemented but no exception raised (and no message 2399 # printed if not in verbose mode) 2400 -def _notImplemented(cmd):
2401 """Dummy unimplemented function""" 2402 if Verbose>0: 2403 _writeError("The %s task has not been implemented" % cmd)
2404
2405 @handleRedirAndSaveKwdsPlus 2406 -def putlog(*args, **kw):
2407 _notImplemented('putlog')
2408
2409 @handleRedirAndSaveKwdsPlus 2410 -def clAllocate(*args, **kw):
2411 _notImplemented('_allocate')
2412
2413 @handleRedirAndSaveKwdsPlus 2414 -def clDeallocate(*args, **kw):
2415 _notImplemented('_deallocate')
2416
2417 @handleRedirAndSaveKwdsPlus 2418 -def clDevstatus(*args, **kw):
2419 _notImplemented('_devstatus')
2420
2421 # unimplemented -- raise exception 2422 2423 -def fprint(*args, **kw):
2424 """Error unimplemented function""" 2425 # The fprint task is never used in CL scripts, as far as I can tell 2426 raise IrafError("The fprint task has not been implemented")
2427
2428 # various helper functions 2429 2430 @handleRedirAndSaveKwds 2431 -def pkgHelp(pkgname=None):
2432 """Give help on package (equivalent to CL '? [taskname]')""" 2433 if pkgname is None: 2434 listCurrent() 2435 else: 2436 listTasks(pkgname)
2437
2438 @handleRedirAndSaveKwds 2439 -def allPkgHelp():
2440 """Give help on all packages (equivalent to CL '??')""" 2441 listTasks()
2442
2443 -def _clProcedure(*args, **kw):
2444 """Core function for the CL task 2445 2446 Gets passed to IrafPythonTask as function argument. 2447 Note I/O redirection has already been set up before calling this. 2448 """ 2449 # just ignore the arguments -- they are only used through .par list 2450 # if input is not redirected, don't do anything 2451 if _sys.stdin == _sys.__stdin__: 2452 return 2453 # initialize environment 2454 locals = {} 2455 exec 'from pyraf import iraf' in locals 2456 exec 'from pyraf.irafpar import makeIrafPar' in locals 2457 exec 'from stsci.tools.irafglobals import *' in locals 2458 exec 'from pyraf.pyrafglobals import *' in locals 2459 # feed the input to clExecute 2460 # redirect input to sys.__stdin__ after reading the CL script from sys.stdin 2461 clExecute(_sys.stdin.read(), locals=locals, Stdin=_sys.__stdin__)
2462
2463 -def clProcedure(input=None, mode="", DOLLARnargs=0, **kw):
2464 """Run CL commands from a file (cl < input) -- OBSOLETE 2465 2466 This is obsolete, replaced by the IrafPythonTask version of 2467 the cl, using above _clProcedure function. It is being 2468 retained only for backward compatibility since translated 2469 versions of CL scripts could use it. New versions will 2470 not use it. Also, this cannot use handleRedirAndSaveKwds. 2471 """ 2472 # handle redirection and save keywords 2473 redirKW, closeFHList = redirProcess(kw) 2474 if kw.has_key('_save'): del kw['_save'] 2475 if len(kw): 2476 raise TypeError('unexpected keyword argument: ' + `kw.keys()`) 2477 # get the input 2478 if redirKW.has_key('stdin'): 2479 stdin = redirKW['stdin'] 2480 del redirKW['stdin'] 2481 if hasattr(stdin,'name'): 2482 filename = stdin.name.split('.')[0] 2483 else: 2484 filename = 'tmp' 2485 elif input is not None: 2486 if isinstance(input,(str,unicode)): 2487 # input is a string -- stick it in a StringIO buffer 2488 stdin = _StringIO.StringIO(input) 2489 filename = input 2490 elif hasattr(input,'read'): 2491 # input is a filehandle 2492 stdin = input 2493 if hasattr(stdin,'name'): 2494 filename = stdin.name.split('.')[0] 2495 else: 2496 filename = 'tmp' 2497 else: 2498 raise TypeError("Input must be a string or input filehandle") 2499 else: 2500 # CL without input does nothing 2501 return 2502 # apply the I/O redirections 2503 resetList = redirApply(redirKW) 2504 # create and run the task 2505 try: 2506 # create task object with no package 2507 newtask = _iraftask.IrafCLTask('', filename, '', stdin, '', '') 2508 newtask.run() 2509 finally: 2510 # reset the I/O redirections 2511 rv = redirReset(resetList, closeFHList) 2512 return rv
2513
2514 @handleRedirAndSaveKwds 2515 -def hidetask(*args):
2516 """Hide the CL task in package listings""" 2517 for taskname in args: 2518 try: 2519 getTask(taskname).setHidden() 2520 except KeyError, e: 2521 _writeError("Warning: Could not find task %s to hide" % 2522 taskname)
2523 2524 # pattern matching single task name, possibly with $ prefix and/or 2525 # .pkg or .tb suffix 2526 # also matches optional trailing comma and whitespace 2527 2528 optional_whitespace = r'[ \t]*' 2529 taskname = r'(?:' + r'(?P<taskprefix>\$?)' + \ 2530 r'(?P<taskname>[a-zA-Z_][a-zA-Z0-9_]*)' + \ 2531 r'(?P<tasksuffix>\.(?:pkg|tb))?' + \ 2532 r',?' + optional_whitespace + r')' 2533 2534 _re_taskname = _re.compile(taskname) 2535 2536 del taskname, optional_whitespace
2537 2538 @handleRedirAndSaveKwdsPlus 2539 -def task(*args, **kw):
2540 """Define IRAF tasks""" 2541 redefine = 0 2542 iscmdstring = False 2543 if kw.has_key('Redefine'): 2544 redefine = kw['Redefine'] 2545 del kw['Redefine'] 2546 # get package info 2547 if kw.has_key('PkgName'): 2548 pkgname = kw['PkgName'] 2549 del kw['PkgName'] 2550 else: 2551 pkgname = curpack() 2552 if kw.has_key('PkgBinary'): 2553 pkgbinary = kw['PkgBinary'] 2554 del kw['PkgBinary'] 2555 else: 2556 pkgbinary = curPkgbinary() 2557 if kw.has_key('IsCmdString'): 2558 iscmdstring = kw['IsCmdString'] 2559 del kw['IsCmdString'] 2560 # fix illegal package names 2561 spkgname = pkgname.replace('.', '_') 2562 if spkgname != pkgname: 2563 _writeError("Warning: `.' illegal in task name, changing " 2564 "`%s' to `%s'" % (pkgname, spkgname)) 2565 pkgname = spkgname 2566 # get the task name 2567 if len(kw) > 1: 2568 raise SyntaxError("More than one `=' in task definition") 2569 elif len(kw) < 1: 2570 raise SyntaxError("Must be at least one `=' in task definition") 2571 s = kw.keys()[0] 2572 value = kw[s] 2573 # To handle when actual CL code is given, not a file name, we will 2574 # replace the code with the name of the tmp file that we write it to. 2575 if iscmdstring: 2576 # write it to a temp file in the home$ dir, then use filename 2577 (fd, tmpCl) = _tempfile.mkstemp(suffix=".cl", prefix=str(s)+'_', 2578 dir=userIrafHome, text=True) 2579 _os.close(fd) 2580 # check for invalid chars as far as python function names go. 2581 # yes this goes against the use of mkstemp from a purity point 2582 # of view but it can't much be helped 2583 tmpClorig = tmpCl 2584 tmpCl = tmpCl.replace('-','_') 2585 tmpCl = tmpCl.replace('+','_') 2586 assert tmpClorig == tmpCl or not _os.path.exists(tmpCl), \ 2587 'Abused mkstemp fname: '+tmpCl 2588 # write inline code to .cl file; len(kw) is checked below 2589 f = open(tmpCl, 'w') 2590 f.write(value+'\n') 2591 # Add text at end to auto-delete this temp file 2592 f.write('#\n# this last section automatically added\n') 2593 f.write('delete '+tmpCl+' verify-\n') 2594 f.close() 2595 # exchange for tmp .cl file name 2596 value = tmpCl 2597 2598 # untranslateName 2599 s = _irafutils.untranslateName(s) 2600 args = args + (s,) 2601 2602 # assign value to each task in the list 2603 global _re_taskname 2604 for tlist in args: 2605 mtl = _re_taskname.match(tlist) 2606 if not mtl: 2607 raise SyntaxError("Illegal task name `%s'" % (tlist,)) 2608 name = mtl.group('taskname') 2609 prefix = mtl.group('taskprefix') 2610 suffix = mtl.group('tasksuffix') 2611 newtask = IrafTaskFactory(prefix,name,suffix,value, 2612 pkgname,pkgbinary,redefine=redefine)
2613
2614 -def redefine(*args, **kw):
2615 """Redefine an existing task""" 2616 kw['Redefine'] = 1 2617 apply(task, args, kw)
2618
2619 -def package(pkgname=None, bin=None, PkgName='', PkgBinary='', **kw):
2620 """Define IRAF package, returning tuple with new package name and binary 2621 2622 PkgName, PkgBinary are old default values. If Stdout=1 is specified, 2623 returns output as string array (normal task behavior) instead of 2624 returning PkgName, PkgBinary. This inconsistency is necessary 2625 to replicate the inconsistent behavior of the package command 2626 in IRAF. 2627 """ 2628 2629 module = irafecl.getTaskModule() 2630 2631 # handle redirection and save keywords 2632 redirKW, closeFHList = redirProcess(kw) 2633 if kw.has_key('_save'): del kw['_save'] 2634 if len(kw): 2635 raise TypeError('unexpected keyword argument: ' + `kw.keys()`) 2636 resetList = redirApply(redirKW) 2637 try: 2638 if pkgname is None: 2639 # no argument: list all loaded packages in search order 2640 printed = {} 2641 lp = loadedPath[:] 2642 lp.reverse() 2643 for pkg in lp: 2644 pkgname = pkg.getName() 2645 if not printed.has_key(pkgname): 2646 printed[pkgname] = 1 2647 print ' %s' % pkgname 2648 rv1 = (PkgName, PkgBinary) 2649 else: 2650 spkgname = pkgname.replace('.', '_') 2651 # remove trailing comma 2652 if spkgname[-1:] == ",": spkgname = spkgname[:-1] 2653 if (spkgname != pkgname) and (Verbose > 0): 2654 _writeError("Warning: illegal characters in task name, " 2655 "changing `%s' to `%s'" % (pkgname, spkgname)) 2656 pkgname = spkgname 2657 # is the package defined? 2658 # if not, is there a CL task by this name? 2659 # otherwise there is an error 2660 pkg = getPkg(pkgname, found=1) 2661 if pkg is None: 2662 pkg = getTask(pkgname, found=1) 2663 if pkg is None or not isinstance(pkg,_iraftask.IrafCLTask) or \ 2664 pkg.getName() != pkgname: 2665 raise KeyError("Package `%s' not defined" % pkgname) 2666 # Hack city -- there is a CL task with the package name, but it was 2667 # not defined to be a package. Convert it to an IrafPkg object. 2668 2669 module.mutateCLTask2Pkg(pkg) 2670 2671 # We must be currently loading this package if we encountered 2672 # its package statement (XXX can I confirm that?). 2673 # Add it to the lists of loaded packages (this usually 2674 # is done by the IrafPkg run method, but we are executing 2675 # as an IrafCLTask instead.) 2676 2677 _addPkg(pkg) 2678 loadedPath.append(pkg) 2679 addLoaded(pkg) 2680 if Verbose>0: _writeError("Warning: CL task `%s' apparently is " 2681 "a package" % pkgname) 2682 2683 # Make sure that this is the current package, even 2684 # if another package was loaded in the package script 2685 # but before the package statement 2686 if loadedPath[-1] is not pkg: loadedPath.append(pkg) 2687 2688 rv1 = (pkgname, bin or PkgBinary) 2689 finally: 2690 rv = redirReset(resetList, closeFHList) 2691 # return output as array of strings if not None, else return name,bin 2692 return rv or rv1
2693
2694 @handleRedirAndSaveKwds 2695 -def clPrint(*args):
2696 """CL print command -- emulates CL spacing and uses redirection keywords""" 2697 for arg in args: 2698 print arg, 2699 # don't put spaces after string arguments 2700 if isinstance(arg,(str,unicode)): _sys.stdout.softspace=0 2701 print
2702
2703 # printf format conversion utilities 2704 2705 -def _quietConv(w, d, c, args, i):
2706 """Format codes that are quietly converted to %s""" 2707 return "%%%ss" % w
2708
2709 -def _boolConv(w, d, c, args, i):
2710 """Boolean gets converted to upper case before printing""" 2711 args[i] = str(args[i]).upper() 2712 return "%%%ss" % w
2713
2714 -def _badConv(w, d, c, args, i):
2715 """Format codes that are converted to %s with warning""" 2716 _writeError("Warning: printf cannot handle format '%%%s', " 2717 "using '%%%ss' instead\n" % (w+d+c, w)) 2718 return "%%%ss" % w
2719
2720 -def _hConv(w, d, c, args, i):
2721 """Handle %h %m %H %M dd:mm:ss.s formats""" 2722 if i<len(args): 2723 try: 2724 if d[1:]: 2725 digits = int(d[1:]) 2726 else: 2727 digits = 1 2728 if c in "HM": 2729 # capital letters convert from degrees to hours (undocumented) 2730 value = args[i]/15.0 2731 else: 2732 value = args[i] 2733 args[i] = clDms(value, digits=digits, seconds=c not in "mM") 2734 except ValueError: 2735 pass 2736 return "%%%ss" % w
2737
2738 -def _rConv(w, d, c, args, i):
2739 """Handle W.DrN general radix format""" 2740 if i<len(args): 2741 try: 2742 base = int(c[-1]) 2743 except ValueError: 2744 base = 10 2745 if w[:1] == "0": 2746 # add leading zeros 2747 args[i] = radix(args[i], base, length=int(w)) 2748 else: 2749 args[i] = radix(args[i], base) 2750 return "%%%ss" % w
2751
2752 -def _wConv(w, d, c, args, i):
2753 """Handle %w format, which is supposed to generate spaces""" 2754 if i<len(args) and not w: 2755 # number of spaces comes from argument 2756 if args[i] == INDEF: 2757 w = 0 2758 else: 2759 try: 2760 w = int(args[i]) 2761 except ValueError: 2762 w = 0 2763 args[i] = "" 2764 return "%%%ss" % w
2765 2766 # pattern matching %w.dc where c is single letter format code 2767 _reFormat = _re.compile(r"%(?P<w>-?\d*)(?P<d>(?:\.\d*)?)(?P<c>[a-zHM])") 2768 2769 # dispatch table for format conversions 2770 _fDispatch = {} 2771 for b in _string.ascii_lowercase: _fDispatch[b] = None 2772 2773 # formats that get quietly converted to uppercase and translated to %s 2774 badList = ["b"] 2775 for b in badList: _fDispatch[b] = _boolConv 2776 2777 # formats that get translated to %s with warning 2778 badList = ["t", "z"] 2779 for b in badList: _fDispatch[b] = _badConv 2780 2781 # other cases 2782 _fDispatch["r"] = _rConv 2783 _fDispatch["w"] = _wConv 2784 _fDispatch["h"] = _hConv 2785 _fDispatch["m"] = _hConv 2786 _fDispatch["H"] = _hConv 2787 _fDispatch["M"] = _hConv 2788 2789 del badList, b
2790 2791 @handleRedirAndSaveKwds 2792 -def printf(format, *args):
2793 """Formatted print function""" 2794 # make argument list mutable 2795 args = list(args) 2796 newformat = [] 2797 # find all format strings and translate them (and arg) if needed 2798 iend = 0 2799 mm = _reFormat.search(format, iend) 2800 i = 0 2801 while mm: 2802 oend = iend 2803 istart = mm.start() 2804 iend = mm.end() 2805 # append the stuff preceding the format 2806 newformat.append(format[oend:istart]) 2807 c = mm.group('c') 2808 # special handling for INDEF arguments 2809 if args[i] == INDEF and c != 'w': 2810 # INDEF always gets printed as string except for '%w' format 2811 f = _quietConv 2812 else: 2813 # dispatch function for this format type 2814 f = _fDispatch[c] 2815 if f is None: 2816 # append the format 2817 newformat.append(mm.group()) 2818 else: 2819 w = mm.group('w') 2820 d = mm.group('d') 2821 # ugly special case for 'r' format 2822 if c == 'r': 2823 c = format[iend-1:iend+1] 2824 iend = iend+1 2825 # append the modified format 2826 newformat.append(f(w, d, c, args, i)) 2827 mm = _reFormat.search(format, iend) 2828 i = i+1 2829 newformat.append(format[iend:]) 2830 format = ''.join(newformat) 2831 # finally ready to print 2832 try: 2833 _sys.stdout.write(format % tuple(args)) 2834 _sys.stdout.flush() 2835 except ValueError, e: 2836 raise IrafError(str(e)) 2837 except TypeError, e: 2838 raise IrafError('%s\nFormat/datatype mismatch in printf ' 2839 '(format is %s)' % (str(e), `format`))
2840 2841 # _backDir is previous working directory 2842 2843 _backDir = None
2844 2845 @handleRedirAndSaveKwds 2846 -def pwd():
2847 """Print working directory""" 2848 print _os.getcwd()
2849
2850 @handleRedirAndSaveKwds 2851 -def chdir(directory=None):
2852 """Change working directory""" 2853 global _backDir 2854 try: 2855 _newBack = _os.getcwd() 2856 except OSError: 2857 # OSError for getcwd() means current directory does not exist 2858 _newBack = _backDir 2859 if directory is None: 2860 # use startup directory as home if argument is omitted 2861 directory = userWorkingHome 2862 if not isinstance(directory, (str,unicode)): 2863 raise IrafError("Illegal non-string value for directory:"+ \ 2864 +repr(directory)) 2865 if iraf.Verbose > 2: print('chdir to: '+str(directory)) 2866 # Check for (1) local directory and (2) iraf variable 2867 # when given an argument like 'dev'. In IRAF 'cd dev' is 2868 # the same as 'cd ./dev' if there is a local directory named 2869 # dev but is equivalent to 'cd dev$' if there is no local 2870 # directory. 2871 try: 2872 edir = Expand(directory) 2873 _os.chdir(edir) 2874 _backDir = _newBack 2875 _irafexecute.processCache.setenv('chdir %s\n' % edir) 2876 except (IrafError, OSError): 2877 try: 2878 edir = Expand(directory + '$') 2879 _os.chdir(edir) 2880 _backDir = _newBack 2881 _irafexecute.processCache.setenv('chdir %s\n' % edir) 2882 except (IrafError, OSError): 2883 raise IrafError("Cannot change directory to `%s'" % (directory,))
2884 2885 cd = chdir
2886 2887 @handleRedirAndSaveKwds 2888 -def back():
2889 """Go back to previous working directory""" 2890 global _backDir 2891 if _backDir is None: 2892 raise IrafError("no previous directory for back()") 2893 try: 2894 _newBack = _os.getcwd() 2895 except OSError: 2896 # OSError for getcwd() means current directory does not exist 2897 _newBack = _backDir 2898 _os.chdir(_backDir) 2899 print _backDir 2900 _irafexecute.processCache.setenv('chdir %s\n' % _backDir) 2901 _backDir = _newBack
2902
2903 -def error(errno=0,errmsg='',task="error",_save=False, suppress=True):
2904 """Print error message""" 2905 e = IrafError("ERROR: %s\n" % errmsg, errno=errno, errmsg=errmsg, errtask=task) 2906 e._ecl_suppress_first_trace = suppress 2907 raise e
2908
2909 -def errno(_save=None):
2910 """Returns status from last call to error()""" 2911 return irafecl._ecl_parent_task().DOLLARerrno
2912 2913 errcode = errno
2914 2915 -def errmsg(_save=None):
2916 """Returns message from last call to error()""" 2917 irafecl._ecl_parent_task().DOLLARerrmsg
2918
2919 -def errtask(_save=None):
2920 """Returns task from last call to error()""" 2921 return irafecl._ecl_parent_task().DOLLARerrtask
2922 2923 # ----------------------------------------------------- 2924 # clCompatibilityMode: full CL emulation (with Python 2925 # syntax accessible only through !P escape) 2926 # ----------------------------------------------------- 2927 2928 _exitCommands = { 2929 "logout": 1, 2930 "exit": 1, 2931 "quit": 1, 2932 ".exit": 1, 2933 }
2934 2935 -def clCompatibilityMode(verbose=0, _save=0):
2936 2937 """Start up full CL-compatibility mode""" 2938 2939 import traceback, __main__ 2940 if verbose: 2941 vmode = ' (verbose)' 2942 else: 2943 vmode = '' 2944 print 'Entering CL-compatibility%s mode...' % vmode 2945 2946 # logging may be active if Monty is in use 2947 if hasattr(__main__,'_pycmdline'): 2948 logfile = __main__._pycmdline.logfile 2949 else: 2950 logfile = None 2951 2952 locals = {} 2953 local_vars_dict = {} 2954 local_vars_list = [] 2955 # initialize environment 2956 exec 'from pyraf import iraf' in locals 2957 exec 'from pyraf.irafpar import makeIrafPar' in locals 2958 exec 'from stsci.tools.irafglobals import *' in locals 2959 exec 'from pyraf.pyrafglobals import *' in locals 2960 exec 'from pyraf.irafecl import EclState' in locals 2961 prompt2 = '>>> ' 2962 while (1): 2963 try: 2964 if not _sys.stdin.isatty(): 2965 prompt = '' 2966 elif loadedPath: 2967 prompt = loadedPath[-1].getName()[:2] + '> ' 2968 else: 2969 prompt = 'cl> ' 2970 line = raw_input(prompt) 2971 # simple continuation escape handling 2972 while line[-1:] == '\\': 2973 line = line + '\n' + raw_input(prompt2) 2974 line = line.strip() 2975 if _exitCommands.has_key(line): 2976 break 2977 elif line[:2] == '!P': 2978 # Python escape -- execute Python code 2979 exec line[2:].strip() in locals 2980 elif line and (line[0] != '#'): 2981 code = clExecute(line, locals=locals, mode='single', 2982 local_vars_dict=local_vars_dict, 2983 local_vars_list=local_vars_list) 2984 if logfile is not None: 2985 # log CL code as comment 2986 cllines = line.split('\n') 2987 for oneline in cllines: 2988 logfile.write('# '+oneline+'\n') 2989 logfile.write(code) 2990 logfile.flush() 2991 if verbose: 2992 print '----- Python -----' 2993 print code, 2994 print '------------------' 2995 except EOFError: 2996 break 2997 except KeyboardInterrupt: 2998 _writeError("Use `logout' or `.exit' to exit CL-compatibility mode") 2999 except: 3000 _sys.stdout.flush() 3001 traceback.print_exc() 3002 print 3003 print 'Leaving CL-compatibility mode...'
3004
3005 # ----------------------------------------------------- 3006 # clArray: IRAF array class with type checking 3007 # Note that subscripts start zero, in Python style -- 3008 # the CL-to-Python translation takes care of the offset 3009 # in CL code, and Python code should use zero-based 3010 # subscripts. 3011 # ----------------------------------------------------- 3012 3013 -def clArray(array_size, datatype, name="<anonymous>", mode="h", 3014 min=None, max=None, enum=None, prompt=None, 3015 init_value=None, strict=0):
3016 """Create an IrafPar object that can be used as a CL array""" 3017 try: 3018 return _irafpar.makeIrafPar(init_value, name=name, datatype=datatype, 3019 mode=mode, min=min, max=max, enum=enum, prompt=prompt, 3020 array_size=array_size, strict=strict) 3021 except ValueError, e: 3022 raise ValueError("Error creating Cl array `%s'\n%s" % 3023 (name, str(e)))
3024 3025 # ----------------------------------------------------- 3026 # clExecute: execute a single cl statement 3027 # ----------------------------------------------------- 3028 3029 # count number of CL tasks currently executing 3030 # used to give unique name to each one 3031 _clExecuteCount = 0
3032 3033 -def clExecute(s, locals=None, mode="proc", 3034 local_vars_dict={}, local_vars_list=[], verbose=0, **kw):
3035 """Execute a single cl statement""" 3036 # handle redirection keywords 3037 3038 redirKW, closeFHList = redirProcess(kw) 3039 if len(kw): 3040 raise TypeError('unexpected keyword argument: ' + `kw.keys()`) 3041 resetList = redirApply(redirKW) 3042 try: 3043 global _clExecuteCount 3044 _clExecuteCount = _clExecuteCount + 1 3045 pycode = _cl2py.cl2py(string=s, mode=mode, local_vars_dict=local_vars_dict, 3046 local_vars_list=local_vars_list) 3047 # use special scriptname 3048 taskname = "CL%s" % (_clExecuteCount,) 3049 scriptname = "<CL script %s>" % (taskname,) 3050 code = pycode.code.lstrip() #XXX needed? 3051 # force compile to inherit future division so we don't rely on 2.x div. 3052 codeObject = compile(code,scriptname,'exec',0,0) 3053 # add this script to linecache 3054 codeLines = code.split('\n') 3055 _linecache.cache[scriptname] = (0,0,codeLines,taskname) 3056 if locals is None: locals = {} 3057 exec codeObject in locals 3058 if pycode.vars.proc_name: 3059 exec pycode.vars.proc_name+"(taskObj=iraf.cl)" in locals 3060 return code 3061 finally: 3062 _clExecuteCount = _clExecuteCount - 1 3063 # note return value not used 3064 rv = redirReset(resetList, closeFHList)
3065
3066 3067 -def clLineToPython(line):
3068 """Returns the Python code corresponding to a single cl statement.""" 3069 pycode = _cl2py.cl2py(string=line, mode='single', 3070 local_vars_dict={}, 3071 local_vars_list=[]) 3072 code = pycode.code 3073 if pycode.vars.proc_name: 3074 code += pycode.vars.proc_name+"(taskObj=iraf.cl)\n" 3075 return code.lstrip()
3076 3077 # ----------------------------------------------------- 3078 # Expand: Expand a string with embedded IRAF variables 3079 # (IRAF virtual filename) 3080 # ----------------------------------------------------- 3081 3082 # Input string is in format 'name$rest' or 'name$str(name2)' where 3083 # name and name2 are defined in the _varDict dictionary. The 3084 # name2 string may have embedded dollar signs, which are ignored. 3085 # There may be multiple embedded parenthesized variable names. 3086 # 3087 # Returns string with IRAF variable name expanded to full host name. 3088 # Input may also be a comma-separated list of strings to Expand, 3089 # in which case an expanded comma-separated list is returned. 3090 3091 # search for leading string without embedded '$' 3092 __re_var_match = _re.compile(r'(?P<varname>[^$]*)\$') 3093 3094 # search for string embedded in parentheses 3095 __re_var_paren = _re.compile(r'\((?P<varname>[^()]*)\)')
3096 3097 -def Expand(instring, noerror=0):
3098 """Expand a string with embedded IRAF variables (IRAF virtual filename) 3099 3100 Allows comma-separated lists. Also uses os.path.expanduser to 3101 replace '~' symbols. 3102 Set noerror flag to silently replace undefined variables with just 3103 the variable name or null (so Expand('abc$def') = 'abcdef' and 3104 Expand('(abc)def') = 'def'). This is the IRAF behavior, though it 3105 is confusing and hides errors. 3106 """ 3107 # call _expand1 for each entry in comma-separated list 3108 wordlist = instring.split(",") 3109 outlist = [] 3110 for word in wordlist: 3111 outlist.append(_os.path.expanduser(_expand1(word, noerror=noerror))) 3112 return ",".join(outlist)
3113
3114 -def _expand1(instring, noerror):
3115 """Expand a string with embedded IRAF variables (IRAF virtual filename)""" 3116 # first expand names in parentheses 3117 # note this works on nested names too, expanding from the 3118 # inside out (just like IRAF) 3119 mm = __re_var_paren.search(instring) 3120 while mm is not None: 3121 # remove embedded dollar signs from name 3122 varname = mm.group('varname').replace('$','') 3123 if defvar(varname): 3124 varname = envget(varname) 3125 elif noerror: 3126 varname = "" 3127 else: 3128 raise IrafError("Undefined variable `%s' in string `%s'" % 3129 (varname, instring)) 3130 instring = instring[:mm.start()] + varname + instring[mm.end():] 3131 mm = __re_var_paren.search(instring) 3132 # now expand variable name at start of string 3133 mm = __re_var_match.match(instring) 3134 if mm is None: 3135 return instring 3136 varname = mm.group('varname') 3137 if defvar(varname): 3138 # recursively expand string after substitution 3139 return _expand1(envget(varname) + instring[mm.end():], noerror) 3140 elif noerror: 3141 return _expand1(varname + instring[mm.end():], noerror) 3142 else: 3143 raise IrafError("Undefined variable `%s' in string `%s'" % 3144 (varname, instring))
3145
3146 -def IrafTaskFactory(prefix='', taskname=None, suffix='', value=None, 3147 pkgname=None, pkgbinary=None, redefine=0, function=None):
3148 3149 """Returns a new or existing IrafTask, IrafPset, or IrafPkg object 3150 3151 Type of returned object depends on value of suffix and value. 3152 3153 Returns a new object unless this task or package is already 3154 defined. In that case if the old task appears consistent with 3155 the new task, a reference to the old task is returned. 3156 Otherwise a warning is printed and a reference to a new task is 3157 returned. 3158 3159 If redefine keyword is set, the behavior is the same except 3160 a warning is printed if it does *not* exist. 3161 """ 3162 3163 module = irafecl.getTaskModule() 3164 3165 if pkgname is None: 3166 pkgname = curpack() 3167 if pkgbinary is None: 3168 pkgbinary = curPkgbinary() 3169 elif pkgbinary is None: 3170 pkgbinary = '' 3171 # fix illegal names 3172 spkgname = pkgname.replace('.', '_') 3173 if spkgname != pkgname: 3174 _writeError("Warning: `.' illegal in package name, changing " 3175 "`%s' to `%s'" % (pkgname, spkgname)) 3176 pkgname = spkgname 3177 3178 staskname = taskname.replace('.', '_') 3179 if staskname != taskname: 3180 _writeError("Warning: `.' illegal in task name, changing " 3181 "`%s' to `%s'" % (taskname, staskname)) 3182 taskname = staskname 3183 3184 if suffix == '.pkg': 3185 return IrafPkgFactory(prefix,taskname,suffix,value,pkgname,pkgbinary, 3186 redefine=redefine) 3187 3188 root, ext = _os.path.splitext(value) 3189 if ext == '.par' and function is None: 3190 return IrafPsetFactory(prefix,taskname,suffix,value,pkgname,pkgbinary, 3191 redefine=redefine) 3192 3193 # normal task definition 3194 3195 fullname = pkgname + '.' + taskname 3196 # existing task object (if any) 3197 task = _tasks.get(fullname) 3198 if task is None and redefine: 3199 _writeError("Warning: `%s' is not a defined task" % taskname) 3200 3201 if function is not None: 3202 newtask = module.IrafPythonTask(prefix,taskname,suffix,value, 3203 pkgname,pkgbinary,function=function) 3204 elif ext == '.cl': 3205 newtask = module.IrafCLTask(prefix,taskname,suffix,value, 3206 pkgname,pkgbinary) 3207 elif value[:1] == '$': 3208 newtask = module.IrafForeignTask(prefix,taskname,suffix,value, 3209 pkgname,pkgbinary) 3210 else: 3211 newtask = module.IrafTask(prefix,taskname,suffix,value, 3212 pkgname,pkgbinary) 3213 if task is not None: 3214 # check for consistency of definition by comparing to the 3215 # new object 3216 if not task.isConsistent(newtask): 3217 # looks different -- print warning and continue 3218 if not redefine: 3219 _writeError("Warning: `%s' is a task redefinition" % 3220 fullname) 3221 else: 3222 # new task is consistent with old task, so return old task 3223 if task.getPkgbinary() != newtask.getPkgbinary(): 3224 # package binary differs -- add it to search path 3225 if Verbose>1: print 'Adding',pkgbinary,'to',task,'path' 3226 task.addPkgbinary(pkgbinary) 3227 return task 3228 # add it to the task list 3229 _addTask(newtask) 3230 return newtask
3231
3232 -def IrafPsetFactory(prefix,taskname,suffix,value,pkgname,pkgbinary, 3233 redefine=0):
3234 3235 """Returns a new or existing IrafPset object 3236 3237 Returns a new object unless this task is already 3238 defined. In that case if the old task appears consistent with 3239 the new task, a reference to the old task is returned. 3240 Otherwise a warning is printed and a reference to a new task is 3241 returned. 3242 3243 If redefine keyword is set, the behavior is the same except 3244 a warning is printed if it does *not* exist. 3245 """ 3246 3247 module = irafecl.getTaskModule() 3248 3249 fullname = pkgname + '.' + taskname 3250 task = _tasks.get(fullname) 3251 if task is None and redefine: 3252 _writeError("Warning: `%s' is not a defined task" % taskname) 3253 3254 newtask = module.IrafPset(prefix,taskname,suffix,value,pkgname,pkgbinary) 3255 if task is not None: 3256 # check for consistency of definition by comparing to the new 3257 # object (which will be discarded) 3258 if task.getFilename() != newtask.getFilename(): 3259 if redefine: 3260 _writeError("Warning: `%s' is a task redefinition" % 3261 fullname) 3262 else: 3263 # old version of task is same as new 3264 return task 3265 # add it to the task list 3266 _addTask(newtask) 3267 return newtask
3268
3269 -def IrafPkgFactory(prefix,taskname,suffix,value,pkgname,pkgbinary, 3270 redefine=0):
3271 3272 """Returns a new or existing IrafPkg object 3273 3274 Returns a new object unless this package is already defined, in which case 3275 a warning is printed and a reference to the existing task is returned. 3276 Redefine parameter currently ignored. 3277 3278 Returns a new object unless this package is already 3279 defined. In that case if the old package appears consistent with 3280 the new package, a reference to the old package is returned. 3281 Else if the old package has already been loaded, a warning 3282 is printed and the redefinition is ignored. 3283 Otherwise a warning is printed and a reference to a new package is 3284 returned. 3285 3286 If redefine keyword is set, the behavior is the same except 3287 a warning is printed if it does *not* exist. 3288 """ 3289 3290 module = irafecl.getTaskModule() 3291 3292 # does package with exactly this name exist in minimum-match 3293 # dictionary _pkgs? 3294 pkg = _pkgs.get_exact_key(taskname) 3295 if pkg is None and redefine: 3296 _writeError("Warning: `%s' is not a defined task" % taskname) 3297 newpkg = module.IrafPkg(prefix,taskname,suffix,value,pkgname,pkgbinary) 3298 if pkg is not None: 3299 if pkg.getFilename() != newpkg.getFilename() or \ 3300 pkg.hasParfile() != newpkg.hasParfile(): 3301 if pkg.isLoaded(): 3302 _writeError("Warning: currently loaded package `%s' was not " 3303 "redefined" % taskname) 3304 return pkg 3305 else: 3306 if not redefine: 3307 _writeError("Warning: `%s' is a task redefinition" % 3308 taskname) 3309 _addPkg(newpkg) 3310 return newpkg 3311 if pkg.getPkgbinary() != newpkg.getPkgbinary(): 3312 # only package binary differs -- add it to search path 3313 if Verbose>1: print 'Adding',pkgbinary,'to',pkg,'path' 3314 pkg.addPkgbinary(pkgbinary) 3315 if pkgname != pkg.getPkgname(): 3316 # add existing task as an item in the new package 3317 _addTask(pkg,pkgname=pkgname) 3318 return pkg 3319 _addPkg(newpkg) 3320 return newpkg
3321
3322 3323 # ----------------------------------------------------- 3324 # Utilities to handle I/O redirection keywords 3325 # ----------------------------------------------------- 3326 3327 -def redirProcess(kw):
3328 3329 """Process Stdout, Stdin, Stderr keywords used for redirection 3330 3331 Removes the redirection keywords from kw 3332 Returns (redirKW, closeFHList) which are a dictionary of 3333 the filehandles for stdin, stdout, stderr and a list of 3334 filehandles to close after execution. 3335 3336 Image and Stdplot redirection not handled (but it isn't clear that these 3337 are ever used anyway) 3338 """ 3339 3340 redirKW = {} 3341 closeFHList = [] 3342 # Dictionary of redirection keywords 3343 # Values are (outputFlag, standardName, openArgs) 3344 # Still need to add graphics redirection keywords 3345 redirDict = { 3346 'Stdin': (0, "stdin", "r"), 3347 'Stdout': (1, "stdout", "w"), 3348 'StdoutAppend': (1, "stdout", "a"), 3349 'Stderr': (1, "stderr", "w"), 3350 'StderrAppend': (1, "stderr", "a"), 3351 'StdoutG': (1, "stdgraph", "w"), 3352 'StdoutAppendG': (1, "stdgraph", "a") 3353 } 3354 # Magic values that trigger special behavior 3355 magicValues = { "STDIN": 1, "STDOUT": 1, "STDERR": 1} 3356 3357 PipeOut = None 3358 for key in redirDict.keys(): 3359 if kw.has_key(key): 3360 outputFlag, standardName, openArgs = redirDict[key] 3361 # if it is a string, open as a file 3362 # otherwise assume it is a filehandle 3363 value = kw[key] 3364 if isinstance(value, str): 3365 if magicValues.has_key(value): 3366 if outputFlag and value == "STDOUT": 3367 fh = _sys.__stdout__ 3368 elif outputFlag and value == "STDERR": 3369 fh = _sys.__stderr__ 3370 elif (not outputFlag) and value == "STDIN": 3371 fh = _sys.__stdin__ 3372 else: 3373 # IRAF doesn't raise an exception here (e.g., on 3374 # input redirection from "STDOUT"), but it should 3375 raise IOError("Illegal value `%s' for %s redirection" % 3376 (value, key)) 3377 else: 3378 # expand IRAF variables 3379 value = Expand(value) 3380 if outputFlag: 3381 # output file 3382 # check to see if it is dev$null 3383 if isNullFile(value): 3384 if _sys.platform.startswith('win'): 3385 value = 'NUL' 3386 else: 3387 value = '/dev/null' 3388 elif "w" in openArgs and \ 3389 envget("clobber","") != yes and \ 3390 _os.path.exists(value): 3391 # don't overwrite unless clobber is set 3392 raise IOError("Output file `%s' already exists" % 3393 value) 3394 fh = open(value,openArgs) 3395 # close this when we're done 3396 closeFHList.append(fh) 3397 elif isinstance(value, int): 3398 # integer is OK for output keywords -- it indicates 3399 # that output should be captured and returned as 3400 # function value 3401 if not outputFlag: 3402 raise IrafError("%s redirection must " 3403 "be from a file handle or string\n" 3404 "Value is `%s'" % 3405 (key, value)) 3406 if not value: 3407 fh = None 3408 else: 3409 if PipeOut is None: 3410 # several outputs can be written to same buffer 3411 # (e.g. Stdout=1, Stderr=1 is legal) 3412 PipeOut = _StringIO.StringIO() 3413 # stick this in the close list too so we know that 3414 # output should be returned 3415 # wrap it in a tuple to make it easy to recognize 3416 closeFHList.append((PipeOut,)) 3417 fh = PipeOut 3418 elif isinstance(value, (list,tuple)): 3419 # list/tuple of strings is OK for input 3420 if outputFlag: 3421 raise IrafError("%s redirection must " 3422 "be to a file handle or string\n" 3423 "Value is type %s" % 3424 (key, type(value))) 3425 try: 3426 if value and value[0][-1:] == '\n': 3427 s = ''.join(value) 3428 elif value: 3429 s = '\n'.join(value) + '\n' 3430 else: 3431 # empty value means null input 3432 s = '' 3433 fh = _StringIO.StringIO(s) 3434 # close this when we're done 3435 closeFHList.append(fh) 3436 except TypeError: 3437 raise IrafError("%s redirection must " 3438 "be from a sequence of strings\n" % key) 3439 else: 3440 # must be a file handle 3441 if outputFlag: 3442 if not hasattr(value, 'write'): 3443 raise IrafError("%s redirection must " 3444 "be to a file handle or string\n" 3445 "Value is `%s'" % 3446 (key, value)) 3447 elif not hasattr(value, 'read'): 3448 raise IrafError("%s redirection must " 3449 "be from a file handle or string\n" 3450 "Value is `%s'" % 3451 (key, value)) 3452 fh = value 3453 if fh is not None: redirKW[standardName] = fh 3454 del kw[key] 3455 # Now handle IRAF semantics for redirection of stderr to mean stdout 3456 # also redirects to stderr file handle if Stdout not also specified 3457 if redirKW.has_key('stderr') and not redirKW.has_key('stdout'): 3458 redirKW['stdout'] = redirKW['stderr'] 3459 return redirKW, closeFHList
3460
3461 -def redirApply(redirKW):
3462 3463 """Modify _sys.stdin, stdout, stderr using the redirKW dictionary 3464 3465 Returns a list of the original filehandles so they can be 3466 restored (by redirReset) 3467 """ 3468 3469 sysDict = { 'stdin': 1, 'stdout': 1, 'stderr': 1 } 3470 resetList = [] 3471 for key, value in redirKW.items(): 3472 if sysDict.has_key(key): 3473 resetList.append((key, getattr(_sys,key))) 3474 setattr(_sys,key,value) 3475 elif key == 'stdgraph': 3476 resetList.append((key, gki.kernel)) 3477 gki.kernel = gki.GkiRedirection(value) 3478 return resetList
3479
3480 3481 -def redirReset(resetList, closeFHList):
3482 3483 """Restore _sys.stdin, stdout, stderr to their original values 3484 3485 Also closes the filehandles in closeFHList. If a tuple with a 3486 StringIO pipe is included in closeFHList, that means the value 3487 should be returned as the return value of the function. 3488 Returns an array of lines (without newlines.) 3489 """ 3490 PipeOut = None 3491 for fh in closeFHList: 3492 if isinstance(fh, tuple): 3493 PipeOut = fh[0] 3494 else: 3495 fh.close() 3496 for key, value in resetList: 3497 if key == 'stdgraph': 3498 gki.kernel = value 3499 else: 3500 setattr(_sys,key,value) 3501 if PipeOut is not None: 3502 # unfortunately cStringIO.StringIO has no readlines method: 3503 # PipeOut.seek(0) 3504 # rv = PipeOut.readlines() 3505 rv = PipeOut.getvalue().