Commit bf91273f authored by Ophélie Gagnard's avatar Ophélie Gagnard

Downlaod: Add "<<" and ">>" operators.

"<<" and ">>" are like "<=" and ">=" except they select the
closest value and accept "Infinity" for integer comparisons.
parent a0105b6d
......@@ -477,14 +477,15 @@ class NetworkcacheClient(object):
class NetworkcacheFilter(object):
special_word_mapping = {"max":max, "min":max}
parse_criterion = re.compile("([<>]=?|==|:)").split
parse_criterion = re.compile("(<<|>>|[<>]=?|==)").split
operator_mapping = {
">=": operator.ge,
"<=": operator.le,
">": operator.gt,
"<": operator.lt,
"==": operator.eq,
">>": operator.ge,
"<<": operator.le,
}
def __init__(self, criterion_list=()):
......@@ -500,42 +501,41 @@ class NetworkcacheFilter(object):
raise NetworkcacheException(
'Could not parse criterion: missing or invalid separator (%s)'
% criterion)
if parsed_criterion[1] != ':':
parsed_criterion[2] = json.loads(parsed_criterion[2])
elif parsed_criterion[2] not in self.special_word_mapping:
raise NetworkcacheException('Unknown special word %r'
% parsed_criterion[2])
parsed_criterion[2] = json.loads(parsed_criterion[2])
parsed_criterion_list.append(parsed_criterion)
self.criterion_list = parsed_criterion_list
else:
raise NetworkcacheException('Invalid criteria: %s' % criterion_list)
def __call__(self, data_dict_iterator):
def __call__(self, data_dict_list):
''' Return a list of shadir entries that match given criteria
'''
# converting generator into list because the min/max case whould exhaust it
data_dict_list = list(data_dict_iterator)
def safe_op(data_dict):
try:
return _op(data_dict[key], value)
except TypeError:
logger.info('Comparison failed: %s %s %s with types: %s %s',
data_dict[key], op, value,
type(data_dict[key]), type(value))
for key, op, value in self.criterion_list:
data_dict_list = [data_dict for data_dict in data_dict_list if key in data_dict]
data_dict_list = [data_dict for data_dict in data_dict_list
if key in data_dict]
if not data_dict_list:
break
if op == ":":
extremum = self.special_word_mapping[value](
data_dict[key] for data_dict in data_dict_list)
data_dict_list = [data_dict for data_dict in data_dict_list
if data_dict[key] == extremum]
else:
_op = self.operator_mapping[op]
if op in ("<<", ">>"):
filtered_data_dict_list = []
for data_dict in data_dict_list:
try:
if self.operator_mapping[op](data_dict[key], value):
if safe_op(data_dict):
if filtered_data_dict_list and _op(filtered_data_dict_list[0][key], data_dict[key]):
filtered_data_dict_list = [data_dict]
elif filtered_data_dict_list and filtered_data_dict_list[0][key] == data_dict[key]:
filtered_data_dict_list.append(data_dict)
elif not filtered_data_dict_list:
filtered_data_dict_list.append(data_dict)
except TypeError:
logger.info('Comparison failed: %s %s %s'
' with types: %s %s',
data_dict[key], op, value,
type(data_dict[key]), type(value))
data_dict_list = filtered_data_dict_list
else:
data_dict_list = list(filter(safe_op, data_dict_list))
return data_dict_list
class NetworkcacheException(Exception):
......@@ -610,8 +610,8 @@ def cmd_upload(*args):
def cmd_download(*args):
parser = _newArgumentParser("URL of data to download.", key_help, True)
parser.add_argument('meta', nargs='*', metavar='KEY{>=,<=,==,<,>,:}VALUE',
help='Filter metadata. Each argument represents a filter with a comparison condition. The filters will be applied one by one with the arguments processed in the order of appearance.VALUE is expected to be a json dump of a comparable object in Python (strings included), except when the separator is ":" (in this case VALUE must be min or max).')
parser.add_argument('meta', nargs='*', metavar='KEY{>=,<=,==,<,>,>>,<<}VALUE',
help='Filter metadata. Each argument represents a filter with a comparison condition. The filters will be applied one by one with the arguments processed in the order of appearance. VALUE is expected to be a json dump of a comparable object in Python (strings included). "<<" and ">>" return the highest (resp. lowest) values lower (resp.higher) than the given value They accept "Infinity" and "-Infinity" for number comparisons.')
args = parser.parse_args(args or sys.argv[1:])
nc = NetworkcacheClient(args.config)
if args.key:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment