Документ взят из кэша поисковой машины. Адрес оригинального документа : http://www.apo.nmsu.edu/Telescopes/TCC/html/parse_defs_8py_source.html
Дата изменения: Tue Sep 15 02:25:37 2015
Дата индексирования: Sun Apr 10 01:50:09 2016
Кодировка:
lsst.tcc: python/tcc/parse/parseDefs.py Source File
lsst.tcc  1.2.2-3-g89ecb63
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
parseDefs.py
Go to the documentation of this file.
1 from __future__ import division, absolute_import
2 """A collection of structures for building python representations of parsed TCC commands.
3 
4 
5 note:
6 Currently negation mixing for parameters can happen eg: 'Axis Init Azimuth, NoAltitude' is allowed.
7 This will have to be handled outside the parser. The parser sees Azimuth and NoAzimuth as
8 distinct keywords (not a negation of a single one). This choice simplifies the code because
9 I believe the only command with negatable parameters is Axis...but I could be wrong
10 """
11 
12 __all__ = ["Qualifier", "Keyword", "Command", "SubCommand", "CommandWrapper"]
13 
14 class CmdDefError(Exception):
15  pass
16 
17 
18 class Qualifier(object):
19  """!Used to define a qualifier (which may have values associated).
20  """
21  def __init__(self,
22  name,
23  valType = None,
24  numValueRange = [0,0],
25  defValueList = None,
26  help = '',
27  negatable = False,
28  defBoolValue = False,
29  ):
30  """
31  @param[in] name string name of qualifier
32  @param[in] valType One of
33  1) None - in which case this is strictly a flag-type qualifier with no values
34  2) a callable function - which will cast any values to the
35  correct type for this qualifier
36  3) a list of strings - in which case this qualifier expects only values
37  belonging to this specific list.
38  @param[in] numValueRange [min, max] amount of values that may be associated
39  @param[in] defValueList if no values are explicitly indicated at parse time,
40  use these instead (must match valType!)
41  @param[in] help a help string
42  @param[in] negatable boolean. Whether or not a preceeding No is allowed when
43  specifying this qualifer. eg /Collimate vs. /NoCollimate
44  @param[in] defBoolValue boolean. If this qualifier is omitted by the user,
45  the resulting ParsedQualifier object will contain this boolean value (and
46  will additionally have the boolValueDefaulted flag set to True...).
47  """
48  self.name = name
49  self.negatable = bool(negatable)
50  self.defBoolValue = bool(defBoolValue)
51  self._help = help
52  defValueList = defValueList or []
53  try:
54  assert len(numValueRange) == 2
55  if numValueRange[1] != None:
56  numValueRange = [int(val) for val in numValueRange]
57  assert numValueRange[0] <= numValueRange[1]
58  else:
59  int(numValueRange[0])
60  if valType == None:
61  # strictly a flag-type qualifier, no values...
62  assert numValueRange == [0,0]
63  assert defValueList == []
64  elif callable(valType):
65  # qualifier has values of type valType, verify that defaults are
66  # property castable, and cast them
67  defValueList = [valType(val) for val in defValueList]
68  else:
69  # qualifier must have values specific to list of valType
70  for keyword in valType:
71  keyword.lower() # must be a string
72  for val in defValueList:
73  # default values must be members of valType (a list in this case)
74  assert val in valType
75  except Exception as e:
76  raise CmdDefError('Poorly formed Qualifer construction: %s' % (e,))
77  self.defValueList = defValueList
78  self.numValueRange = numValueRange
79  self.valType = valType
80 
81  @property
82  def argList(self):
83  if self.valType != None:
84  # determine if values are basic (cast) types,
85  # or a keyword type (eg from a list of allowed keywords)
86  if callable(self.valType):
87  strType = str(self.valType).split("'")[1]
88  else:
89  strType = 'keyword'
90  minArgs = ', '.join([strType]*self.numValueRange[0])# for x in range(self.numValueRange[0])])
91  if self.numValueRange[1] != None:
92  maxArgs = ', '.join([strType]*(self.numValueRange[1]-self.numValueRange[0])) #for x in range(self.numValueRange[1]-self.numValueRange[0])])
93  else:
94  maxArgs = '%s, *'%strType
95  if minArgs and maxArgs:
96  # more than zero of them
97  argList = ' = (%s [,%s])' % (minArgs, maxArgs)
98  elif maxArgs:
99  # only optional args
100  if self.numValueRange[1] == 1:
101  argList = ' [= %s]' % maxArgs
102  else:
103  argList = ' [= (%s)]' % maxArgs
104  else:
105  # only mandatory args
106  if self.numValueRange[0] == 1:
107  argList = ' = %s' % minArgs
108  else:
109  argList = ' = (%s)' % minArgs
110 
111  return argList
112  else:
113  # no args
114  return ''
115 
116  @property
117  def help(self):
118  """!Print a help string
119  """
120  helpList = []
121  helpList.append('/%s%s' % (self.name, self.argList))
122  if self.defValueList:
123  helpList.append(' default: %s' % str(self.defValueList))
124  nlSplit = [' ' + x.strip() for x in self._help.split('\n')]
125  helpList += nlSplit
126  if hasattr(self.valType, 'pop'):
127  helpList.append(' Valid Keywords:')
128  for kw in self.valType:
129  helpList.append(' %s' % kw)
130  return helpList
131 
132 class ParamElement(object):
133  """!A param is ultimately defined using a list of one or more of these
134  """
135  def __init__(self,
136  name = None,
137  castVals = None,
138  numValueRange = None,
139  defValueList = None,
140  passMeByDefault=False,
141  help = ''
142  ):
143  """
144  @param[in] name a string, will be used for unique abbreviation matching if not None
145  @param[in] castVals a callable, will cast any passed values to the correct type
146  @param[in] numValueRange [int, int] or [int, None]. Describes the max/min amount of acceptable values in valueList. If None, any amount of values are allowed
147  @param[in] defValueList a (possible empty) list of basic values to be passed by default if none were specified during parsing
148  @param[in] passMeByDefault a boolean. If True this param will be passed if a default is wanted
149  """
150  self.name = name
151  if numValueRange != None:
152  try:
153  assert len(numValueRange) == 2
154  if numValueRange[1] != None:
155  numValueRange = [int(val) for val in numValueRange]
156  assert numValueRange[0] <= numValueRange[1]
157  else:
158  int(numValueRange[0])
159  except:
160  raise CmdDefError('numValueRange must be a 2 item list of integers ordered [low, high or None]')
161  try:
162  if numValueRange != [0,0]:
163  # expect values, check for cast
164  assert callable(castVals)
165  except:
166  raise CmdDefError('a cast function must be defined for values.')
167  self.castVals = castVals
168  self.numValueRange = numValueRange
169  self.passMeByDefault = bool(passMeByDefault)
170  if defValueList != None:
171  # test that values are cast correctly
172  try:
173  self.defValueList = [self.castVals(val) for val in defValueList]
174  except:
175  raise CmdDefError('Default value list cannot be casted correctly')
176  try:
177  if self.numValueRange[1] == None:
178  assert self.numValueRange[0] <= len(self.defValueList)
179  else:
180  assert self.numValueRange[0] <= len(self.defValueList) <= self.numValueRange[1]
181  except:
182  raise CmdDefError('Default value list outside allowed range of number of values')
183  else:
184  #self.defValueList = [] # to allow [] to be a specified default value as in CoordSet
185  self.defValueList = None
186  self.help = help
187 
188  def __str__(self):
189  return 'name: ' + self.name + ' numValueRange: ' + str(self.numValueRange)
190 
192  """!For defining a single Keyword
193  """
194  def __init__(self,
195  name,
196  castVals = None,
197  numValueRange = None,
198  defValueList = None,
199  passMeByDefault = False,
200  help = '',
201  ):
202  """
203  @param[in] name a string, will be used for unique abbreviation matching if not None
204  @param[in] castVals a callable, will cast any passed values to the correct type
205  @param[in] numValueRange [int, int] or [int, None]. Describes the max/min amount of acceptable values in valueList. If None, any amount of values are allowed
206  @param[in] defValueList a (possible empty) list of basic values to be passed by default if none were specified during parsing
207  @param[in] passMeByDefault a boolean. If True this param will be passed if a default is wanted
208  @param[in] help a help string
209  """
210  ParamElement.__init__(self,
211  name = name,
212  castVals = castVals,
213  numValueRange = numValueRange,
214  defValueList = defValueList,
215  passMeByDefault = passMeByDefault,
216  help = help,
217  )
218 
219 class ParamBase(object):
220  """!One piece of a command that has been split on whitespace (and not commas nor equals sign..)
221  """
222  def __init__(self,
223  name,
224  paramElementList,
225  numParamRange = [1, 1] ,
226  help = '',
227  ):
228  """
229  @param[in] name a name for this param, used to index the parsed param dictionary
230  to be constructed at the time this is parsed.
231  @param[in] paramElementList a list of ParamElement objects
232  @param[in] numParamRange [int, int] or [int, None]. Describes the max/min amount
233  of acceptable params in paramList. If None,
234  any amount of params are allowed
235  @param[in] help a help string describing this parameter
236  """
237  self.name = name
238  try:
239  assert len(numParamRange) == 2
240  if numParamRange[1] != None:
241  numParamRange = [int(val) for val in numParamRange]
242  assert numParamRange[0] <= numParamRange[1]
243  else:
244  int(numParamRange[0])
245  except:
246  raise CmdDefError('numParamRange must be a 2 item list of integers ordered [low, high or None]')
247  self.numParamRange = numParamRange
248  # name (used for matching) must be specified on all or none of params in paramList
249  uniqueNames = [par.name for par in paramElementList]
250  if None in uniqueNames:
251  # make sure they are all None
252  try:
253  for name in uniqueNames:
254  assert name == None
255  except:
256  raise CmdDefError('For a given parameter, all values must either be named or not named; a mix is unacceptable.')
257  self.matchList = None
258  else:
259  self.matchList = uniqueNames
260  self.paramElementList = paramElementList
261  self._help = help
262 
263  @property
264  def defaultParamList(self):
265  """!Which params to pass by default for this slot?
266  """
267  return [p for p in self.paramElementList if p.passMeByDefault]
268 
269 
270  @property
271  def help(self):
272  raise NotImplementedError('subclasses must override')
273 
275  """!For defining a param slot expecting keywords and optionally values
276  """
277  def __init__(self, name, keywordDefList, numParamRange = [1,1], help=''):
278  """ @param[in] name a name for this param
279  @param[in] keywordDefList a list of Keyword objects, be sure to specify any
280  wanted as defaults specifically
281  @param[in] numParamRange number of keywords that may be passed jointly
282  @param[in] help a help string
283  """
284  ParamBase.__init__(self,
285  name = name,
286  paramElementList = keywordDefList,
287  numParamRange = numParamRange,
288  help = help,
289  )
290 
291  def getArgs(self, strType, valRange):
292  minArgs = ', '.join([strType]*valRange[0])# for x in range(valRange[0])])
293  if valRange[1] != None:
294  maxArgs = ', '.join([strType]*(valRange[1]-valRange[0])) # for x in range(valRange[1]-valRange[0])])
295  else:
296  maxArgs = '%s, *'%strType
297  if minArgs and maxArgs:
298  # more than zero of them
299  argList = '%s [,%s]' % (minArgs, maxArgs)
300  elif maxArgs:
301  # only optional args
302  argList = '[%s]' % maxArgs
303  else:
304  # only mandatory args
305  argList = '%s' % minArgs
306  return argList
307 
308  @property
309  def argList(self):
310  return self.getArgs(strType='keyword', valRange = self.numParamRange)
311 
312  @property
313  def help(self):
314  helpList = []
315  helpList.append('%s: %s' % (self.name, self.argList))
316  nlSplit = [x.strip() for x in self._help.split('\n')]
317  # indent remaining
318  nlSplit = [' ' + x for x in nlSplit]
319  helpList += nlSplit
320  if self.defaultParamList:
321  helpList.append(' Default: %s' % str([x.name for x in self.defaultParamList]))
322  helpList.append(' Valid Keywords:')
323  for kw in self.paramElementList:
324  kwHelp = []
325  kwName = kw.name
326  if kw.castVals != None:
327  strType = str(kw.castVals).split("'")[1]
328  kwArgs = self.getArgs(strType = strType, valRange = kw.numValueRange)
329  kwHelp.append(' %s = %s'%(kwName, kwArgs))
330  else:
331  # no args
332  kwHelp.append(' %s' % kwName)
333  if kw.defValueList:
334  kwHelp.append(' default: %s'% str(kw.defValueList))
335  if kw.help:
336  kwHelp.append(' %s'% str(kw.help))
337  helpList += kwHelp
338  return helpList
339 
340 
342  """!Represents a list of type castVals
343  """
344  def __init__(self, name, castVals, numValueRange=[1,1], defValueList = None, help = 'help'):
345  """
346  @param[in] name a name for this param
347  @param[in] castVals a callable, will cast any passed values to the correct type
348  @param[in] numValueRange [int, int] or [int, None]. Describes the max/min amount of acceptable values in valueList. If None, any amount of values are allowed
349  @param[in] defValueList a (possible empty) list of basic values to be passed by default if none were specified during parsing
350  @param[in] help a help string
351  """
352  passMeByDefault = True if defValueList is not None else False
353  paramElementList = [ParamElement(
354  name = None,
355  castVals = castVals,
356  numValueRange = numValueRange,
357  defValueList = defValueList,
358  passMeByDefault = passMeByDefault,
359  )]
360  ParamBase.__init__(self,
361  name = name,
362  paramElementList = paramElementList,
363  help = help,
364  )
365 
366  @property
367  def argList(self):
368  valType = str(self.paramElementList[0].castVals).split("'")[1]
369  valRange = self.paramElementList[0].numValueRange
370  minArgs = ', '.join([valType]*valRange[0])# for x in range(valRange[0])])
371  if valRange[1] != None:
372  maxArgs = ', '.join([valType]*(valRange[1]-valRange[0]))# for x in range(valRange[1]-valRange[0])])
373  else:
374  maxArgs = '%s, *'%valType
375  if minArgs and maxArgs:
376  # more than zero of them
377  argList = '%s [,%s]' % (minArgs, maxArgs)
378  elif maxArgs:
379  # only optional args
380  argList = '[%s]' % maxArgs
381  else:
382  # only mandatory args
383  argList = '%s' % minArgs
384  return argList
385 
386  @property
387  def help(self):
388  helpList = []
389  helpList.append('%s: %s' % (self.name, self.argList))
390  nlSplit = [x.strip() for x in self._help.split('\n')]
391  # indent remaining
392  nlSplit = [' ' + x for x in nlSplit]
393  helpList += nlSplit
394  if self.defaultParamList:
395  helpList.append(' Default: %s' % str(self.defaultParamList[0].defValueList))
396  return helpList
397 
398 class Command(object):
399  """!For defining a command
400  """
401  def __init__(self, name, paramList=None, qualifierList=None, help='', callFunc=None, minParAmt=0):
402  """!Inputs
403  @param[in] name command name
404  @param[in] paramList list of parameters (ParamBase objects) in the expected order, or None if no parameters
405  @param[in] qualifierList list of qualifiers (Qualifier objects), or None if no qualifiers
406  @param[in] help help string
407  @param[in] callFunc function to call that takes parsed command as an argument
408  @param[in] minParAmt the minimum number of arguments requried for this command
409  """
410  self.name = name
411  self.paramList = paramList or []
412  self.qualifierList = qualifierList or []
413  self.help = help
414  self.callFunc = callFunc
415  self.minParAmt = int(minParAmt)
416 
417  def getFullHelp(self):
418  """!Return full help as a list of strings
419  """
420  #paramNames = " ".join(param.name for param in self.paramList)
421  dataList = self.getBriefHelp()
422  if self.paramList:
423  dataList.append('')
424  dataList.append("Parameters:")
425  for param in self.paramList:
426  for helpLine in param.help:
427  dataList.append(" %s" % (helpLine,))
428  if self.qualifierList:
429  dataList.append('')
430  dataList.append("Qualifiers:")
431  for qual in self.qualifierList:
432  for helpLine in qual.help:
433  dataList.append(" %s" % (helpLine))
434  return dataList
435 
436  def getBriefHelp(self):
437  """!Return brief help as a list of strings
438  """
439  dataList = []
440  line1 = ''
441  if self.name != None: # subcommands will have a name == None.
442  line1 += self.name.upper() + ' '
443  line1 += ' '.join([x.name for x in self.paramList])
444  dataList.append(line1)
445  dataList.append(' ' + self.help)
446  #paramNames = " ".join(param.name for param in self.paramList)
447  return dataList
448 
449 
451  """!First paramSlot has the name of this subcommand. Used for cases where sub commands
452  of a command require unique parsing.
453  """
454  def __init__(self,
455  selfKeyword,
456  paramList = None,
457  qualifierList = None,
458  help = '',
459  callFunc = None,
460  minParAmt = 0,
461  ):
462  """!Inputs
463  @param[in] selfKeyword a Keyword object
464  @param[in] paramList list of any additional parameters (ParamBase objects) in the expected order, or None if no parameters
465  @param[in] qualifierList list of qualifiers (Qualifier objects), or None if no qualifiers
466  @param[in] help help string
467  @param[in] callFunc function to call that takes parsed command as an argument
468  @param[in] minParAmt the minimum number of arguments requried for this command
469  """
470  minParAmt += 1 # the selfKeyword is (under the hood) a required parameter
471  # not including it in the minParAmt because this is command-like...
472  paramList = paramList or []
473  # generate a self-param unit, since this sub-command is both a parameter and a command
474  paramList = [KeywordParam(name = selfKeyword.name, keywordDefList=[selfKeyword])] + paramList
475  self.subCommandName = selfKeyword.name # for help to print correctly
476  Command.__init__(self,
477  name = None, # must be None for nice help printing.
478  paramList = paramList,
479  qualifierList = qualifierList,
480  help = help,
481  callFunc = callFunc,
482  minParAmt = minParAmt,
483  )
484 
485 
486 class CommandWrapper(object):
487  """!An outer wrapper for commands with alternate parsing syntaxes, eg 'SET'
488  """
489  def __init__(self,
490  name,
491  subCmdList = None,
492  help = '',
493  ):
494  """!Inputs
495  @param[in] name command name (eg 'set')
496  @param[in] subCmdList a list of SubCommand objects providing definitions for alternate command
497  validation.
498  @param[in] help help string
499  """
500  self.name = name
501  #self.name = name # hack for now, for help printing
502  self.subCmdList = subCmdList or []
503  self.help = help
504 
505  def getFullHelp(self):
506  """!Return full help as a list of strings
507  """
508  dataList = []
509  for subCmd in self.subCmdList:
510  subList = subCmd.getFullHelp()
511  subList[0] = self.name.upper() + " " + subList[0]
512  dataList += subList
513  return dataList
514 
515  def getBriefHelp(self):
516  """!Return brief help as a list of strings
517  """
518  dataList = []
519  for subCmd in self.subCmdList:
520  subList = subCmd.getBriefHelp()
521  subList[0] = self.name.upper() + " " + subList[0]
522  dataList += subList
523  return dataList
def getFullHelp
Return full help as a list of strings.
Definition: parseDefs.py:417
Used to define a qualifier (which may have values associated).
Definition: parseDefs.py:18
def getBriefHelp
Return brief help as a list of strings.
Definition: parseDefs.py:515
For defining a command.
Definition: parseDefs.py:398
First paramSlot has the name of this subcommand.
Definition: parseDefs.py:450
A param is ultimately defined using a list of one or more of these.
Definition: parseDefs.py:132
Represents a list of type castVals.
Definition: parseDefs.py:341
An outer wrapper for commands with alternate parsing syntaxes, eg &#39;SET&#39;.
Definition: parseDefs.py:486
For defining a single Keyword.
Definition: parseDefs.py:191
def help
Print a help string.
Definition: parseDefs.py:117
For defining a param slot expecting keywords and optionally values.
Definition: parseDefs.py:274
def getFullHelp
Return full help as a list of strings.
Definition: parseDefs.py:505
One piece of a command that has been split on whitespace (and not commas nor equals sign...
Definition: parseDefs.py:219
def defaultParamList
Which params to pass by default for this slot?
Definition: parseDefs.py:264
def getBriefHelp
Return brief help as a list of strings.
Definition: parseDefs.py:436