Statistics
| Branch: | Tag: | Revision:

root / lib / qlang.py @ 5e12acfe

History | View | Annotate | Download (9.8 kB)

1 a123dc19 Michael Hanselmann
#
2 a123dc19 Michael Hanselmann
#
3 a123dc19 Michael Hanselmann
4 2cfbc784 Iustin Pop
# Copyright (C) 2010, 2011, 2012 Google Inc.
5 a123dc19 Michael Hanselmann
#
6 a123dc19 Michael Hanselmann
# This program is free software; you can redistribute it and/or modify
7 a123dc19 Michael Hanselmann
# it under the terms of the GNU General Public License as published by
8 a123dc19 Michael Hanselmann
# the Free Software Foundation; either version 2 of the License, or
9 a123dc19 Michael Hanselmann
# (at your option) any later version.
10 a123dc19 Michael Hanselmann
#
11 a123dc19 Michael Hanselmann
# This program is distributed in the hope that it will be useful, but
12 a123dc19 Michael Hanselmann
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 a123dc19 Michael Hanselmann
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 a123dc19 Michael Hanselmann
# General Public License for more details.
15 a123dc19 Michael Hanselmann
#
16 a123dc19 Michael Hanselmann
# You should have received a copy of the GNU General Public License
17 a123dc19 Michael Hanselmann
# along with this program; if not, write to the Free Software
18 a123dc19 Michael Hanselmann
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 a123dc19 Michael Hanselmann
# 02110-1301, USA.
20 a123dc19 Michael Hanselmann
21 a123dc19 Michael Hanselmann
22 341ff8e9 Michael Hanselmann
"""Module for a simple query language
23 341ff8e9 Michael Hanselmann

24 341ff8e9 Michael Hanselmann
A query filter is always a list. The first item in the list is the operator
25 341ff8e9 Michael Hanselmann
(e.g. C{[OP_AND, ...]}), while the other items depend on the operator. For
26 341ff8e9 Michael Hanselmann
logic operators (e.g. L{OP_AND}, L{OP_OR}), they are subfilters whose results
27 341ff8e9 Michael Hanselmann
are combined. Unary operators take exactly one other item (e.g. a subfilter for
28 341ff8e9 Michael Hanselmann
L{OP_NOT} and a field name for L{OP_TRUE}). Binary operators take exactly two
29 341ff8e9 Michael Hanselmann
operands, usually a field name and a value to compare against. Filters are
30 341ff8e9 Michael Hanselmann
converted to callable functions by L{query._CompileFilter}.
31 341ff8e9 Michael Hanselmann

32 341ff8e9 Michael Hanselmann
"""
33 a123dc19 Michael Hanselmann
34 7578ab0a Michael Hanselmann
import re
35 b459a848 Andrea Spadaccini
import string # pylint: disable=W0402
36 f8638e28 Michael Hanselmann
import logging
37 7578ab0a Michael Hanselmann
38 7578ab0a Michael Hanselmann
import pyparsing as pyp
39 7578ab0a Michael Hanselmann
40 7578ab0a Michael Hanselmann
from ganeti import errors
41 3f2f55bb Michael Hanselmann
from ganeti import netutils
42 16629d10 Michael Hanselmann
from ganeti import utils
43 f8638e28 Michael Hanselmann
from ganeti import compat
44 7578ab0a Michael Hanselmann
45 7578ab0a Michael Hanselmann
46 341ff8e9 Michael Hanselmann
# Logic operators with one or more operands, each of which is a filter on its
47 341ff8e9 Michael Hanselmann
# own
48 a123dc19 Michael Hanselmann
OP_OR = "|"
49 88076fd1 Michael Hanselmann
OP_AND = "&"
50 88076fd1 Michael Hanselmann
51 88076fd1 Michael Hanselmann
52 341ff8e9 Michael Hanselmann
# Unary operators with exactly one operand
53 88076fd1 Michael Hanselmann
OP_NOT = "!"
54 3b877f08 Michael Hanselmann
OP_TRUE = "?"
55 88076fd1 Michael Hanselmann
56 88076fd1 Michael Hanselmann
57 341ff8e9 Michael Hanselmann
# Binary operators with exactly two operands, the field name and an
58 341ff8e9 Michael Hanselmann
# operator-specific value
59 a123dc19 Michael Hanselmann
OP_EQUAL = "="
60 88076fd1 Michael Hanselmann
OP_NOT_EQUAL = "!="
61 ad48eacc Michael Hanselmann
OP_LT = "<"
62 ad48eacc Michael Hanselmann
OP_LE = "<="
63 ad48eacc Michael Hanselmann
OP_GT = ">"
64 ad48eacc Michael Hanselmann
OP_GE = ">="
65 88076fd1 Michael Hanselmann
OP_REGEXP = "=~"
66 88076fd1 Michael Hanselmann
OP_CONTAINS = "=[]"
67 a123dc19 Michael Hanselmann
68 a123dc19 Michael Hanselmann
69 0b0ca0c0 Michael Hanselmann
#: Characters used for detecting user-written filters (see L{_CheckFilter})
70 ad48eacc Michael Hanselmann
FILTER_DETECTION_CHARS = frozenset("()=/!~'\"\\<>" + string.whitespace)
71 f8638e28 Michael Hanselmann
72 0b0ca0c0 Michael Hanselmann
#: Characters used to detect globbing filters (see L{_CheckGlobbing})
73 f8638e28 Michael Hanselmann
GLOB_DETECTION_CHARS = frozenset("*?")
74 3f2f55bb Michael Hanselmann
75 3f2f55bb Michael Hanselmann
76 60cba7f8 Michael Hanselmann
def MakeSimpleFilter(namefield, values):
77 31554d0a Michael Hanselmann
  """Builds simple a filter.
78 60cba7f8 Michael Hanselmann

79 60cba7f8 Michael Hanselmann
  @param namefield: Name of field containing item name
80 60cba7f8 Michael Hanselmann
  @param values: List of names
81 60cba7f8 Michael Hanselmann

82 60cba7f8 Michael Hanselmann
  """
83 60cba7f8 Michael Hanselmann
  if values:
84 60cba7f8 Michael Hanselmann
    return [OP_OR] + [[OP_EQUAL, namefield, i] for i in values]
85 60cba7f8 Michael Hanselmann
86 60cba7f8 Michael Hanselmann
  return None
87 7578ab0a Michael Hanselmann
88 7578ab0a Michael Hanselmann
89 7578ab0a Michael Hanselmann
def _ConvertLogicOp(op):
90 7578ab0a Michael Hanselmann
  """Creates parsing action function for logic operator.
91 7578ab0a Michael Hanselmann

92 7578ab0a Michael Hanselmann
  @type op: string
93 7578ab0a Michael Hanselmann
  @param op: Operator for data structure, e.g. L{OP_AND}
94 7578ab0a Michael Hanselmann

95 7578ab0a Michael Hanselmann
  """
96 7578ab0a Michael Hanselmann
  def fn(toks):
97 7578ab0a Michael Hanselmann
    """Converts parser tokens to query operator structure.
98 7578ab0a Michael Hanselmann

99 7578ab0a Michael Hanselmann
    @rtype: list
100 7578ab0a Michael Hanselmann
    @return: Query operator structure, e.g. C{[OP_AND, ["=", "foo", "bar"]]}
101 7578ab0a Michael Hanselmann

102 7578ab0a Michael Hanselmann
    """
103 7578ab0a Michael Hanselmann
    operands = toks[0]
104 7578ab0a Michael Hanselmann
105 7578ab0a Michael Hanselmann
    if len(operands) == 1:
106 7578ab0a Michael Hanselmann
      return operands[0]
107 7578ab0a Michael Hanselmann
108 7578ab0a Michael Hanselmann
    # Build query operator structure
109 7578ab0a Michael Hanselmann
    return [[op] + operands.asList()]
110 7578ab0a Michael Hanselmann
111 7578ab0a Michael Hanselmann
  return fn
112 7578ab0a Michael Hanselmann
113 7578ab0a Michael Hanselmann
114 7578ab0a Michael Hanselmann
_KNOWN_REGEXP_DELIM = "/#^|"
115 7578ab0a Michael Hanselmann
_KNOWN_REGEXP_FLAGS = frozenset("si")
116 7578ab0a Michael Hanselmann
117 7578ab0a Michael Hanselmann
118 7578ab0a Michael Hanselmann
def _ConvertRegexpValue(_, loc, toks):
119 7578ab0a Michael Hanselmann
  """Regular expression value for condition.
120 7578ab0a Michael Hanselmann

121 7578ab0a Michael Hanselmann
  """
122 7578ab0a Michael Hanselmann
  (regexp, flags) = toks[0]
123 7578ab0a Michael Hanselmann
124 7578ab0a Michael Hanselmann
  # Ensure only whitelisted flags are used
