Skip to content

Commit fd52699

Browse files
authored
RD=2144 Add is_not filter operator (#1294)
1 parent 6da1a79 commit fd52699

File tree

3 files changed

+26
-19
lines changed

3 files changed

+26
-19
lines changed

cloudify_cli/cli/helptexts.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -504,11 +504,12 @@
504504
"The labels' keys are saved in lowercase."
505505

506506
LABELS_FILTER_RULES = "A labels' filter rule. Labels' filter rules must be " \
507-
"one of: <key>=<value>, <key>!=<value>, <key> is null," \
508-
" <key> is not null. <value> can be a single string " \
509-
"or a list of strings of the form " \
510-
"[<value1>,<value2>,...]. Any comma and colon in " \
511-
"<value> must be escaped with `\\`. The labels' " \
507+
"one of: <key>=<value>, <key>!=<value>, " \
508+
"<key> is-not <value>, <key> is null, " \
509+
"<key> is not null. <value> can be a single string or " \
510+
"a list of strings of the form " \
511+
"[<value1>,<value2>,...]. Any comma and " \
512+
"colon in <value> must be escaped with `\\`. " \
512513
"The labels' keys specified in the filter rules will " \
513514
"be saved in lower case."
514515

cloudify_cli/filters_utils.py

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
OPERATOR_MAPPING = {
1919
'=': 'any_of',
2020
'!=': 'not_any_of',
21+
'is-not': 'is_not',
2122
'contains': 'contains',
2223
'does-not-contain': 'not_contains',
2324
'starts-with': 'starts_with',
@@ -34,9 +35,9 @@ class InvalidLabelsFilterRuleFormat(CloudifyCliError):
3435
def __init__(self, labels_filter_value):
3536
super(CloudifyCliError, self).__init__(
3637
'The labels filter rule `{0}` is not in the right format. It must '
37-
'be one of: <key>=<value>, <key>!=<value>, <key> is null, '
38-
'<key> is not null. <value> can be a single string or a list of '
39-
'strings of the form [<value1>,<value2>,...]. '
38+
'be one of: <key>=<value>, <key>!=<value>, <key> is-not <value>,'
39+
' <key> is null, <key> is not null. <value> can be a single '
40+
'string or a list of strings of the form [<value1>,<value2>,...]. '
4041
'<value> cannot contain control characters, plus, any comma and '
4142
'colon in <value> must be escaped with `\\`. <key> can '
4243
'contain only letters, digits and the characters '
@@ -94,16 +95,15 @@ def __init__(self, key, values, operator):
9495

9596
@classmethod
9697
def from_string(cls, str_filter_rule):
97-
match_equal = re.match(r'^([\w\-\.]+)(=)([^\n\t\"]+)$',
98-
str_filter_rule)
99-
match_not_equal = re.match(r'^([\w\-\.]+)(!=)([^\n\t\"]+)$',
100-
str_filter_rule)
101-
equal_matching = match_equal or match_not_equal
102-
if equal_matching:
103-
key = equal_matching.group(1).lower()
104-
operator = equal_matching.group(2)
105-
values = cls._get_rule_values(equal_matching.group(3))
106-
return cls(key, values, OPERATOR_MAPPING[operator])
98+
for operator in ['!=', '=', ' is-not ']:
99+
matching = re.match(
100+
r'^([\w\-\.]+)({0})([^\n\t\"]+)$'.format(operator),
101+
str_filter_rule)
102+
if matching:
103+
key = matching.group(1).lower()
104+
operator = matching.group(2)
105+
values = cls._get_rule_values(matching.group(3))
106+
return cls(key, values, OPERATOR_MAPPING[operator.strip()])
107107

108108
match_null = re.match(r'^([\w\-\.]+) (is null)$', str_filter_rule)
109109
match_not_null = re.match(r'^([\w\-\.]+) (is not null)$',
@@ -122,6 +122,8 @@ def __str__(self):
122122
cli_operator = REVERSED_OPERATOR_MAPPING[self['operator']]
123123
if self['operator'] in ('is_null', 'is_not_null'):
124124
return '"{0} {1}"'.format(self['key'], cli_operator)
125+
if cli_operator == 'is-not':
126+
cli_operator = ' is-not '
125127
self['values'] = [val.replace(',', '\\,').replace(':', '\\:')
126128
.replace('$', '\\$') for val in self['values']]
127129
return super(LabelsFilterRule, self).__str__(cli_operator)

cloudify_cli/tests/commands/test_filters.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,11 @@
2424
('"k_l is null"', {'key': 'k_l', 'values': [], 'operator': 'is_null',
2525
'type': 'label'}),
2626
('"l_m-n.o is not null"', {'key': 'l_m-n.o', 'values': [],
27-
'operator': 'is_not_null', 'type': 'label'})
27+
'operator': 'is_not_null', 'type': 'label'}),
28+
('"p is-not [i#:,j k\xf3]"', {'key': 'p', 'values': ['i#:', 'j k\xf3'],
29+
'operator': 'is_not', 'type': 'label'}),
30+
('"q is-not rg@!"', {'key': 'q', 'values': ['rg@!'],
31+
'operator': 'is_not', 'type': 'label'}),
2832
])
2933

3034
# These are not real attributes, but it doesn't matter for the CLI tests

0 commit comments

Comments
 (0)