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
20
21 from stsci.tools.irafglobals import *
22 from subproc import SubprocessError
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
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
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'):
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
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
121 BITS_PER_LONG = _struct.calcsize('l') * 8
122
123
124
125 FP_EPSILON = _numpy.finfo(None).eps
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141 _varDict = {}
142 _tasks = {}
143 _mmtasks = _minmatch.MinMatchDict()
144 _pkgs = _minmatch.MinMatchDict()
145 _loaded = {}
146
147
148
149
150
151
152
153
154 loadedPath = []
155
156
157
158
159 cl = None
160
161
162
163
164
165
166 from irafhelp import help
167
168
169
170
171
172
173
174
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
188
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
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
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
235 if _irafinst.EXISTS:
236 clProcedure(Stdin='hlib$zzsetenv.def')
237
238
239 global clpkg
240 clpkg = IrafTaskFactory('', 'clpackage', '.pkg', 'hlib$clpackage.cl',
241 'clpackage', 'bin$')
242
243
244
245
246 cl = IrafTaskFactory('','cl','','cl$cl.par','clpackage','bin$',
247 function=_clProcedure)
248 cl.setHidden()
249
250
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
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
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
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
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
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
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
320
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
366
367
368
369
370
371
372
373
374
375
376
377
378
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
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
399 fh = open(savefile,'wb')
400 doclose = 1
401
402
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
410
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
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
436
437 global Verbose
438 Verbose.set(dict['Verbose'])
439 del dict['Verbose']
440
441
442 global loadedPath
443 loadedPath[:] = dict['loadedPath']
444 del dict['loadedPath']
445
446
447 globals().update(dict)
448
449
450
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
460 global cl
461 _addTask(cl)
462
463 if doprint: listCurrent()
464
465
466
467
468
469
470 -def _addPkg(pkg):
479
480
481
482
483
484
485 -def _addTask(task, pkgname=None):
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
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
527
528 def wrapper(*args, **kw):
529
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
537 target(*args)
538 finally:
539 rv = redirReset(resetList, closeFHList)
540 return rv
541
542 return wrapper
543
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
552
553 def wrapper(*args, **kw):
554
555 redirKW, closeFHList = redirProcess(kw)
556 if kw.has_key('_save'): del kw['_save']
557
558
559 resetList = redirApply(redirKW)
560 try:
561
562 target(*args, **kw)
563 finally:
564 rv = redirReset(resetList, closeFHList)
565 return rv
566
567 return wrapper
568
569
570
571
572
573
574
575
576
577 -def addLoaded(pkg):
581
582
583
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
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
611 apply(t.run, tuple(args), kw)
612
619 """Returns list of names of all IRAF tasks that may match taskname"""
620 return _mmtasks.getallkeys(taskname, [])
621
628 """Returns list of names of all IRAF pkgs that may match pkgname"""
629 return _pkgs.getallkeys(pkgname, [])
630
631
632
633
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
652 taskname = _irafutils.untranslateName(taskname)
653
654
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
662
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
673 task = _tasks[fullname[0]]
674 if Verbose>1: print 'found',task.getName(),'in task list'
675 return task
676
677
678
679
680
681
682
683
684
685
686
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
695 if len(trylist) == 1: return _tasks[trylist[0]]
696
697 if not trylist:
698
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
717
718
719 for i in xrange(len(loadedPath)):
720 pkg = loadedPath[-1-i].getName()
721 if pkg in pkglist:
722
723 j = pkglist.index(pkg)
724 return _tasks[trylist[j]]
725
726
727 if found:
728 return None
729 else:
730 raise KeyError("Task "+taskname+" is not in a loaded package")
731
732
733
734
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
752 pkgname = _irafutils.untranslateName(pkgname)
753 return _pkgs[pkgname]
754 except _minmatch.AmbiguousKeyError, e:
755
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
771 """Returns list of names of all defined IRAF tasks"""
772 return _tasks.keys()
773
775 """Returns list of all defined IrafTask objects"""
776 return _tasks.values()
777
779 """Returns list of names of all defined IRAF packages"""
780 return _pkgs.keys()
781
783 """Returns list of names of all loaded IRAF packages"""
784 return _loaded.keys()
785
787 """Returns dictionary all IRAF variables"""
788 return _varDict
789
791 """Returns list of names of all IRAF variables"""
792 return _varDict.keys()
793
794
795
796
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
820 for i in xrange(len(keylist)): keylist[i] = keylist[i] + '/'
821 _irafutils.printCols(keylist)
822
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
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
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
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
927 except _minmatch.AmbiguousKeyError, e:
928 print str(e)
929 except (KeyError, TypeError):
930 if deftask(arg):
931 print 'language'
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()
942
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
978
979
980
981
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
992 if paramname[:2] == "_.":
993 paramname = pkg.getName() + paramname[1:]
994 return pkg.getParam(paramname,native=native,mode=mode,prompt=prompt)
995
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
1008
1009
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
1032
1033 _NullFileList = ["dev$null", "/dev/null"]
1034 _NullPath = None
1048
1050 """Return sub-string using IRAF 1-based indexing"""
1051 if s == INDEF: return INDEF
1052
1053 if first == 0: return ''
1054 return s[first-1:last]
1055
1057 """Return length of string"""
1058 if s == INDEF: return INDEF
1059 return len(s)
1060
1062 """Returns true if argument is INDEF"""
1063 if s == INDEF:
1064 return 1
1065 else:
1066 return 0
1067
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
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
1094 """Return string converted to lower case"""
1095 if s == INDEF: return INDEF
1096 return s.lower()
1097
1099 """Return string converted to upper case"""
1100 if s == INDEF: return INDEF
1101 return s.upper()
1102
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
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
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
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
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
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
1187 """Return a modulo b"""
1188 if INDEF in (a,b): return INDEF
1189 return (a % b)
1190
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
1212 return "%0*d" % (length, ivalue)
1213
1214 hexIvalue = hex(ivalue)
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
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
1234 """Convert arg in degrees to radians"""
1235 if value==INDEF:
1236 return INDEF
1237 else:
1238 return _math.radians(value)
1239
1241 """Convert arg in radians to degrees"""
1242 if value==INDEF:
1243 return INDEF
1244 else:
1245 return _math.degrees(value)
1246
1248 """Trigonometric sine function. Input in radians."""
1249 if value==INDEF:
1250 return INDEF
1251 else:
1252 return _math.sin(value)
1253
1255 """Trigonometric arc sine function. Result in radians."""
1256 if value==INDEF:
1257 return INDEF
1258 else:
1259 return _math.asin(value)
1260
1262 """Trigonometric cosine function. Input in radians."""
1263 if value==INDEF:
1264 return INDEF
1265 else:
1266 return _math.cos(value)
1267
1269 """Trigonometric arc cosine function. Result in radians."""
1270 if value==INDEF:
1271 return INDEF
1272 else:
1273 return _math.acos(value)
1274
1276 """Trigonometric tangent function. Input in radians."""
1277 if value==INDEF:
1278 return INDEF
1279 else:
1280 return _math.tan(value)
1281
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
1290 """Trigonometric sine function. Input in degrees."""
1291 if value==INDEF:
1292 return INDEF
1293 else:
1294 return _math.sin(_math.radians(value))
1295
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
1304 """Trigonometric cosine function. Input in degrees."""
1305 if value==INDEF:
1306 return INDEF
1307 else:
1308 return _math.cos(_math.radians(value))
1309
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
1318 """Trigonometric tangent function. Input in degrees."""
1319 if value==INDEF:
1320 return INDEF
1321 else:
1322 return _math.tan(_math.radians(value))
1323
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
1332 """Exponential function"""
1333 if value==INDEF:
1334 return INDEF
1335 else:
1336 return _math.exp(value)
1337
1339 """Natural log function"""
1340 if value==INDEF:
1341 return INDEF
1342 else:
1343 return _math.log(value)
1344
1346 """Base 10 log function"""
1347 if value==INDEF:
1348 return INDEF
1349 else:
1350 return _math.log10(value)
1351
1353 """Square root function"""
1354 if value==INDEF:
1355 return INDEF
1356 else:
1357 return _math.sqrt(value)
1358
1360 """Absolute value function"""
1361 if value==INDEF:
1362 return INDEF
1363 else:
1364 return abs(value)
1365
1367 """Minimum of list of arguments"""
1368 if INDEF in args:
1369 return INDEF
1370 else:
1371 return min(*args)
1372
1374 """Maximum of list of arguments"""
1375 if INDEF in args:
1376 return INDEF
1377 else:
1378 return max(*args)
1379
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
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
1396 """Bitwise boolean NOT of an integer"""
1397 if value==INDEF: return INDEF
1398 return ~(int(value))
1399
1401 """Bitwise boolean AND of two integers"""
1402 if INDEF in (x,y): return INDEF
1403 return x&y
1404
1406 """Bitwise boolean OR of two integers"""
1407 if INDEF in (x,y): return INDEF
1408 return x|y
1409
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
1419
1420
1421
1422
1423
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
1432
1433
1434 epath = _os.sep.join(dlist)
1435 fname = _os.path.abspath(epath)
1436
1437 if fname[-1] != _os.sep and dlist[-1] in ['', _os.curdir,_os.pardir]:
1438 fname = fname + _os.sep
1439 return fname
1440
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
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
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
1486
1487 return 0
1488
1490 """Returns true if file exists"""
1491 if filename == INDEF: return INDEF
1492 filename = _denode(filename)
1493
1494 magicValues = { "STDIN": 1, "STDOUT": 1, "STDERR": 1}
1495 return magicValues.has_key(filename) or _os.path.exists(Expand(filename))
1496
1498 """Floating point compare to within machine precision. This logic is
1499 taken directly from IRAF's fp_equald function."""
1500
1501 if INDEF in (x,y): return INDEF
1502 if x==y: return True
1503
1504
1505
1506 if x==0.0 or y==0.0: return False
1507
1508
1509 normx, ex = _fp_norm(x)
1510 normy, ey = _fp_norm(y)
1511
1512
1513 if ex != ey: return False
1514
1515
1516 x1 = 1.0 + abs(normx-normy)
1517 x2 = 1.0 + (32.0 * FP_EPSILON)
1518 return x1 <= x2
1519
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
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:
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'[^/]*!')
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
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
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
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
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
1600 """Returns true if image matching name exists and is readable"""
1601
1602 if filename == INDEF: return INDEF
1603
1604
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
1612 if filename.find('[]') != -1:
1613 return 0
1614
1615
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
1623
1624
1625
1626
1627
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
1635
1636 if (outstr.find('no images found') >= 0):
1637 return 0
1638 else:
1639 return 1
1640
1645
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
1655 return 0
1656
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
1665 return 0
1666
1673
1680
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
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
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
1725
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
1748
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
1759
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
1771 for i in range(n):
1772
1773
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
1779 if i==0:
1780 iend = 0
1781 else:
1782
1783 pat = [r'\s*']*(2*i)
1784 for j in range(i): pat[2*j+1] = f[j]
1785
1786
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
1823
1824 global _nscan
1825 try:
1826 line = eval(line, {'iraf': iraf}, locals)
1827
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
1838
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
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
1856
1857
1858
1859
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
1865 cmd = namelist[0] + ' = ""'
1866 exec cmd in locals
1867
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
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
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
1901
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
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
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
1926
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
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
1942 rv = redirReset(resetList, closeFHList)
1943
1945 """Return number of items read in last scan function"""
1946 global _nscan
1947 return _nscan
1948
1949
1950
1951
1952
1953
1954
1955
1956 @handleRedirAndSaveKwdsPlus
1957 -def set(*args, **kw):
1958 """Set IRAF environment variables"""
1959 if len(args) == 0:
1960 if len(kw) != 0:
1961
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
1970 if svalue.find('#') > 0 and svalue.find("'") < 0 and \
1971 svalue.find('"') < 0:
1972
1973
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
1980
1981 listVars(" ", "=")
1982 else:
1983
1984
1985
1986
1987
1988
1989
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
1995
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
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
2030
2031 @handleRedirAndSaveKwds
2032 -def sleep(seconds=0):
2033 """Sleep for specified time"""
2034 _time.sleep(float(seconds))
2035
2037 """Beep to terminal (even if output is redirected)"""
2038
2039 _sys.__stdout__.write("")
2040 _sys.__stdout__.flush()
2041
2043 """Execute a system-dependent command in the shell, returning status"""
2044
2045
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
2053 if s[:1] == '!':
2054 shell = "/bin/sh"
2055 s = s[1:]
2056 else:
2057
2058 shell=None
2059
2060
2061 if not s: return 0
2062
2063
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
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
2111
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
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
2122
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
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:
2137 taskname.eParam()
2138 except AttributeError:
2139 try:
2140 getTask(taskname).eParam()
2141 except (KeyError, TypeError):
2142 try:
2143 _wrapTeal(taskname)
2144 except _teal.cfgpars.NoCfgFileError:
2145 _writeError('Warning: Could not find task "'+taskname+'"')
2146
2148 """ Wrap the call to TEAL. Try to use focus switching here. """
2149
2150 oldFoc = _wutil.getFocalWindowID()
2151 _wutil.forceFocusToNewWindow()
2152
2153 try:
2154
2155 _teal.teal(taskname, returnDict=False, errorsToTerm=True,
2156 raiseUnfound=True)
2157
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
2169 getTask(taskname).tParam()
2170
2171
2172
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
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:
2228 getTask(taskname).unlearn()
2229 except KeyError, e:
2230 try:
2231 flist = _teal.cfgpars.getUsrCfgFilesForPyPkg(taskname)
2232 if flist == None or len(flist) == 0:
2233 pass
2234 elif len(flist) == 1:
2235 _os.remove(flist[0])
2236 else:
2237 if force:
2238 for f in flist:
2239 _os.remove(f)
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):
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
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
2329 for keyword in ['_save', 'verbose', 'tasknames']:
2330 if kw.has_key(keyword):
2331 del kw[keyword]
2332
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
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
2352 efilename = Expand(filename)
2353 namespace = {'PkgName': pkgname, 'PkgBinary': pkgbinary,
2354 '__file__': efilename}
2355 execfile(efilename, namespace)
2356
2357
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
2366
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
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
2390
2391 -def clDummy(*args, **kw):
2392 """Dummy do-nothing function"""
2393
2394 pass
2395
2396 bye = keep = logout = clbye = cache = language = clDummy
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):
2408
2409 @handleRedirAndSaveKwdsPlus
2410 -def clAllocate(*args, **kw):
2412
2413 @handleRedirAndSaveKwdsPlus
2414 -def clDeallocate(*args, **kw):
2416
2417 @handleRedirAndSaveKwdsPlus
2418 -def clDevstatus(*args, **kw):
2420
2421
2422
2423 -def fprint(*args, **kw):
2424 """Error unimplemented function"""
2425
2426 raise IrafError("The fprint task has not been implemented")
2427
2428
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
2440 """Give help on all packages (equivalent to CL '??')"""
2441 listTasks()
2442
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
2450
2451 if _sys.stdin == _sys.__stdin__:
2452 return
2453
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
2460
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
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
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
2488 stdin = _StringIO.StringIO(input)
2489 filename = input
2490 elif hasattr(input,'read'):
2491
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
2501 return
2502
2503 resetList = redirApply(redirKW)
2504
2505 try:
2506
2507 newtask = _iraftask.IrafCLTask('', filename, '', stdin, '', '')
2508 newtask.run()
2509 finally:
2510
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
2525
2526
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
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
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
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
2574
2575 if iscmdstring:
2576
2577 (fd, tmpCl) = _tempfile.mkstemp(suffix=".cl", prefix=str(s)+'_',
2578 dir=userIrafHome, text=True)
2579 _os.close(fd)
2580
2581
2582
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
2589 f = open(tmpCl, 'w')
2590 f.write(value+'\n')
2591
2592 f.write('#\n# this last section automatically added\n')
2593 f.write('delete '+tmpCl+' verify-\n')
2594 f.close()
2595
2596 value = tmpCl
2597
2598
2599 s = _irafutils.untranslateName(s)
2600 args = args + (s,)
2601
2602
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
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
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
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
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
2658
2659
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
2667
2668
2669 module.mutateCLTask2Pkg(pkg)
2670
2671
2672
2673
2674
2675
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
2684
2685
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
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
2700 if isinstance(arg,(str,unicode)): _sys.stdout.softspace=0
2701 print
2702
2706 """Format codes that are quietly converted to %s"""
2707 return "%%%ss" % w
2708
2710 """Boolean gets converted to upper case before printing"""
2711 args[i] = str(args[i]).upper()
2712 return "%%%ss" % w
2713
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
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
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
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
2767 _reFormat = _re.compile(r"%(?P<w>-?\d*)(?P<d>(?:\.\d*)?)(?P<c>[a-zHM])")
2768
2769
2770 _fDispatch = {}
2771 for b in _string.ascii_lowercase: _fDispatch[b] = None
2772
2773
2774 badList = ["b"]
2775 for b in badList: _fDispatch[b] = _boolConv
2776
2777
2778 badList = ["t", "z"]
2779 for b in badList: _fDispatch[b] = _badConv
2780
2781
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
2795 args = list(args)
2796 newformat = []
2797
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
2806 newformat.append(format[oend:istart])
2807 c = mm.group('c')
2808
2809 if args[i] == INDEF and c != 'w':
2810
2811 f = _quietConv
2812 else:
2813
2814 f = _fDispatch[c]
2815 if f is None:
2816
2817 newformat.append(mm.group())
2818 else:
2819 w = mm.group('w')
2820 d = mm.group('d')
2821
2822 if c == 'r':
2823 c = format[iend-1:iend+1]
2824 iend = iend+1
2825
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
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
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):
2884
2885 cd = chdir
2886
2887 @handleRedirAndSaveKwds
2888 -def back():
2902
2903 -def error(errno=0,errmsg='',task="error",_save=False, suppress=True):
2908
2912
2913 errcode = errno
2918
2922
2923
2924
2925
2926
2927
2928 _exitCommands = {
2929 "logout": 1,
2930 "exit": 1,
2931 "quit": 1,
2932 ".exit": 1,
2933 }
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
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
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
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
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
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
3007
3008
3009
3010
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
3027
3028
3029
3030
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
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
3048 taskname = "CL%s" % (_clExecuteCount,)
3049 scriptname = "<CL script %s>" % (taskname,)
3050 code = pycode.code.lstrip()
3051
3052 codeObject = compile(code,scriptname,'exec',0,0)
3053
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
3064 rv = redirReset(resetList, closeFHList)
3065
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
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092 __re_var_match = _re.compile(r'(?P<varname>[^$]*)\$')
3093
3094
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
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
3115 """Expand a string with embedded IRAF variables (IRAF virtual filename)"""
3116
3117
3118
3119 mm = __re_var_paren.search(instring)
3120 while mm is not None:
3121
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
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
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
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
3194
3195 fullname = pkgname + '.' + taskname
3196
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
3215
3216 if not task.isConsistent(newtask):
3217
3218 if not redefine:
3219 _writeError("Warning: `%s' is a task redefinition" %
3220 fullname)
3221 else:
3222
3223 if task.getPkgbinary() != newtask.getPkgbinary():
3224
3225 if Verbose>1: print 'Adding',pkgbinary,'to',task,'path'
3226 task.addPkgbinary(pkgbinary)
3227 return task
3228
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
3257
3258 if task.getFilename() != newtask.getFilename():
3259 if redefine:
3260 _writeError("Warning: `%s' is a task redefinition" %
3261 fullname)
3262 else:
3263
3264 return task
3265
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
3293
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
3313 if Verbose>1: print 'Adding',pkgbinary,'to',pkg,'path'
3314 pkg.addPkgbinary(pkgbinary)
3315 if pkgname != pkg.getPkgname():
3316
3317 _addTask(pkg,pkgname=pkgname)
3318 return pkg
3319 _addPkg(newpkg)
3320 return newpkg
3321
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
3343
3344
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
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
3362
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
3374
3375 raise IOError("Illegal value `%s' for %s redirection" %
3376 (value, key))
3377 else:
3378
3379 value = Expand(value)
3380 if outputFlag:
3381
3382
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
3392 raise IOError("Output file `%s' already exists" %
3393 value)
3394 fh = open(value,openArgs)
3395
3396 closeFHList.append(fh)
3397 elif isinstance(value, int):
3398
3399
3400
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
3411
3412 PipeOut = _StringIO.StringIO()
3413
3414
3415
3416 closeFHList.append((PipeOut,))
3417 fh = PipeOut
3418 elif isinstance(value, (list,tuple)):
3419
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
3432 s = ''
3433 fh = _StringIO.StringIO(s)
3434
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
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
3456
3457 if redirKW.has_key('stderr') and not redirKW.has_key('stdout'):
3458 redirKW['stdout'] = redirKW['stderr']
3459 return redirKW, closeFHList
3460
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
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
3503
3504
3505 rv = PipeOut.getvalue().