125 7578ab0a Michael Hanselmann
  unknown_flags = (frozenset(flags) - _KNOWN_REGEXP_FLAGS)
126 7578ab0a Michael Hanselmann
  if unknown_flags:
127 7578ab0a Michael Hanselmann
    raise pyp.ParseFatalException("Unknown regular expression flags: '%s'" %
128 7578ab0a Michael Hanselmann
                                  "".join(unknown_flags), loc)
129 7578ab0a Michael Hanselmann
130 7578ab0a Michael Hanselmann
  if flags:
131 7578ab0a Michael Hanselmann
    re_flags = "(?%s)" % "".join(sorted(flags))
132 7578ab0a Michael Hanselmann
  else:
133 7578ab0a Michael Hanselmann
    re_flags = ""
134 7578ab0a Michael Hanselmann
135 7578ab0a Michael Hanselmann
  re_cond = re_flags + regexp
136 7578ab0a Michael Hanselmann
137 7578ab0a Michael Hanselmann
  # Test if valid
138 7578ab0a Michael Hanselmann
  try:
139 7578ab0a Michael Hanselmann
    re.compile(re_cond)
140 7578ab0a Michael Hanselmann
  except re.error, err:
141 7578ab0a Michael Hanselmann
    raise pyp.ParseFatalException("Invalid regular expression (%s)" % err, loc)
142 7578ab0a Michael Hanselmann
143 7578ab0a Michael Hanselmann
  return [re_cond]
144 7578ab0a Michael Hanselmann
145 7578ab0a Michael Hanselmann
146 7578ab0a Michael Hanselmann
def BuildFilterParser():
147 7578ab0a Michael Hanselmann
  """Builds a parser for query filter strings.
148 7578ab0a Michael Hanselmann

149 7578ab0a Michael Hanselmann
  @rtype: pyparsing.ParserElement
150 7578ab0a Michael Hanselmann

151 7578ab0a Michael Hanselmann
  """
152 7578ab0a Michael Hanselmann
  field_name = pyp.Word(pyp.alphas, pyp.alphanums + "_/.")
153 7578ab0a Michael Hanselmann
154 7578ab0a Michael Hanselmann
  # Integer
155 7578ab0a Michael Hanselmann
  num_sign = pyp.Word("-+", exact=1)
156 7578ab0a Michael Hanselmann
  number = pyp.Combine(pyp.Optional(num_sign) + pyp.Word(pyp.nums))
157 7578ab0a Michael Hanselmann
  number.setParseAction(lambda toks: int(toks[0]))
158 7578ab0a Michael Hanselmann
159 16629d10 Michael Hanselmann
  quoted_string = pyp.quotedString.copy().setParseAction(pyp.removeQuotes)
160 16629d10 Michael Hanselmann
161 7578ab0a Michael Hanselmann
  # Right-hand-side value
162 16629d10 Michael Hanselmann
  rval = (number | quoted_string)
163 7578ab0a Michael Hanselmann
164 7578ab0a Michael Hanselmann
  # Boolean condition
165 7578ab0a Michael Hanselmann
  bool_cond = field_name.copy()
166 7578ab0a Michael Hanselmann
  bool_cond.setParseAction(lambda (fname, ): [[OP_TRUE, fname]])
167 7578ab0a Michael Hanselmann
168 7578ab0a Michael Hanselmann
  # Simple binary conditions
169 7578ab0a Michael Hanselmann
  binopstbl = {
170 7578ab0a Michael Hanselmann
    "==": OP_EQUAL,
171 7578ab0a Michael Hanselmann
    "!=": OP_NOT_EQUAL,
172 ad48eacc Michael Hanselmann
    "<": OP_LT,
173 ad48eacc Michael Hanselmann
    "<=": OP_LE,
174 ad48eacc Michael Hanselmann
    ">": OP_GT,
175 ad48eacc Michael Hanselmann
    ">=": OP_GE,
176 7578ab0a Michael Hanselmann
    }
177 7578ab0a Michael Hanselmann
178 7578ab0a Michael Hanselmann
  binary_cond = (field_name + pyp.oneOf(binopstbl.keys()) + rval)
179 7578ab0a Michael Hanselmann
  binary_cond.setParseAction(lambda (lhs, op, rhs): [[binopstbl[op], lhs, rhs]])
180 7578ab0a Michael Hanselmann
181 7578ab0a Michael Hanselmann
  # "in" condition
