Merge "Avoid using hasattr() on troveclient resources for py3 porting"

This commit is contained in:
Zuul 2018-03-19 06:48:31 +00:00 committed by Gerrit Code Review
commit aaf4f2642f
3 changed files with 48 additions and 5 deletions

View File

@ -238,7 +238,18 @@ class LaunchForm(forms.SelfHandlingForm):
# only add to choices if datastore has at least one version
version_choices = ()
for v in versions:
if hasattr(v, 'active') and not v.active:
# NOTE(zhaochao): troveclient API resources are lazy
# loading objects. When an attribute is not found, the
# get() method of the Manager object will be called
# with the ID of the resource. However for
# datastore_versions, the get() method is expecting two
# arguments: datastore and datastore_version(name), so
# TypeError will be raised as not enough arguments are
# passed. In Python 2.x, hasattr() won't reraise the
# exception(which is not correct), but reraise under
# Python 3(which should be correct).
# Use v.to_dict() to verify the 'active' info instead.
if not v.to_dict().get('active', True):
continue
selection_text = self._build_datastore_display_text(
ds.name, v.name)

View File

@ -12,7 +12,6 @@
# License for the specific language governing permissions and limitations
# under the License.
import copy
import logging
import six
@ -378,7 +377,26 @@ class DatabaseConfigurationsTests(test.TestCase):
'configuration_update',),
config_param_manager: ('get',)})
def test_values_tab_apply_action(self):
config = copy.deepcopy(self.database_configurations.first())
# NOTE(zhaochao): we cannot use copy.deepcopy() under Python 3,
# because of the lazy-loading feature of the troveclient Resource
# objects. copy.deepcopy will use hasattr to search for the
# '__setstate__' attribute of the resource object. As the resource
# object is lazy loading, searching attributes relys on the 'is_load'
# property, unfortunately this property is also not loaded at the
# moment, then we're getting in an infinite loop there. Python will
# raise RuntimeError saying "maximum recursion depth exceeded", this is
# ignored under Python 2.x, but reraised under Python 3 by hasattr().
#
# Temporarily importing troveclient and reconstructing a configuration
# object from the original config object's dict info will make this
# case (and the next) working under Python 3.
original_config = self.database_configurations.first()
from troveclient.v1 import configurations
config = configurations.Configuration(
configurations.Configurations(None), original_config.to_dict())
# Making sure the newly constructed config object is the same as
# the original one.
self.assertEqual(config, original_config)
# setup the configuration parameter manager
config_param_mgr = config_param_manager.ConfigParamManager(
@ -412,7 +430,16 @@ class DatabaseConfigurationsTests(test.TestCase):
'configuration_update',),
config_param_manager: ('get',)})
def test_values_tab_apply_action_exception(self):
config = copy.deepcopy(self.database_configurations.first())
# NOTE(zhaochao) Please refer to the comment at the beginning of the
# 'test_values_tab_apply_action' about not using copy.deepcopy() for
# details.
original_config = self.database_configurations.first()
from troveclient.v1 import configurations
config = configurations.Configuration(
configurations.Configurations(None), original_config.to_dict())
# Making sure the newly constructed config object is the same as
# the original one.
self.assertEqual(config, original_config)
# setup the configuration parameter manager
config_param_mgr = config_param_manager.ConfigParamManager(

View File

@ -211,7 +211,12 @@ class SetInstanceDetailsAction(workflows.Action):
# only add to choices if datastore has at least one version
version_choices = ()
for v in versions:
if hasattr(v, 'active') and not v.active:
# NOTE(zhaochao): please refer to the comment about
# the same change for 'populate_datastore_choices'
# of 'LaunchForm' in
# trove_dashboard/content/database_clusters/forms.py
# for details.
if not v.to_dict().get('active', True):
continue
if self.backup_id:
if v.id != backup.datastore['version_id']: