﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
30546	isinstance() call on SimpleLazyObject doesn't swallow evaluation exceptions on Python3.	Sławek Ehlert	nobody	"When running this little script:

{{{
from django.utils.functional import *

def a_func():
    raise Exception('naah')

slo = SimpleLazyObject(a_func)

assert not isinstance(slo, type)
}}}

I'd expect the assertion to pass. It works as I'd expect it to work on Django 1.11 and Python 2.7. However, it does blow up with the {{{naah}}} exception on both Django 1.11 and 2.2 on Python 3.5 (also on Python 3.6 and 3.7) with the following traceback:
{{{
Traceback (most recent call last):
  File ""<input>"", line 1, in <module>
    assert not isinstance(slo, type)
  File ""... /lib/python3.5/site-packages/django/utils/functional.py"", line 238, in inner
    self._setup()
  File ""... /lib/python3.5/site-packages/django/utils/functional.py"", line 386, in _setup
    self._wrapped = self._setupfunc()
  File ""<input>"", line 2, in a_func
    raise Exception('naah')
Exception: naah
}}}

I'm not sure if this is by design, but the behaviour is certainly inconsistent on Py3 vs. Py2.

I found this problem while trying to run our test suite on Python 3. Unittest framework does an obvious {{{if isinstance(obj, type) and issubclass(obj, case.TestCase):}}} check when collecting the test suite (see https://github.com/python/cpython/blob/v3.5.7/Lib/unittest/loader.py#L122), so when we have a module-level {{{SimpleLazyObject}}} (obviously it wraps a different function than the one I've given here, but also a failing one) it gets unexpectedly evaluated and raises an exception, which prevents us from even gathering the tests on Python 3.

I'm not really sure why this is happening. After some brief debugging, it looks like {{{isinstance}}} function on Python 3 is accessing the {{{__class__}}} attribute (which is wrapped with the {{{new_method_proxy}}} function - see https://github.com/django/django/blob/2.2.2/django/utils/functional.py#L348) causing evaluation of the underlying function, whereas on Python 2.7 {{{isinstance}}} doesn't seem to do that."	Bug	closed	Utilities	dev	Normal	wontfix	SimpleLazyObject lazy evaluation		Accepted	0	0	0	0	0	0
