Skip to content

Commit

Permalink
Fix tests on Python 3 by solving some deprecations.
Browse files Browse the repository at this point in the history
  • Loading branch information
jamadden committed Jul 9, 2018
1 parent 73526de commit 987ef6a
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 23 deletions.
8 changes: 5 additions & 3 deletions src/nti/externalization/externalization/__init__.py
Expand Up @@ -108,17 +108,19 @@ def toExternalDictionary(*args, **kwargs): # pragma: no cover


def is_nonstr_iter(v):
warnings.warn("'is_nonstr_iter' will be deleted.", FutureWarning)
warnings.warn("'is_nonstr_iter' will be deleted. It is broken on Python 3",
FutureWarning, stacklevel=2)
return hasattr(v, '__iter__')


def removed_unserializable(ext):
# pylint:disable=too-many-branches
# XXX: Why is this here? We don't use it anymore.
# Can it be removed?
warnings.warn("'removed_unserializable' will be deleted.", FutureWarning)
warnings.warn("'removed_unserializable' will be deleted.", FutureWarning, stacklevel=2)
def _is_sequence(m):
return not isinstance(m, collections.Mapping) and is_nonstr_iter(m)
return (not isinstance(m, (str, collections.Mapping))
and hasattr(m, '__iter__'))

def _clean(m):
if isinstance(m, collections.Mapping):
Expand Down
2 changes: 1 addition & 1 deletion src/nti/externalization/externalization/externalizer.py
Expand Up @@ -252,7 +252,7 @@ def _to_external_object_state(obj, state, top_level=False):
elif result is not _marker:
return result
else:
logger.warn("Recursive call to object %s.", obj)
logger.warning("Recursive call to object %s.", obj)
result = internal_to_standard_external_dictionary(obj,
decorate=False)

Expand Down
22 changes: 16 additions & 6 deletions src/nti/externalization/internalization/updater.py
Expand Up @@ -94,7 +94,15 @@ def _get_update_signature(updater):
spec = _argspec_cache.get(kind)
if spec is None:
try:
argspec = inspect.getargspec(updater.updateFromExternalObject)
if hasattr(inspect, 'getfullargspec'):
# Python 3. getargspec() is deprecated.
argspec = inspect.getfullargspec(updater.updateFromExternalObject) # pylint:disable=no-member
keywords = argspec.varkw
else:
argspec = inspect.getargspec(updater.updateFromExternalObject)
keywords = argspec.keywords
args = argspec.args
defaults = argspec.defaults
except TypeError: # pragma: no cover (This is hard to catch in pure-python coverage mode)
# Cython functions and other extension types are "not a Python function"
# and don't work with this. We assume they use the standard form accepting
Expand All @@ -105,24 +113,24 @@ def _get_update_signature(updater):
# argspec.keywords, if not none, is the name of the **kwarg
# These all must be methods (or at least classmethods), having
# an extra 'self' argument.
if not argspec.keywords:
if not keywords:
# No **kwarg, good!
if len(argspec.args) == 3:
if len(args) == 3:
# update(ext, context) or update(ext, context=None) or update(ext, dataserver)
spec = _UPDATE_ARGS_TWO
else:
# update(ext)
spec = _UPDATE_ARGS_ONE
else:
if len(argspec.args) == 3:
if len(args) == 3:
# update(ext, context, **kwargs) or update(ext, dataserver, **kwargs)
spec = _UPDATE_ARGS_TWO
elif argspec.keywords.startswith("unused") or argspec.keywords.startswith('_'):
elif keywords.startswith("unused") or keywords.startswith('_'):
spec = _UPDATE_ARGS_ONE
else:
spec = _UPDATE_ARGS_CONTEXT_KW

if 'dataserver' in argspec.args and argspec.defaults and len(argspec.defaults) >= 1:
if 'dataserver' in args and defaults and len(defaults) >= 1:
warnings.warn("The type %r still uses updateFromExternalObject(dataserver=None). "
"Please change to context=None." % (kind,),
FutureWarning)
Expand All @@ -131,6 +139,7 @@ def _get_update_signature(updater):

return spec


_usable_updateFromExternalObject_cache = {}

def _obj_has_usable_updateFromExternalObject(obj):
Expand All @@ -154,6 +163,7 @@ def _obj_has_usable_updateFromExternalObject(obj):

