#33220 closed Cleanup/optimization (wontfix)
Test suite failures when using PYTHONOPTIMIZE or optimization CLI flags
| Reported by: | Keryn Knight | Owned by: | nobody |
|---|---|---|---|
| Component: | Testing framework | Version: | dev |
| Severity: | Normal | Keywords: | |
| Cc: | Triage Stage: | Unreviewed | |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
I can't see any tickets for this, but searching for assert, assertion, -OO, -O2 doesn't necessarily cover all the ways to talk about it, so apologies if this is covered elsewhere!
For reasons entirely unrelated, a while back I added the following to my env:
export PYTHONDONTWRITEBYTECODE=true export PYTHONUNBUFFERED=true export PYTHONOPTIMIZE=2 export PYTHONWARNINGS=default export PYTHONUTF8=1
Most of which have no effect, but to my consternation (because I'd entirely forgotten having done so!), using ./runtests.py suddenly started throwing a lot of errors at me (because of PYTHONOPTIMIZE=2), the list of which follows further below.
Most of the errors fall into either one of:
- using
assert x ==y, 'error'being blown away entirely (in one case, this cryptically results anUnboundLocalErrorinstead) - checking
__doc__values, which are replaced withNone
There are a handful of tests which fail at -O, and a bunch more which do so only when -OO is used. A sticky issue is that there's no great answer for CI:
- running the base suite (
./runtests.pywith none of the optional deps, but with-OO) means some tests/bits won't be covered. - running each of the supported suite combos under normal +
-OOis exhaustive for little benefit and many more suite executions. - not running
-OOat all means at best, any PR will pass without incident (having not broken anything), but without demonstrating things work.
The fix for assert would probably be to either skipIf them or fix the places they're used to raise an exception which is always present, like ValueError or TypeError, though this means changing the exceptions outside of tests in a couple of places :/
The fix for __doc__ is to either skipIf them or selectively test them based on sys.flags.optimize.
I'd personally prefer not to skipIf, because many of the tests assert multiple things, only one of which breaks.
At least one test is also, as far as I can tell, passing incorrectly currently:
FAIL: test_get_version_invalid_version (version.tests.VersionTests) (version=(3, 2, 0, 'gamma', 1, '20210315111111'))
This is actually failing on the length assertion rather than the alpha/beta/... one.
The complete list, then, first at -O:
======================================================================
ERROR: test_file_error_blocking (file_uploads.tests.FileUploadTests)
The server should not block when there are upload errors (bug #8622).
----------------------------------------------------------------------
Traceback (most recent call last):
File "/django/tests/file_uploads/tests.py", line 584, in test_file_error_blocking
self.client.post('/upload_errors/', post_data)
File "/django/django/test/client.py", line 756, in post
response = super().post(path, data=data, content_type=content_type, secure=secure, **extra)
File "/django/django/test/client.py", line 407, in post
return self.generic('POST', path, post_data, content_type,
File "/django/django/test/client.py", line 473, in generic
return self.request(**r)
File "/django/django/test/client.py", line 721, in request
self.check_exception(response)
File "/django/django/test/client.py", line 582, in check_exception
raise exc_value
File "/django/django/core/handlers/exception.py", line 47, in inner
response = get_response(request)
File "/django/django/core/handlers/base.py", line 181, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/django/tests/file_uploads/views.py", line 139, in file_upload_errors
return file_upload_echo(request)
File "/django/tests/file_uploads/views.py", line 76, in file_upload_echo
r = {k: f.name for k, f in request.FILES.items()}
File "/django/django/core/handlers/wsgi.py", line 116, in FILES
self._load_post_and_files()
File "/django/django/http/request.py", line 328, in _load_post_and_files
self._post, self._files = self.parse_file_upload(self.META, data)
File "/django/django/http/request.py", line 288, in parse_file_upload
return parser.parse()
File "/django/django/http/multipartparser.py", line 262, in parse
chunk = handler.receive_data_chunk(chunk, counters[i])
File "/django/tests/file_uploads/uploadhandler.py", line 47, in receive_data_chunk
raise CustomUploadError("Oops!")
file_uploads.uploadhandler.CustomUploadError: Oops!
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/django/tests/file_uploads/tests.py", line 585, in test_file_error_blocking
except reference_error.__class__ as err:
UnboundLocalError: local variable 'reference_error' referenced before assignment
======================================================================
FAIL: test_real_apps_non_set (migrations.test_state.StateTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/django/tests/migrations/test_state.py", line 929, in test_real_apps_non_set
ProjectState(real_apps=['contenttypes'])
AssertionError: AssertionError not raised
======================================================================
FAIL: test_flags_with_pre_compiled_regex (utils_tests.test_regex_helper.LazyReCompileTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/django/tests/utils_tests/test_regex_helper.py", line 54, in test_flags_with_pre_compiled_regex
lazy_test_pattern.match('TEST')
File "/python/3.9.5/lib/python3.9/contextlib.py", line 124, in __exit__
next(self.gen)
File "/django/django/test/testcases.py", line 684, in _assert_raises_or_warns_cm
yield cm
AssertionError: AssertionError not raised
======================================================================
FAIL: test_get_version_invalid_version (version.tests.VersionTests) (version=(3, 2, 0, 'alpha', 1, '20210315111111'))
----------------------------------------------------------------------
Traceback (most recent call last):
File "/django/tests/version/tests.py", line 61, in test_get_version_invalid_version
get_complete_version(version)
AssertionError: AssertionError not raised
======================================================================
FAIL: test_get_version_invalid_version (version.tests.VersionTests) (version=(3, 2, 0, 'gamma', 1, '20210315111111'))
----------------------------------------------------------------------
Traceback (most recent call last):
File "/django/tests/version/tests.py", line 61, in test_get_version_invalid_version
get_complete_version(version)
AssertionError: AssertionError not raised
----------------------------------------------------------------------
Ran 15290 tests in 508.250s
FAILED (failures=4, errors=1,...
At -OO (ignoring those that occurred at -O):
======================================================================
FAIL: test_testcase_ordering (test_runner.test_discover_runner.DiscoverRunnerTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/django/tests/test_runner/test_discover_runner.py", line 301, in test_testcase_ordering
self.assertIn('DocTestCase', [t.__class__.__name__ for t in suite._tests[2:]])
AssertionError: 'DocTestCase' not found in ['Test', 'TestVanillaUnittest', 'SkipDocTestCase']
======================================================================
FAIL: test_migrate_check_plan (migrations.test_commands.MigrateTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/django/django/test/utils.py", line 437, in inner
return func(*args, **kwargs)
File "/django/tests/migrations/test_commands.py", line 293, in test_migrate_check_plan
self.assertEqual(
AssertionError: 'Plan[60 chars]alamander\n Raw Python operation -> Grow salamander tail.\n' != 'Plan[60 chars]alamander\n Raw Python operation\n'
Planned operations:
migrations.0001_initial
Create model Salamander
- Raw Python operation -> Grow salamander tail.
+ Raw Python operation
======================================================================
FAIL: test_migrate_plan (migrations.test_commands.MigrateTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/django/django/test/utils.py", line 437, in inner
return func(*args, **kwargs)
File "/django/tests/migrations/test_commands.py", line 430, in test_migrate_plan
self.assertEqual(
AssertionError: "Plan[90 chars]ation -> Grow salamander tail.\nmigrations.000[199 chars]']\n" != "Plan[90 chars]ation\nmigrations.0002_second\n Create mode[174 chars]']\n"
Planned operations:
migrations.0001_initial
Create model Salamander
- Raw Python operation -> Grow salamander tail.
+ Raw Python operation
migrations.0002_second
Create model Book
Raw SQL operation -> ['SELECT * FROM migrations_book']
migrations.0003_third
Create model Author
Raw SQL operation -> ['SELECT * FROM migrations_author']
======================================================================
FAIL: test_inclusion_tag_registration (template_tests.test_custom.InclusionTagTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/django/tests/template_tests/test_custom.py", line 316, in test_inclusion_tag_registration
self.verify_tag(inclusion.inclusion_no_params, 'inclusion_no_params')
File "/django/tests/template_tests/test_custom.py", line 43, in verify_tag
self.assertEqual(tag.__doc__, 'Expected %s __doc__' % name)
AssertionError: None != 'Expected inclusion_no_params __doc__'
======================================================================
FAIL: test_simple_tag_registration (template_tests.test_custom.SimpleTagTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/django/tests/template_tests/test_custom.py", line 155, in test_simple_tag_registration
self.verify_tag(custom.no_params, 'no_params')
File "/django/tests/template_tests/test_custom.py", line 43, in verify_tag
self.assertEqual(tag.__doc__, 'Expected %s __doc__' % name)
AssertionError: None != 'Expected no_params __doc__'
======================================================================
FAIL: test_preserve_attributes (decorators.tests.MethodDecoratorTests) (Test=<class 'decorators.tests.MethodDecoratorTests.test_preserve_attributes.<locals>.TestPlain'>)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/django/tests/decorators/tests.py", line 271, in test_preserve_attributes
self.assertEqual(Test.method.__doc__, 'A method')
AssertionError: None != 'A method'
======================================================================
FAIL: test_preserve_attributes (decorators.tests.MethodDecoratorTests) (Test=<class 'decorators.tests.MethodDecoratorTests.test_preserve_attributes.<locals>.TestMethodAndClass'>)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/django/tests/decorators/tests.py", line 271, in test_preserve_attributes
self.assertEqual(Test.method.__doc__, 'A method')
AssertionError: None != 'A method'
======================================================================
FAIL: test_preserve_attributes (decorators.tests.MethodDecoratorTests) (Test=<class 'decorators.tests.MethodDecoratorTests.test_preserve_attributes.<locals>.TestFunctionIterable'>)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/django/tests/decorators/tests.py", line 271, in test_preserve_attributes
self.assertEqual(Test.method.__doc__, 'A method')
AssertionError: None != 'A method'
======================================================================
FAIL: test_preserve_attributes (decorators.tests.MethodDecoratorTests) (Test=<class 'decorators.tests.MethodDecoratorTests.test_preserve_attributes.<locals>.TestMethodIterable'>)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/django/tests/decorators/tests.py", line 271, in test_preserve_attributes
self.assertEqual(Test.method.__doc__, 'A method')
AssertionError: None != 'A method'
======================================================================
FAIL: test_cached_property (utils_tests.test_functional.FunctionalTests) (attr='value')
----------------------------------------------------------------------
Traceback (most recent call last):
File "/django/tests/utils_tests/test_functional.py", line 63, in assertCachedPropertyWorks
self.assertEqual(get(Class).__doc__, 'Here is the docstring...')
AssertionError: None != 'Here is the docstring...'
======================================================================
FAIL: test_cached_property (utils_tests.test_functional.FunctionalTests) (attr='other')
----------------------------------------------------------------------
Traceback (most recent call last):
File "/django/tests/utils_tests/test_functional.py", line 63, in assertCachedPropertyWorks
self.assertEqual(get(Class).__doc__, 'Here is the docstring...')
AssertionError: None != 'Here is the docstring...'
======================================================================
FAIL: test_cached_property (utils_tests.test_functional.FunctionalTests) (attr='__foo__')
----------------------------------------------------------------------
Traceback (most recent call last):
File "/django/tests/utils_tests/test_functional.py", line 63, in assertCachedPropertyWorks
self.assertEqual(get(Class).__doc__, 'Here is the docstring...')
AssertionError: None != 'Here is the docstring...'
======================================================================
FAIL: test_cached_property_auto_name (utils_tests.test_functional.FunctionalTests) (attr='_Class__value')
----------------------------------------------------------------------
Traceback (most recent call last):
File "/django/tests/utils_tests/test_functional.py", line 63, in assertCachedPropertyWorks
self.assertEqual(get(Class).__doc__, 'Here is the docstring...')
AssertionError: None != 'Here is the docstring...'
======================================================================
FAIL: test_cached_property_auto_name (utils_tests.test_functional.FunctionalTests) (attr='other')
----------------------------------------------------------------------
Traceback (most recent call last):
File "/django/tests/utils_tests/test_functional.py", line 63, in assertCachedPropertyWorks
self.assertEqual(get(Class).__doc__, 'Here is the docstring...')
AssertionError: None != 'Here is the docstring...'
======================================================================
FAIL: test_attributes (decorators.tests.DecoratorsTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/django/tests/decorators/tests.py", line 91, in test_attributes
self.assertEqual(fully_decorated.__doc__, 'Expected __doc__')
AssertionError: None != 'Expected __doc__'
----------------------------------------------------------------------
Ran 15290 tests in 480.762s
FAILED (failures=15,...
If we want to go ahead and attempt to fix/resolve these, I do have a draft branch fixing the above errors, though it obviously won't do anything on CI, may not catch everything, and may not be the desired way to do it (having excised all the assert statements entirely, for example).
Change History (4)
comment:1 by , 4 years ago
| Resolution: | → wontfix |
|---|---|
| Status: | new → closed |
follow-up: 3 comment:2 by , 4 years ago
Keryn, your point about the second subtest of test_get_version_invalid_version() passing without testing what it claims to test looks valid to me. I would hazard that would be a welcome cleanup PR (and could ref this ticket number, even, maybe, to suggest how it was found).
comment:3 by , 4 years ago
Replying to Jacob Walls:
Keryn, your point about the second subtest of
test_get_version_invalid_version()passing without testing what it claims to test looks valid to me. I would hazard that would be a welcome cleanup PR (and could ref this ticket number, even, maybe, to suggest how it was found).
get_version() is an internal Django utility, so I'd not change this (see comment).
comment:4 by , 4 years ago
I would drop PYTHONOPTIMIZE from your environment, basically no one knows about its existence so most code assumes assert always works.
Raising specific errors instead of using
assertwas already discussed in #32508. We decided that remaining cases are valid and should remain asassert. I don't think it's worth changing other tests that fail with-O.