Skip to content

Commit cc74bee

Browse files
committed
Adds some more python 2 to 3 fixes
Problem: This is just one of many python 2 to 3 fixes that need to be made. This is a progressive enhancement Analysis: Various code portions in the resources class and tests were not python 3 compatible. For instance, the BaseException class deprecated its "message" attribute in 2.6 and removed it in 3.0. This needed to be addressed in several areas. Additionally there were some changes that needed to be made to loops over things that became iterators. Tests: f5/bigip/test/test_resource.py
1 parent b78859e commit cc74bee

2 files changed

Lines changed: 41 additions & 24 deletions

File tree

f5/bigip/resource.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@
101101
from f5.sdk_exception import F5SDKError
102102
from f5.sdk_exception import UnsupportedMethod
103103
from requests.exceptions import HTTPError
104+
from six import iteritems
105+
from six import iterkeys
106+
from six import itervalues
104107

105108

106109
class MissingRequiredCommandParameter(F5SDKError):
@@ -195,7 +198,7 @@ def _missing_required_parameters(rqset, **kwargs):
195198
196199
::returns list
197200
"""
198-
key_set = set(kwargs.keys())
201+
key_set = set(list(iterkeys(kwargs)))
199202
required_minus_received = rqset - key_set
200203
if required_minus_received != set():
201204
return list(required_minus_received)
@@ -307,7 +310,7 @@ def _check_exclusive_parameters(self, **kwargs):
307310
:raises ExclusiveAttributesPresent
308311
"""
309312
if len(self._meta_data['exclusive_attributes']) > 0:
310-
attr_set = set(kwargs.keys())
313+
attr_set = set(list(iterkeys(kwargs)))
311314
ex_set = set(self._meta_data['exclusive_attributes'][0])
312315
common_set = attr_set.intersection(ex_set)
313316
if len(common_set) > 1:
@@ -479,9 +482,17 @@ def _update(self, **kwargs):
479482
# because these are subCollections and _meta_data and
480483
# other non-BIG-IP® attrs are not removed from the subCollections
481484
# See issue #146 for details
482-
for key, value in self.__dict__.items():
485+
tmp = dict()
486+
for key, value in iteritems(self.__dict__):
487+
# In Python2 versions we were changing a dictionary in place,
488+
# but this cannot be done with an iterator as an error is raised.
489+
# So instead we create a temporary holder for the modified dict
490+
# and then re-assign it afterwards.
483491
if isinstance(value, Collection):
484-
self.__dict__.pop(key, '')
492+
pass
493+
else:
494+
tmp[key] = value
495+
self.__dict__ = tmp
485496
data_dict = self.to_dict()
486497

487498
# Remove any read-only attributes from our data_dict before we update
@@ -773,7 +784,7 @@ def _activate_URI(self, selfLinkuri):
773784

774785
# attrs local alias
775786
attribute_reg = self._meta_data.get('attribute_registry', {})
776-
attrs = attribute_reg.values()
787+
attrs = list(itervalues(attribute_reg))
777788
attrs.append(Stats)
778789

779790
(scheme, domain, path, qarg, frag) = urlparse.urlsplit(selfLinkuri)

f5/bigip/test/test_resource.py

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -81,22 +81,22 @@ def test_Resource__local_update_IncompatibleKeys():
8181
r = Resource(mock.MagicMock())
8282
with pytest.raises(DeviceProvidesIncompatibleKey) as DPIKIO:
8383
r._local_update({"_meta_data": "foo"})
84-
assert DPIKIO.value.message ==\
84+
assert str(DPIKIO.value) ==\
8585
"Response contains key '_meta_data' which is incompatible"\
8686
" with this API!!\n Response json: {'_meta_data': 'foo'}"
8787
with pytest.raises(DeviceProvidesIncompatibleKey) as DPIKIO:
8888
r._local_update({"__MANGLENAME": "foo"})
89-
assert DPIKIO.value.message ==\
89+
assert str(DPIKIO.value) ==\
9090
"Device provided '__MANGLENAME' which is disallowed,"\
9191
" it mangles into a Python non-public attribute."
9292
with pytest.raises(DeviceProvidesIncompatibleKey) as DPIKIO:
9393
r._local_update({"for": "foo"})
94-
assert DPIKIO.value.message ==\
94+
assert str(DPIKIO.value) ==\
9595
"Device provided 'for' which is disallowed because"\
9696
" it's a Python keyword."
9797
with pytest.raises(DeviceProvidesIncompatibleKey) as DPIKIO:
9898
r._local_update({"%abcd": "foo"})
99-
assert DPIKIO.value.message ==\
99+
assert str(DPIKIO.value) ==\
100100
"Device provided '%abcd' which is disallowed because"\
101101
" it's not a valid Python 2.7 identifier."
102102

