Fix usage of iterator/list on Python 3

* CombinationEvaluator: convert states (built using zip) to a list
  because states is consumed more than once. On Python 3, zip() returns
  an iterator which can only be consumed once.
* Replace dict.keys()[0] with list(dict.keys())[0]. On Python 3, keys()
  returns an iterator which is not indexable.
* test_event_scenarios: replace filter() with a list-comprehension, the
  test expects a list whereas filter() returns on iterator on Python 3.
* mongo/utils.py: replace obj.keys()[0] with list(obj.keys())[0],
  and replace obj.values()[0] with list(obj.values())[0]
* Add the following API v2 tests to tox.ini in Python 3.4:

  - test_event_scenarios.TestEventAPI.test_get_events_filter_datetime_trait

Change-Id: I28bcb65940edbc226c8dbb272f4e3c040ebc37a1
This commit is contained in:
Victor Stinner 2015-06-16 00:05:49 +02:00
parent 5213933b5f
commit 86ffa59c73
6 changed files with 23 additions and 20 deletions

View File

@ -16,9 +16,8 @@
# under the License.
from six import moves
from oslo_log import log
from six import moves
from ceilometer.alarm import evaluator
from ceilometer.i18n import _
@ -108,6 +107,8 @@ class CombinationEvaluator(evaluator.Evaluator):
states = zip(alarm.rule['alarm_ids'],
moves.map(self._get_alarm_state, alarm.rule['alarm_ids']))
# states is consumed more than once, we need a list
states = list(states)
if self._sufficient_states(alarm, states):
self._transition(alarm, states)

View File

@ -289,8 +289,8 @@ class QueryTransformer(object):
orderby_filter = []
for field in orderby:
field_name = field.keys()[0]
ordering = self.ordering_functions[field.values()[0]]
field_name = list(field.keys())[0]
ordering = self.ordering_functions[list(field.values())[0]]
orderby_filter.append((field_name, ordering))
return orderby_filter
@ -312,12 +312,12 @@ class QueryTransformer(object):
del tree["not"]
def transform(subtree):
op = subtree.keys()[0]
op = list(subtree.keys())[0]
if op in ["and", "or"]:
[transform(child) for child in subtree[op]]
elif op == "not":
negated_tree = subtree[op]
negated_op = negated_tree.keys()[0]
negated_op = list(negated_tree.keys())[0]
if negated_op == "and":
_apply_de_morgan(subtree, negated_tree, negated_op)
transform(subtree)
@ -326,7 +326,8 @@ class QueryTransformer(object):
transform(subtree)
elif negated_op == "not":
# two consecutive not annihilates themselves
new_op = negated_tree.values()[0].keys()[0]
value = list(negated_tree.values())[0]
new_op = list(value.keys())[0]
subtree[new_op] = negated_tree[negated_op][new_op]
del subtree["not"]
transform(subtree)
@ -352,8 +353,8 @@ class QueryTransformer(object):
def _handle_not_op(self, negated_tree):
# assumes that not is moved to the leaf already
# so we are next to a leaf
negated_op = negated_tree.keys()[0]
negated_field = negated_tree[negated_op].keys()[0]
negated_op = list(negated_tree.keys())[0]
negated_field = list(negated_tree[negated_op].keys())[0]
value = negated_tree[negated_op][negated_field]
if negated_op == "=":
return {negated_field: {"$ne": value}}
@ -364,8 +365,8 @@ class QueryTransformer(object):
{self.operators[negated_op]: value}}}
def _handle_simple_op(self, simple_op, nodes):
field_name = nodes.keys()[0]
field_value = nodes.values()[0]
field_name = list(nodes.keys())[0]
field_value = list(nodes.values())[0]
# no operator for equal in Mongo
if simple_op == "=":
@ -377,8 +378,8 @@ class QueryTransformer(object):
return op
def _process_json_tree(self, condition_tree):
operator_node = condition_tree.keys()[0]
nodes = condition_tree.values()[0]
operator_node = list(condition_tree.keys())[0]
nodes = list(condition_tree.values())[0]
if operator_node in self.complex_operators:
return self._handle_complex_op(operator_node, nodes)

View File

@ -102,14 +102,14 @@ class TestComplexQuery(base.BaseTestCase):
filter_expr = {"AND": [{"=": {"project_id": 42}},
{"=": {"project_id": 44}}]}
self.query._convert_operator_to_lower_case(filter_expr)
self.assertEqual("and", filter_expr.keys()[0])
self.assertEqual("and", list(filter_expr.keys())[0])
filter_expr = {"Or": [{"=": {"project_id": 43}},
{"anD": [{"=": {"project_id": 44}},
{"=": {"project_id": 42}}]}]}
self.query._convert_operator_to_lower_case(filter_expr)
self.assertEqual("or", filter_expr.keys()[0])
self.assertEqual("and", filter_expr["or"][1].keys()[0])
self.assertEqual("or", list(filter_expr.keys())[0])
self.assertEqual("and", list(filter_expr["or"][1].keys())[0])
def test_invalid_filter_misstyped_field_name_samples(self):
filter = {"=": {"project_id11": 42}}

View File

@ -223,7 +223,7 @@ class TestEventAPI(EventTestBase):
self.assertEqual(1, len(data))
self.assertEqual('Bar', data[0]['event_type'])
traits = filter(lambda x: x['name'] == 'trait_B', data[0]['traits'])
traits = [x for x in data[0]['traits'] if x['name'] == 'trait_B']
self.assertEqual(1, len(traits))
self.assertEqual('integer', traits[0]['type'])
self.assertEqual('101', traits[0]['value'])
@ -236,7 +236,7 @@ class TestEventAPI(EventTestBase):
self.assertEqual(1, len(data))
self.assertEqual('Zoo', data[0]['event_type'])
traits = filter(lambda x: x['name'] == 'trait_C', data[0]['traits'])
traits = [x for x in data[0]['traits'] if x['name'] == 'trait_C']
self.assertEqual(1, len(traits))
self.assertEqual('float', traits[0]['type'])
self.assertEqual('200.123456', traits[0]['value'])
@ -247,7 +247,7 @@ class TestEventAPI(EventTestBase):
'value': '2014-01-01T05:00:00',
'type': 'datetime'}])
self.assertEqual(1, len(data))
traits = filter(lambda x: x['name'] == 'trait_D', data[0]['traits'])
traits = [x for x in data[0]['traits'] if x['name'] == 'trait_D']
self.assertEqual(1, len(traits))
self.assertEqual('datetime', traits[0]['type'])
self.assertEqual('2014-01-01T05:00:00', traits[0]['value'])

View File

@ -231,7 +231,7 @@ class AggregatorTransformer(ScalingTransformer):
self.retention_time))
full = self.aggregated_samples >= self.size
if full or expired:
x = self.samples.values()
x = list(self.samples.values())
# gauge aggregates need to be averages
for s in x:
if s.type == sample.TYPE_GAUGE:

View File

@ -50,6 +50,7 @@ commands = python -m testtools.run \
ceilometer.tests.api.v2.test_alarm_scenarios.TestAlarms.test_alarms_query_with_timestamp \
ceilometer.tests.api.v2.test_app \
ceilometer.tests.api.v2.test_complex_query_scenarios.TestQueryMetersController.test_query_with_isotime \
ceilometer.tests.api.v2.test_event_scenarios.TestEventAPI.test_get_events_filter_datetime_trait \
ceilometer.tests.api.v2.test_list_resources_scenarios.TestListResources.test_with_invalid_resource_id \
ceilometer.tests.api.v2.test_query \
ceilometer.tests.compute.virt.libvirt.test_inspector \