return usable_from


try:
from zope.testing import cleanup # pylint:disable=ungrouped-imports
except ImportError: # pragma: no cover
Expand Down
15 changes: 8 additions & 7 deletions src/nti/externalization/tests/test_externalization.py
Expand Up @@ -204,23 +204,24 @@ def toExternalObject(self, **unused_kwargs):


def test_removed_unserializable(self):
import warnings
marker = object()
ext = {'x': 1, 'y': [1, 2, marker], 'z': marker,
'a': {3, 4}, 'b': {'c': (marker, 1)}}
removed_unserializable(ext)
with warnings.catch_warnings(record=True): # removed_unserializable is deprecated
assert_that(removed_unserializable((1, 2, 3)),
is_([1, 2, 3]))

assert_that(removed_unserializable([[(1, 2, 3)]]),
is_([[[1, 2, 3]]]))
removed_unserializable(ext)
assert_that(ext, has_entry('x', is_(1)))
assert_that(ext, has_entry('y', is_([1, 2, None])))
assert_that(ext, has_entry('a', is_([3, 4])))
assert_that(ext, has_entry('z', is_(none())))
assert_that(ext, has_entry('b', has_entry('c', is_([None, 1]))))


assert_that(removed_unserializable((1, 2, 3)),
is_([1, 2, 3]))

assert_that(removed_unserializable([[(1, 2, 3)]]),
is_([[[1, 2, 3]]]))

def test_devmode_non_externalizable_object_replacer(self):
assert_that(calling(DevmodeNonExternalizableObjectReplacementFactory(None)).with_args(self),
raises(NonExternalizableObjectError, "Asked to externalize non-externalizable"))
Expand Down
3 changes: 2 additions & 1 deletion src/nti/externalization/tests/test_internalization.py
Expand Up @@ -106,7 +106,7 @@ def test_search_for_factory_no_type(self):
def test_search_for_factory_updates_search_set(self):
from zope.testing.loggingsupport import InstalledHandler

with warnings.catch_warnings():
with warnings.catch_warnings(record=True):
INT.register_legacy_search_module(__name__)
# The cache is initialized lazily
assert_that(__name__, is_in(INT.LEGACY_FACTORY_SEARCH_MODULES))
Expand Down Expand Up @@ -483,6 +483,7 @@ def updateFromExternalObject(self, ext, dataserver=None):
with warnings.catch_warnings(record=True) as w:
self._callFUT(contained, {})
assert_that(contained, has_property('updated', True))
__traceback_info__ = [repr(i.__dict__) for i in w]
assert_that(w, has_length(1))

def test_update_mapping_with_registered_factory(self):
Expand Down
13 changes: 8 additions & 5 deletions src/nti/externalization/tests/test_zcml.py
Expand Up @@ -190,7 +190,6 @@ def test_scan_package_empty(self):


def test_scan_package_legacy_utility(self):
from nti.externalization import internalization as INT
@interface.implementer(IExtRoot)
class O(object):
__external_can_create__ = True
Expand Down Expand Up @@ -229,13 +228,17 @@ class TestClassObjectFactory(PlacelessSetup,
</configure>
""" % (__name__,)

assertRaisesRegex = getattr(unittest.TestCase,
'assertRaisesRegex',
unittest.TestCase.assertRaisesRegexp)

def test_scan_no_create(self):
class O(object):
pass

self._addFactory(O)
with self.assertRaisesRegexp(xmlconfig.ZopeXMLConfigurationError,
"must set __external_can_create__ to true"):
with self.assertRaisesRegex(xmlconfig.ZopeXMLConfigurationError,
"must set __external_can_create__ to true"):
xmlconfig.string(self.SCAN_THIS_MODULE.replace('PLACEHOLDER', ''))

def test_scan_not_callable(self):
Expand All @@ -244,8 +247,8 @@ class O(object):

self._addFactory(O())

with self.assertRaisesRegexp(xmlconfig.ZopeXMLConfigurationError,
"must be callable"):
with self.assertRaisesRegex(xmlconfig.ZopeXMLConfigurationError,
"must be callable"):
xmlconfig.string(self.SCAN_THIS_MODULE.replace('PLACEHOLDER', ''))

def test_scan_no_name(self):
Expand Down

1 comment on commit 987ef6a

@papachoco
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Please sign in to comment.