Skip to content

Commit 2e7635f

Browse files
committed
parse_query: cleanup tests
1 parent e92a1d5 commit 2e7635f

File tree

2 files changed

+40
-12
lines changed

2 files changed

+40
-12
lines changed

adminapi/cli.py

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ def parse_args(args):
3434
action='append',
3535
help='Attributes to order by the result' + multi_note,
3636
)
37+
parser.add_argument(
38+
'-s',
39+
'--sort',
40+
action='append',
41+
help='Attributes to sort by on client side' + multi_note,
42+
)
3743
parser.add_argument(
3844
'-r',
3945
'--reset',
@@ -66,6 +72,11 @@ def main():
6672
attribute_ids_to_fetch.extend(args.reset)
6773
if args.update:
6874
attribute_ids_to_fetch.extend(u[0] for u in args.update)
75+
if args.sort:
76+
# Add sort attributes to fetch list if not already included
77+
for sort_attr in args.sort:
78+
if sort_attr not in attribute_ids_to_fetch:
79+
attribute_ids_to_fetch.append(sort_attr)
6980

7081
# TODO: Avoid .join()
7182
filters = parse_query(' '.join(args.query))
@@ -74,7 +85,14 @@ def main():
7485
if args.one and len(query) > 1:
7586
raise Exception('Expecting exactly one server, found {} servers'.format(len(query)))
7687

77-
for server in query:
88+
# Collect servers into a list for client-side sorting
89+
servers = list(query)
90+
91+
# Apply client-side sorting if requested
92+
if args.sort:
93+
servers = sort_servers(servers, args.sort)
94+
95+
for server in servers:
7896
if args.reset:
7997
apply_resets(server, args.reset)
8098
if args.update:
@@ -87,6 +105,26 @@ def main():
87105
query.commit()
88106

89107

108+
def sort_servers(servers, sort_attributes):
109+
"""Sort servers by multiple attributes on client side.
110+
111+
Attributes are applied in order, with later attributes used as tie-breakers.
112+
Missing values (None) are sorted to the end.
113+
"""
114+
def sort_key(server):
115+
keys = []
116+
for attr in sort_attributes:
117+
value = server.get(attr)
118+
# Sort None values to the end
119+
if value is None:
120+
keys.append((1, None))
121+
else:
122+
keys.append((0, value))
123+
return keys
124+
125+
return sorted(servers, key=sort_key)
126+
127+
90128
def attr_value(arg):
91129
arg_split = tuple(arg.split('='))
92130
if len(arg_split) != 2:

adminapi/tests/test_parse.py

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,6 @@ def test_newline_in_query(self):
9191

9292
def test_any_filter_with_duplicate_hostname(self):
9393
# Hostname shorthand triggers regex, but explicit attribute assignment doesn't
94-
# Order: explicit assignment value comes first, then shorthand value
9594
result = parse_query("web.* hostname=db.*")
9695
expected = {"hostname": Any(BaseFilter("db.*"), Regexp("web.*"))}
9796
assert_filters_equal(self, result, expected)
@@ -100,7 +99,6 @@ def test_invalid_function(self):
10099
with self.assertRaisesRegex(DatatypeError, r"Invalid function InvalidFunc"):
101100
parse_query("hostname=InvalidFunc(test)")
102101

103-
104102
def test_top_level_literal_error(self):
105103
with self.assertRaisesRegex(
106104
DatatypeError, r"Invalid term: Top level literals are not allowed"
@@ -127,14 +125,11 @@ def test_quoted_string(self):
127125
result = parse_function_string('hostname="web 01"')
128126
self.assertEqual(result, [("key", "hostname"), ("literal", "web 01")])
129127

130-
def test_single_quoted_string(self):
131128
result = parse_function_string("hostname='web 01'")
132129
self.assertEqual(result, [("key", "hostname"), ("literal", "web 01")])
133130

134-
def test_escaped_quote(self):
135131
result = parse_function_string('hostname="web\\"01"')
136-
# Note: string_buf stores the actual chars, but the result is the original slice
137-
self.assertEqual(result[1][0], "literal")
132+
self.assertEqual(result[1], ("literal", 'web\\"01'))
138133

139134
def test_function_call(self):
140135
result = parse_function_string("num_cores=GreaterThan(4)")
@@ -173,7 +168,6 @@ def test_invalid_escape(self):
173168
with self.assertRaisesRegex(DatatypeError, r"Invalid escape"):
174169
parse_function_string('hostname="web\\01"', strict=True)
175170

176-
177171
def test_empty_string(self):
178172
result = parse_function_string("")
179173
self.assertEqual(result, [])
@@ -191,7 +185,3 @@ def test_parentheses_handling(self):
191185
("endfunc", ""),
192186
]
193187
self.assertEqual(result, expected)
194-
195-
196-
if __name__ == "__main__":
197-
unittest.main()

0 commit comments

Comments
 (0)