182 7578ab0a Michael Hanselmann
  in_cond = (rval + pyp.Suppress("in") + field_name)
183 7578ab0a Michael Hanselmann
  in_cond.setParseAction(lambda (value, field): [[OP_CONTAINS, field, value]])
184 7578ab0a Michael Hanselmann
185 7578ab0a Michael Hanselmann
  # "not in" condition
186 7578ab0a Michael Hanselmann
  not_in_cond = (rval + pyp.Suppress("not") + pyp.Suppress("in") + field_name)
187 7578ab0a Michael Hanselmann
  not_in_cond.setParseAction(lambda (value, field): [[OP_NOT, [OP_CONTAINS,
188 7578ab0a Michael Hanselmann
                                                               field, value]]])
189 7578ab0a Michael Hanselmann
190 7578ab0a Michael Hanselmann
  # Regular expression, e.g. m/foobar/i
191 7578ab0a Michael Hanselmann
  regexp_val = pyp.Group(pyp.Optional("m").suppress() +
192 7578ab0a Michael Hanselmann
                         pyp.MatchFirst([pyp.QuotedString(i, escChar="\\")
193 7578ab0a Michael Hanselmann
                                         for i in _KNOWN_REGEXP_DELIM]) +
194 7578ab0a Michael Hanselmann
                         pyp.Optional(pyp.Word(pyp.alphas), default=""))
195 7578ab0a Michael Hanselmann
  regexp_val.setParseAction(_ConvertRegexpValue)
196 7578ab0a Michael Hanselmann
  regexp_cond = (field_name + pyp.Suppress("=~") + regexp_val)
197 7578ab0a Michael Hanselmann
  regexp_cond.setParseAction(lambda (field, value): [[OP_REGEXP, field, value]])
198 7578ab0a Michael Hanselmann
199 7578ab0a Michael Hanselmann
  not_regexp_cond = (field_name + pyp.Suppress("!~") + regexp_val)
200 7578ab0a Michael Hanselmann
  not_regexp_cond.setParseAction(lambda (field, value):
201 7578ab0a Michael Hanselmann
                                 [[OP_NOT, [OP_REGEXP, field, value]]])
202 7578ab0a Michael Hanselmann
203 16629d10 Michael Hanselmann
  # Globbing, e.g. name =* "*.site"
204 16629d10 Michael Hanselmann
  glob_cond = (field_name + pyp.Suppress("=*") + quoted_string)
205 16629d10 Michael Hanselmann
  glob_cond.setParseAction(lambda (field, value):
206 16629d10 Michael Hanselmann
                           [[OP_REGEXP, field,
207 16629d10 Michael Hanselmann
                             utils.DnsNameGlobPattern(value)]])
208 16629d10 Michael Hanselmann
209 16629d10 Michael Hanselmann
  not_glob_cond = (field_name + pyp.Suppress("!*") + quoted_string)
210 16629d10 Michael Hanselmann
  not_glob_cond.setParseAction(lambda (field, value):
211 16629d10 Michael Hanselmann
                               [[OP_NOT, [OP_REGEXP, field,
212 16629d10 Michael Hanselmann
                                          utils.DnsNameGlobPattern(value)]]])
213 16629d10 Michael Hanselmann
214 7578ab0a Michael Hanselmann
  # All possible conditions
215 7578ab0a Michael Hanselmann
  condition = (binary_cond ^ bool_cond ^
216 7578ab0a Michael Hanselmann
               in_cond ^ not_in_cond ^
217 16629d10 Michael Hanselmann
               regexp_cond ^ not_regexp_cond ^
218 16629d10 Michael Hanselmann
               glob_cond ^ not_glob_cond)
219 7578ab0a Michael Hanselmann
220 7578ab0a Michael Hanselmann
  # Associativity operators
221 7578ab0a Michael Hanselmann
  filter_expr = pyp.operatorPrecedence(condition, [
222 7578ab0a Michael Hanselmann
    (pyp.Keyword("not").suppress(), 1, pyp.opAssoc.RIGHT,
223 7578ab0a Michael Hanselmann
     lambda toks: [[OP_NOT, toks[0][0]]]),
224 7578ab0a Michael Hanselmann
    (pyp.Keyword("and").suppress(), 2, pyp.opAssoc.LEFT,
225 7578ab0a Michael Hanselmann
     _ConvertLogicOp(OP_AND)),
226 7578ab0a Michael Hanselmann
    (pyp.Keyword("or").suppress(), 2, pyp.opAssoc.LEFT,
227 7578ab0a Michael Hanselmann
     _ConvertLogicOp(OP_OR)),
228 7578ab0a Michael Hanselmann
    ])
