³ò ¼e(?c@s‘dZddkZddkZdfd„ƒYZdZdZdZd„Zd „Zd „Z d „Z d fd „ƒYZ dfd„ƒYZ dS(ssysargs.py: Object to check command line arguments $Revision: 1.5 $ $Date: 2003/01/25 00:25:11 $ Exports: class SysArgs: Represents digested command line arguments. SysArgs(switchSpecs, posSpecs): [ if (switchSpecs is a list of SwitchArg objects representing switches accepted by this program, and is-switch-valid(switchSpecs)) and ( posSpecs is a list of PosArg objects representing positional arguments accepted by this program, and is-pos-list-valid(posSpecs)) -> if (sys.argv contains only switches in switchSpecs) and (sys.argv's positional arguments conform to posSpecs) -> return a new SysArgs object representing those digested arguments else -> sys.stderr +:= (usage message) + (error message) stop execution ] .switchSpecs: [ as passed to constructor, read-only ] .posSpecs: [ as passed to constructor, read-only ] .switchMap: [ a dictionary mapping L |-> s, for all switch values in sys.argv, such that s is the value of that switch (1 for non-value switches, 0 for switches not in sys.argv, and a string for value-type switches), and L is the SwitchArg.letter value ] .posMap: [ the positional arguments from sys.argv, in a 1-1 correspondence with the elements of self.posSpecs, as a dictionary mapping k |-> v, where k is the PosArg.key value, and v is None for a missing optional unrepeated argument, the value as a string for a present unrepeated argument, and a list of strings for a repeated argument ] | Example: | args = SysArgs ( | [ SwitchArg ( "v", [ "verbose output" ] ), | SwitchArg ( "f", | [ "Use this argument to specify the name of a file", | "that you wanted mangled." ], takesValue=1 ), | SwitchArg ( "o", [ "output file (optional)" ], | takesValue=1 ) ], | [ PosArg ( "infiles", | [ "Names of input files to be mangled." ], | repeated=1 ), | PosArg ( "logfile", | [ "Output log file." ] ) ] ) | print "f argument value is:", args.switchMap["f"] | print "3rd input file is:", args.posMap["infiles"][2] def usage(switchSpecs, posSpecs, *textList): [ if (switchSpecs and posSpecs are as passed to SysArgs) and (textList is a list of strings) -> sys.stderr +:= (usage message) + (concatenation of textList) stop execution ] class SwitchArg: Represents one possible switch argument SwitchArg(letter, description, takesValue=0): [ if (letter is the switch letter as a one-character string) and (takesValue is true if the switch must have a value) and (description is a textual description of the meaning of the switch as a list of strings not exceeding 60 characters per string) -> return a new SwitchArg object representing those values ] .letter: [ as passed to constructor ] .description: [ as passed to constructor ] .takesValue: [ as passed to constructor ] class PosArg: Represents one (possibly repeated) positional argument PosArg ( key, description, optional=0, repeated=0 ): [ if (key is the name of this argument in the usage message) and (description is as in SwitchArg()) and (optional is true iff the positional argument is optional) and (repeated is true iff the argument may be repeated) -> return a new PosArg representing those values ] .key: [ as passed to constructor ] .description: [ as passed to constructor ] .optional: [ as passed to constructor ] .repeated: [ as passed to constructor ] iÿÿÿÿNtSysArgscBszeZdZd„Zd„Zd„Zd„Zd„Zd„Zd„Z d„Z d „Z d „Z d „Z d „ZRS( sƒRepresents validated command line arguments. State/Invariants: .__optx: [ if self.posSpecs contains any optional arguments -> the index in self.posSpecs of the first one else -> None ] .__repx: [ if self.posSpecs contains a repeating argument -> its index in self.posSpecs else -> None ] cCsT||_||_h|_h|_|iƒ\}}|i|ƒ|i|ƒdS(sConstructor for SysArgsN(t switchSpecstposSpecst switchMaptposMapt_SysArgs__roughSortt_SysArgs__optCheckt_SysArgs__posCheck(tselfRRtoptListtposList((s,/u/www/docs/tcc/projects/pystyler/sysargs.pyt__init__•s     cCsh|iƒ}y!titid|ƒ}|SWn4tij o%}t|i|it|ƒƒnXdS(sHRough syntax checking of the arguments. [ if sys.argv passes getopt.getopt -> return (options returned by getopt.getopt(), args returned by getopt.getopt()) else -> sys.stderr +:= (usage message) + (error message) stop execution ] iN( t_SysArgs__buildOptionStringtgetopttsystargvt GetoptErrortusageRRtstr(Rt optionStringtresulttdetail((s,/u/www/docs/tcc/projects/pystyler/sysargs.pyt __roughSortÁs  cCsYg}xC|iD]8}|io|id|iƒq|i|iƒqWdi|ƒS(sSet up the string that tells getopt.getopt what switches we allow [ if self.switchSpecs is as invariant -> optionString := string for the 2nd argument of getopt.getopt, based on self.switchSpecs ] s%s:t(Rt takesValuetappendtlettertjoin(RRtsw((s,/u/www/docs/tcc/projects/pystyler/sysargs.pyt__buildOptionStringás   cCsSx!|iD]}d|i|i if optList is consistent with self.switchSpecs and its letters are unique -> self.switchMap +:= entries mapping letters from optList |-> the option values as in the invariant else -> sys.stderr +:= (usage message) + (error message) stop execution ] iiN(RRRt_SysArgs__checkSwitch(RR tswitchtvalue((s,/u/www/docs/tcc/projects/pystyler/sysargs.pyt __optChecks    cCsf|ii|ƒpt|i|id|ƒnt|ƒdjod|i| if letter is a letter in self.switchSpecs but not a key in self.switchMap -> if value is "" -> self.switchMap[letter] := 1 else -> self.switchMap[letter] := value else -> sys.stderr +:= (usage message) + (error message) stop execution ] sNo such switch: -%siiN(Rthas_keyRRRtlen(RRR ((s,/u/www/docs/tcc/projects/pystyler/sysargs.pyt __checkSwitch,s cCs|iƒ|i|ƒdS(sêCheck the positional arguments from posList against self.posSpecs [ if posList is a list of strings representing positional command line arguments -> if posList is consistent with self.posSpecs -> self.posMap +:= entries mapping k |-> v where k is the set of .key values in self.posSpecs and the values v are as in the invariant self.__optx := as invariant self.__repx := as invariant self.__minPos := as invariant self.__maxPos := as invariant else -> sys.stderr +:= (usage message) + (error message) stop execution ] N(t_SysArgs__validatePosListt_SysArgs__storePositionals(RR ((s,/u/www/docs/tcc/projects/pystyler/sysargs.pyt __posCheckOs cCsCd|_d|_x*tt|iƒƒD]}|i|ƒq(WdS(s4Insure is-pos-list-valid(self.posSpecs) [ if is-pos-list-valid(self.posSpecs) -> self.__optx := as invariant self.__repx := as invariant else -> sys.stderr +:= (usage message) + (error message) stop execution ] N(tNonet_SysArgs__optxt_SysArgs__repxtrangeR#Rt_SysArgs__validatePosSpec(Rtposx((s,/u/www/docs/tcc/projects/pystyler/sysargs.pyt__validatePosListxs  cCs5|i|}|io•|idj ot|i|idƒn|idj ot|i|iddƒn|io'|iot|i|iddƒn||_n†|ioN|idj ot|i|iddƒn|idjo ||_q1n.|idj ot|i|iddƒndS( sùCheck one positional specifier for validity. [ if posx is an index in self.posSpecs -> if (self.posSpecs[posx] is repeated but there is already a repeated element) or (self.posSpecs[posx] is repeated or non-optional but there are already optional elements) or (self.posSpecs[posx] is both repeated and optional) -> sys.stderr +:= (usage message) + (error message) stop execution else if self.posSpecs[posx] is repeated -> self.__repx := posx else if (self.posSpecs[posx] is optional) and self.__optx is None) -> self.__optx := posx ] else -> I ] s1Programming error: multiple repeated positionals.s.Programming error: you can't mix repeated and soptional arguments.s-Programming error: an argument can't be both srepeated and optional.s*Programming error: all optional arguments s must be last.N(RtrepeatedR*R(RRR)toptional(RR-tposArg((s,/u/www/docs/tcc/projects/pystyler/sysargs.pyt__validatePosSpec¥s2        cCsS|idj o|i|ƒn/|idj o|i|ƒn|i|ƒdS(s¬Allocate positional arguments to their self.posSpecs members [ if posList is a list of positional arguments as strings -> if posList is a valid sequence of positionals as specified by self.posSpec -> self.posMap := as invariant from posList else -> sys.stderr +:= (usage message) + (error message) stop execution ] N(R*R(t_SysArgs__scatterRepeatedR)t_SysArgs__scatterOptionalst_SysArgs__scatterRequireds(RR ((s,/u/www/docs/tcc/projects/pystyler/sysargs.pyt__storePositionalsÙs    cCst|iƒd}t|ƒ|}|djo7t|i|idt|ƒt|iƒdfƒnx2t|iƒD]!}|||i|i|i if posList matches self.posSpecs -> self.posMap +:= entries mapping keys from self.posSpecs |-> corresponding values from posList, with any repeated arguments packed into a list under self.posSpecs[self.__repx].key else -> sys.stderr +:= (usage message) + (error message) stop execution ] Here's how arguments from posList map onto self.posSpecs. The most general case is where there are required arguments both before and after the repeated argument R2: |<------------ len(poslist) ------------>| |<-- self.__repx -->|<-numReps->| +===================+===========+========+ posList | initial, required | repeated | final, | ACTUAL | | | req'd | POSITIONALS +===================+===========+========+ | | / / | | / / | | / / v v / / |<-- self.__repx -->|<-1->|v v +===================+=====+========+ self.posSpecs | initial, required | rep.| final, | POSITIONAL ARG. | | | req'd | SPECIFIERS +===================+=====+========+ |<------ len(self.posSpecs) ------>| iis=Only %d positional arguments were supplied, need at least %d.N(R#RRRR+R*Rtkey(RR t numNonRepstnumRepsR-tspextsourcex((s,/u/www/docs/tcc/projects/pystyler/sysargs.pyt__scatterRepeateds* %+ cCsçt|ƒ|ijo-t|i|id|it|ƒfƒnx2t|iƒD]!}|||i|i|i if posList matches self.posSpecs -> self.posMap +:= entries mapping keys from self.posSpecs |-> corresponding values from posList, or None for missing optional arguments else -> sys.stderr +:= (usage message) + (error message) stop execution ] s-At least %d positional required, %d supplied.N( R#R)RRRR+RR7R((RR tiR7((s,/u/www/docs/tcc/projects/pystyler/sysargs.pyt__scatterOptionalsXscCs‹t|ƒt|iƒjo3t|i|idt|iƒt|ƒfƒnx5tt|ƒƒD]!}|||i|i|i if posList matches self.posSpecs -> self.posMap +:= entries mapping keys from self.posSpecs |-> corresponding values from posList else -> sys.stderr +:= (usage message) + (error message) stop execution ] s.%d positional arguments required, %d supplied.N(R#RRRR+RR7(RR R=((s,/u/www/docs/tcc/projects/pystyler/sysargs.pyt__scatterRequireds…s!(t__name__t __module__t__doc__R RR RRRR%R,R&R3R4R5(((s,/u/www/docs/tcc/projects/pystyler/sysargs.pyR„s  ,  , # ) - 4 / P -s***i icGsËdi|ƒ}tiidtƒt||ƒ}tiidttid|fƒtiidtƒx|D]}t|ƒqqWx|D]}t|ƒqŒWtiidt|fƒti dƒdS( s$Write a usage message and terminate.Rs %s Usage: s %s %s %s is %s where: s %s Error: %s iN( RRtstderrtwritetMESSAGE_PREFIXtbuildCommandModelRt usageSwitchtusagePostexit(RRttextListttextt commandModelRtpos((s,/u/www/docs/tcc/projects/pystyler/sysargs.pyR¥s cCs–g}x"|D]}|id|iƒq Wx[|D]S}|io|id|iƒq2|i|iƒ|io|idƒq2q2Wdi|ƒS(sôBuild a model command line for the usage message. [ if (switchSpecs is a list of SwitchArg objects) and (posSpecs is a list of PosArg objects) -> return a string showing the switches and positionals they describe ] s-%ss[%s]s...t (RRR0R7R/R(RRRRRM((s,/u/www/docs/tcc/projects/pystyler/sysargs.pyRFÎs   cCseddttd|if}x@|iD]5}tiidt||fƒddtt}q(WdS(syDisplay a SwitchArg [ if switch is a SwitchArg object -> sys.stderr +:= lines describing switch ] s%s%-*sRNs-%ss %s %s %s s%sN(t WHERE_INDENTt DESC_MARGINRt descriptionRRCRDRE(Rtprefixtline((s,/u/www/docs/tcc/projects/pystyler/sysargs.pyRGðs  cCs¦ddtt|if}|i}dt}t|iƒtdjodt|fGHndt||dfGH|d=x'|D]}dtdt||fGHqWdS( smDisplay a PosArg [ if pos is a PosArg object -> sys.stderr +:= lines describing pos ] s%s%-*sRNis%s %ss%s %s %sis %s %s%s %sN(RORPR7RQR#RE(RMRRt linesLeftt blankMarginRS((s,/u/www/docs/tcc/projects/pystyler/sysargs.pyRHs   t SwitchArgcBseZdZdd„ZRS(s9Represents the specification for a valid switch argument.icCs||_||_||_dS(sConstructor for SwitchArgN(RRQR(RRRQR((s,/u/www/docs/tcc/projects/pystyler/sysargs.pyR .s  (R@RARBR (((s,/u/www/docs/tcc/projects/pystyler/sysargs.pyRV,stPosArgcBseZdZddd„ZRS(s=Represents the specification for a valid positional argument.icCs(||_||_||_||_dS(sConstructor for PosArgN(R7RQR0R/(RR7RQR0R/((s,/u/www/docs/tcc/projects/pystyler/sysargs.pyR :s   (R@RARBR (((s,/u/www/docs/tcc/projects/pystyler/sysargs.pyRW8s( RBRR RRERPRORRFRGRHRVRW(((s,/u/www/docs/tcc/projects/pystyler/sysargs.pysMs  &ÿÿ ) "  $