#35402: DatabaseFeatures.django_test_skips crashes when it references a class in
another test module
-------------------------------------+-------------------------------------
               Reporter:  Tim        |          Owner:  nobody
  Graham                             |
                   Type:  Bug        |         Status:  new
              Component:  Database   |        Version:  dev
  layer (models, ORM)                |
               Severity:  Normal     |       Keywords:
           Triage Stage:             |      Has patch:  0
  Unreviewed                         |
    Needs documentation:  0          |    Needs tests:  0
Patch needs improvement:  0          |  Easy pickings:  0
                  UI/UX:  0          |
-------------------------------------+-------------------------------------
 Since the introduction of `DatabaseFeatures.django_test_skips` (#32178),
 I've used it to skip test classes, however, this can crash if there are
 multiple test modules in a package.

 To reproduce, first make this modification to skip a class
 {{{#!diff
 diff --git a/django/db/backends/sqlite3/features.py
 b/django/db/backends/sqlite3/features.py
 index d95c6fb2d1..51229fe970 100644
 --- a/django/db/backends/sqlite3/features.py
 +++ b/django/db/backends/sqlite3/features.py
 @@ -68,8 +68,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
      def django_test_skips(self):
          skips = {
              "SQLite stores values rounded to 15 significant digits.": {
 -                "model_fields.test_decimalfield.DecimalFieldTests."
 -                "test_fetch_from_db_without_float_rounding",
 +                "model_fields.test_decimalfield.DecimalFieldTests",
              },
              "SQLite naively remakes the table on field alteration.": {
 }}}

 Then try to execute a test module in `model_fields` besides the one with
 the skip:
 {{{#!shell
 $ ./tests/runtests.py model_fields.test_autofield
 Testing against Django installed in '/home/tim/code/django/django' with up
 to 3 processes
 Found 62 test(s).
 Creating test database for alias 'default'...
 Traceback (most recent call last):
   File "/home/tim/code/django/django/utils/module_loading.py", line 30, in
 import_string
     return cached_import(module_path, class_name)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/home/tim/code/django/django/utils/module_loading.py", line 16, in
 cached_import
     return getattr(module, class_name)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 AttributeError: module 'model_fields' has no attribute 'test_decimalfield'

 The above exception was the direct cause of the following exception:

 Traceback (most recent call last):
   File "/home/tim/code/django/./tests/runtests.py", line 784, in <module>
     failures = django_tests(
                ^^^^^^^^^^^^^
   File "/home/tim/code/django/./tests/runtests.py", line 422, in
 django_tests
     failures = test_runner.run_tests(test_labels)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/home/tim/code/django/django/test/runner.py", line 1066, in
 run_tests
     old_config = self.setup_databases(
                  ^^^^^^^^^^^^^^^^^^^^^
   File "/home/tim/code/django/django/test/runner.py", line 964, in
 setup_databases
     return _setup_databases(
            ^^^^^^^^^^^^^^^^^
   File "/home/tim/code/django/django/test/utils.py", line 206, in
 setup_databases
     connection.creation.create_test_db(
   File "/home/tim/code/django/django/db/backends/base/creation.py", line
 102, in create_test_db
     self.mark_expected_failures_and_skips()
   File "/home/tim/code/django/django/db/backends/base/creation.py", line
 356, in mark_expected_failures_and_skips
     test_case = import_string(test_case_name)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/home/tim/code/django/django/utils/module_loading.py", line 32, in
 import_string
     raise ImportError(
 ImportError: Module "model_fields" does not define a "test_decimalfield"
 attribute/class
 }}}

 A naive fix:
 {{{#!diff
 diff --git a/django/db/backends/base/creation.py
 b/django/db/backends/base/creation.py
 index 6856fdb596..f6cc270b16 100644
 --- a/django/db/backends/base/creation.py
 +++ b/django/db/backends/base/creation.py
 @@ -350,6 +350,9 @@ class BaseDatabaseCreation:
                  test_app = test_name.split(".")[0]
                  # Importing a test app that isn't installed raises
 RuntimeError.
                  if test_app in settings.INSTALLED_APPS:
 +                    # If this is a a test class, it may need to be
 imported.
 +                    if test_name.count(".") == 2:
 +                        import_string(test_name)
                      test_case = import_string(test_case_name)
                      test_method = getattr(test_case, test_method_name)
                      setattr(test_case, test_method_name,
 skip(reason)(test_method))
 }}}
-- 
Ticket URL: <https://code.djangoproject.com/ticket/35402>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/0107018f10ae9e2b-c223f599-eff4-492e-bde1-85500a28f536-000000%40eu-central-1.amazonses.com.

Reply via email to