229 7578ab0a Michael Hanselmann
230 7578ab0a Michael Hanselmann
  parser = pyp.StringStart() + filter_expr + pyp.StringEnd()
231 7578ab0a Michael Hanselmann
  parser.parseWithTabs()
232 7578ab0a Michael Hanselmann
233 7578ab0a Michael Hanselmann
  # Originally C{parser.validate} was called here, but there seems to be some
234 7578ab0a Michael Hanselmann
  # issue causing it to fail whenever the "not" operator is included above.
235 7578ab0a Michael Hanselmann
236 7578ab0a Michael Hanselmann
  return parser
237 7578ab0a Michael Hanselmann
238 7578ab0a Michael Hanselmann
239 7578ab0a Michael Hanselmann
def ParseFilter(text, parser=None):
240 7578ab0a Michael Hanselmann
  """Parses a query filter.
241 7578ab0a Michael Hanselmann

242 7578ab0a Michael Hanselmann
  @type text: string
243 7578ab0a Michael Hanselmann
  @param text: Query filter
244 7578ab0a Michael Hanselmann
  @type parser: pyparsing.ParserElement
245 7578ab0a Michael Hanselmann
  @param parser: Pyparsing object
246 7578ab0a Michael Hanselmann
  @rtype: list
247 7578ab0a Michael Hanselmann

248 7578ab0a Michael Hanselmann
  """
249 f8638e28 Michael Hanselmann
  logging.debug("Parsing as query filter: %s", text)
250 f8638e28 Michael Hanselmann
251 7578ab0a Michael Hanselmann
  if parser is None:
252 7578ab0a Michael Hanselmann
    parser = BuildFilterParser()
253 7578ab0a Michael Hanselmann
254 7578ab0a Michael Hanselmann
  try:
255 7578ab0a Michael Hanselmann
    return parser.parseString(text)[0]
256 7578ab0a Michael Hanselmann
  except pyp.ParseBaseException, err:
257 7578ab0a Michael Hanselmann
    raise errors.QueryFilterParseError("Failed to parse query filter"
258 7578ab0a Michael Hanselmann
                                       " '%s': %s" % (text, err), err)
259 3f2f55bb Michael Hanselmann
260 3f2f55bb Michael Hanselmann
261 f8638e28 Michael Hanselmann
def _IsHostname(text):
262 f8638e28 Michael Hanselmann
  """Checks if a string could be a hostname.
263 3f2f55bb Michael Hanselmann

264 3f2f55bb Michael Hanselmann
  @rtype: bool
265 3f2f55bb Michael Hanselmann

266 3f2f55bb Michael Hanselmann
  """
267 3f2f55bb Michael Hanselmann
  try:
268 3f2f55bb Michael Hanselmann
    netutils.Hostname.GetNormalizedName(text)
269 3f2f55bb Michael Hanselmann
  except errors.OpPrereqError:
270 f8638e28 Michael Hanselmann
    return False
271 f8638e28 Michael Hanselmann
  else:
272 3f2f55bb Michael Hanselmann
    return True
273 3f2f55bb Michael Hanselmann
274 f8638e28 Michael Hanselmann
275 f8638e28 Michael Hanselmann
def _CheckFilter(text):
276 f8638e28 Michael Hanselmann
  """CHecks if a string could be a filter.
277 f8638e28 Michael Hanselmann

278 f8638e28 Michael Hanselmann
  @rtype: bool
279 f8638e28 Michael Hanselmann

280 f8638e28 Michael Hanselmann
  """
281 f8638e28 Michael Hanselmann
  return bool(frozenset(text) & FILTER_DETECTION_CHARS)
282 f8638e28 Michael Hanselmann
283 f8638e28 Michael Hanselmann
284 f8638e28 Michael Hanselmann
def _CheckGlobbing(text):
285 f8638e28 Michael Hanselmann
  """Checks if a string could be a globbing pattern.
286 f8638e28 Michael Hanselmann

287 f8638e28 Michael Hanselmann
  @rtype: bool
288 f8638e28 Michael Hanselmann

289 f8638e28 Michael Hanselmann
  """
290 f8638e28 Michael Hanselmann
  return bool(frozenset(text) & GLOB_DETECTION_CHARS)