@@ -132,19 +132,26 @@ def test_missing_required_creation_parameter(self):
132132
r._meta_data['required_creation_parameters'] = set(['NONEMPTY'])
133133
with pytest.raises(MissingRequiredCreationParameter) as MRCPEIO:
134134
r.create(partition="Common", name='CreateTest')
135-
assert MRCPEIO.value.message ==\
135+
assert str(MRCPEIO.value) ==\
136136
"Missing required params: ['NONEMPTY']"
137137

138138
def test_KindTypeMismatch(self):
139+
expected_result = (
140+
"For instances of type ''Virtual'' the "
141+
"corresponding kind must be ''tm:ltm:virtual:virtualstate'' "
142+
"but creation returned "
143+
"JSON with kind: 'tm:'"
144+
)
139145
r = Virtual(mock.MagicMock())
146+
140147
r._meta_data['bigip']._meta_data['icr_session'].post.return_value =\
141-
MockResponse({u"kind": u"tm:"})
142-
with pytest.raises(KindTypeMismatch) as KTMmEIO:
148+
MockResponse({"kind": "tm:"})
149+
150+
with pytest.raises(KindTypeMismatch) as error:
143151
r.create(partition="Common", name="test_create")
144-
assert KTMmEIO.value.message ==\
145-
"For instances of type ''Virtual'' the corresponding kind must "\
146-
"be ''tm:ltm:virtual:virtualstate'' but creation returned "\
147-
"JSON with kind: u'tm:'"
152+
153+
result = error.value.args[0]
154+
assert result == expected_result
148155

149156
def test_success(self, fake_vs):
150157
x = fake_vs.create(partition="Common", name="test_create")
@@ -217,7 +224,7 @@ def test__create_with_Collision():
217224
r._meta_data['uri'] = 'URI'
218225
with pytest.raises(URICreationCollision) as UCCEIO:
219226
r.create(uri='URI')
220-
assert UCCEIO.value.message ==\
227+
assert str(UCCEIO.value) ==\
221228
"There was an attempt to assign a new uri to this resource,"\
222229
" the _meta_data['uri'] is URI and it should not be changed."
223230

@@ -235,7 +242,7 @@ def test__check_generation_with_mismatch(self):
235242
r.generation = 1
236243
with pytest.raises(GenerationMismatch) as GMEIO:
237244
r.update(a=u"b", force=False)
238-
assert GMEIO.value.message ==\
245+
assert str(GMEIO.value) ==\
239246
'The generation of the object on the BigIP (0)'\
240247
' does not match the current object(1)'
241248

@@ -267,7 +274,6 @@ def test_Collection_removal(self):
267274
r.update(a=u"b")
268275
submitted = r._meta_data['bigip']. \
269276
_meta_data['icr_session'].put.call_args[1]['json']
270-
271277
assert 'contained' not in submitted
272278

273279
def test_read_only_removal(self):
@@ -366,7 +372,7 @@ def test_read_only_validate(self):
366372
r.generation = 0
367373
with pytest.raises(AttemptedMutationOfReadOnly) as AMOROEIO:
368374
r.modify(READONLY=True)
369-
assert "READONLY" in AMOROEIO.value.message
375+
assert "READONLY" in str(AMOROEIO.value)
370376

371377
def test_reduce_boolean_removes_enabled(self, fake_rsrc):
372378
fake_rsrc.modify(enabled=False)
@@ -425,7 +431,7 @@ def test_invalid_force(self):
425431
r._meta_data['bigip']._meta_data = {'icr_session': mock_session}
426432
with pytest.raises(InvalidForceType) as IFTEIO:
427433
r.delete(force='true')
428-
assert IFTEIO.value.message == 'force parameter must be type bool'
434+
assert str(IFTEIO.value) == 'force parameter must be type bool'
429435

430436

431437
class Element(Resource):
@@ -469,7 +475,7 @@ def test_unregistered_kind(self):
469475
c.generation = 0
470476
with pytest.raises(UnregisteredKind) as UKEIO:
471477
c.get_collection()
472-
assert UKEIO.value.message ==\
478+
assert str(UKEIO.value) ==\
473479
"'tm:' is not registered!"
474480

475481

@@ -479,15 +485,15 @@ def test_missing_required_params(self):
479485
r._meta_data['required_load_parameters'] = set(['IMPOSSIBLE'])
480486
with pytest.raises(MissingRequiredReadParameter) as MRREIO:
481487
r.load(partition='Common', name='test_load')
482-
assert MRREIO.value.message ==\
488+
assert str(MRREIO.value) ==\
483489
"Missing required params: ['IMPOSSIBLE']"
484490

485491
def test_requests_params_collision(self):
486492
r = Resource(mock.MagicMock())
487493
with pytest.raises(RequestParamKwargCollision) as RPKCEIO:
488494
r.load(partition='Common', name='test_load',
489495
requests_params={'partition': 'ERROR'})
490-
assert RPKCEIO.value.message ==\
496+
assert str(RPKCEIO.value) ==\
491497
"Requests Parameter 'partition' collides with a load parameter"\
492498
" of the same name."
493499

0 commit comments

Comments
 (0)