291 f8638e28 Michael Hanselmann
292 f8638e28 Michael Hanselmann
293 6f287cf3 Iustin Pop
def _MakeFilterPart(namefield, text, isnumeric=False):
294 f8638e28 Michael Hanselmann
  """Generates filter for one argument.
295 f8638e28 Michael Hanselmann

296 f8638e28 Michael Hanselmann
  """
297 6f287cf3 Iustin Pop
  if isnumeric:
298 6f287cf3 Iustin Pop
    try:
299 6f287cf3 Iustin Pop
      number = int(text)
300 6f287cf3 Iustin Pop
    except (TypeError, ValueError), err:
301 76b62028 Iustin Pop
      raise errors.OpPrereqError("Invalid job ID passed: %s" % str(err),
302 6f287cf3 Iustin Pop
                                 errors.ECODE_INVAL)
303 6f287cf3 Iustin Pop
    return [OP_EQUAL, namefield, number]
304 6f287cf3 Iustin Pop
  elif _CheckGlobbing(text):
305 f8638e28 Michael Hanselmann
    return [OP_REGEXP, namefield, utils.DnsNameGlobPattern(text)]
306 f8638e28 Michael Hanselmann
  else:
307 f8638e28 Michael Hanselmann
    return [OP_EQUAL, namefield, text]
308 f8638e28 Michael Hanselmann
309 f8638e28 Michael Hanselmann
310 6f287cf3 Iustin Pop
def MakeFilter(args, force_filter, namefield=None, isnumeric=False):
311 f8638e28 Michael Hanselmann
  """Try to make a filter from arguments to a command.
312 f8638e28 Michael Hanselmann

313 f8638e28 Michael Hanselmann
  If the name could be a filter it is parsed as such. If it's just a globbing
314 f8638e28 Michael Hanselmann
  pattern, e.g. "*.site", such a filter is constructed. As a last resort the
315 f8638e28 Michael Hanselmann
  names are treated just as a plain name filter.
316 f8638e28 Michael Hanselmann

317 f8638e28 Michael Hanselmann
  @type args: list of string
318 f8638e28 Michael Hanselmann
  @param args: Arguments to command
319 f8638e28 Michael Hanselmann
  @type force_filter: bool
320 f8638e28 Michael Hanselmann
  @param force_filter: Whether to force treatment as a full-fledged filter
321 03ec545a Michael Hanselmann
  @type namefield: string
322 03ec545a Michael Hanselmann
  @param namefield: Name of field to use for simple filters (use L{None} for
323 03ec545a Michael Hanselmann
    a default of "name")
324 6f287cf3 Iustin Pop
  @type isnumeric: bool
325 6f287cf3 Iustin Pop
  @param isnumeric: Whether the namefield type is numeric, as opposed to
326 6f287cf3 Iustin Pop
    the default string type; this influences how the filter is built
327 f8638e28 Michael Hanselmann
  @rtype: list
328 f8638e28 Michael Hanselmann
  @return: Query filter
329 f8638e28 Michael Hanselmann

330 f8638e28 Michael Hanselmann
  """
331 03ec545a Michael Hanselmann
  if namefield is None:
332 03ec545a Michael Hanselmann
    namefield = "name"
333 03ec545a Michael Hanselmann
334 f8638e28 Michael Hanselmann
  if (force_filter or
335 f8638e28 Michael Hanselmann
      (args and len(args) == 1 and _CheckFilter(args[0]))):
336 f8638e28 Michael Hanselmann
    try:
337 f8638e28 Michael Hanselmann
      (filter_text, ) = args
338 f8638e28 Michael Hanselmann
    except (TypeError, ValueError):
339 f8638e28 Michael Hanselmann
      raise errors.OpPrereqError("Exactly one argument must be given as a"
340 2cfbc784 Iustin Pop
                                 " filter", errors.ECODE_INVAL)
341 f8638e28 Michael Hanselmann
342 f8638e28 Michael Hanselmann
    result = ParseFilter(filter_text)
343 f8638e28 Michael Hanselmann
  elif args:
344 6f287cf3 Iustin Pop
    result = [OP_OR] + map(compat.partial(_MakeFilterPart, namefield,
345 6f287cf3 Iustin Pop
                                          isnumeric=isnumeric), args)
346 f8638e28 Michael Hanselmann
  else:
347 f8638e28 Michael Hanselmann
    result = None
348 f8638e28 Michael Hanselmann
349 f8638e28 Michael Hanselmann
  return result