Opened 13 months ago

Closed 3 months ago

#22279 closed Bug (fixed)

AttributeError: 'db.backends.dummy.base.DatabaseWrapper' object has no attribute 'Database'

Reported by: blueyed Owned by: nobody
Component: Database layer (models, ORM) Version: master
Severity: Normal Keywords:
Cc: Triage Stage: Ready for checkin
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

I am getting a AttributeError: 'DatabaseWrapper' object has no attribute 'Database' exception, while trying to setup/use py.test with Django.

DJANGO_SECRET_KEY=foo DJANGO_SETTINGS_MODULE=config.settings PYTHONPATH=. py.test -s --ipdb project/model/tests.py

self.wrapper is django.db.backends.dummy.base.DatabaseWrapper.

> …/django-master/django/db/utils.py(86)__exit__()
     85         ):
---> 86             db_exc_type = getattr(self.wrapper.Database, dj_exc_type.__name__)
     87             if issubclass(exc_type, db_exc_type):

ipdb> bt
  …/django-master/django/test/testcases.py(857)<genexpr>()
    855     """
    856     return all(conn.features.supports_transactions
--> 857                for conn in connections.all())
    858 
    859 

  …/django-master/django/utils/functional.py(55)__get__()
     53         if instance is None:
     54             return self
---> 55         res = instance.__dict__[self.func.__name__] = self.func(instance)
     56         return res
     57 

  …/django-master/django/db/backends/__init__.py(701)supports_transactions()
    699                 self.connection.commit()
    700         finally:
--> 701             self.connection.leave_transaction_management()
    702         return count == 0
    703 

  …/django-master/django/db/backends/__init__.py(320)leave_transaction_management()
    318                 "Transaction managed block ended with pending COMMIT/ROLLBACK")
    319 
--> 320         if managed == self.get_autocommit():
    321             self.set_autocommit(not managed)
    322 

  …/django-master/django/db/backends/__init__.py(327)get_autocommit()
    325         Check the autocommit state.
    326         """
--> 327         self.ensure_connection()
    328         return self.autocommit
    329 

  …/django-master/django/db/backends/__init__.py(124)ensure_connection()
    122         if self.connection is None:
    123             with self.wrap_database_errors:
--> 124                 self.connect()
    125 
    126     ##### Backend-specific wrappers for PEP-249 connection methods #####

> …/django-master/django/db/utils.py(86)__exit__()
     84                 Error,
     85         ):
---> 86             db_exc_type = getattr(self.wrapper.Database, dj_exc_type.__name__)
     87             if issubclass(exc_type, db_exc_type):
     88                 dj_exc_value = dj_exc_type(*exc_value.args)

  …/django-master/django/test/testcases.py(182)__call__()
    180         if not skipped:
    181             try:
--> 182                 self._pre_setup()
    183             except Exception:
    184                 result.addError(self, sys.exc_info())

  …/django-master/django/test/testcases.py(749)_pre_setup()
    747                 flush.Command.emit_post_migrate(verbosity=0, interactive=False, database=db_name)
    748         try:
--> 749             self._fixture_setup()
    750         except Exception:
    751             if self.available_apps is not None:

  …/django-master/django/test/testcases.py(870)_fixture_setup()
    868 
    869     def _fixture_setup(self):
--> 870         if not connections_support_transactions():
    871             return super(TestCase, self)._fixture_setup()
    872 

  …/django-master/django/test/testcases.py(857)connections_support_transactions()
    855     """
    856     return all(conn.features.supports_transactions
--> 857                for conn in connections.all())
    858 
    859 

  …/django-master/django/test/testcases.py(857)<genexpr>()
    855     """
    856     return all(conn.features.supports_transactions
--> 857                for conn in connections.all())
    858 
    859 

  …/django-master/django/utils/functional.py(55)__get__()
     53         if instance is None:
     54             return self
---> 55         res = instance.__dict__[self.func.__name__] = self.func(instance)
     56         return res
     57 

  …/django-master/django/db/backends/__init__.py(701)supports_transactions()
    699                 self.connection.commit()
    700         finally:
--> 701             self.connection.leave_transaction_management()
    702         return count == 0
    703 

  …/django-master/django/db/backends/__init__.py(320)leave_transaction_management()
    318                 "Transaction managed block ended with pending COMMIT/ROLLBACK")
    319 
--> 320         if managed == self.get_autocommit():
    321             self.set_autocommit(not managed)
    322 

  …/django-master/django/db/backends/__init__.py(327)get_autocommit()
    325         Check the autocommit state.
    326         """
--> 327         self.ensure_connection()
    328         return self.autocommit
    329 

  …/django-master/django/db/backends/__init__.py(124)ensure_connection()
    122         if self.connection is None:
    123             with self.wrap_database_errors:
--> 124                 self.connect()
    125 
    126     ##### Backend-specific wrappers for PEP-249 connection methods #####

> …/django-master/django/db/utils.py(86)__exit__()
     84                 Error,
     85         ):
---> 86             db_exc_type = getattr(self.wrapper.Database, dj_exc_type.__name__)
     87             if issubclass(exc_type, db_exc_type):
     88                 dj_exc_value = dj_exc_type(*exc_value.args)

Change History (8)

comment:1 Changed 13 months ago by timo

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Resolution set to needsinfo
  • Status changed from new to closed

It's not clear to me that this is a bug in Django, or if it is, how we can reproduce it. More likely, you should first use our support channels to see if others have been able to use py.test with Django. A quick search reveals pytest-django which suggests others have been able successfully integrate the two projects.

https://code.djangoproject.com/wiki/TicketClosingReasons/UseSupportChannels

comment:2 Changed 13 months ago by blueyed

  • Resolution needsinfo deleted
  • Status changed from closed to new

I am using pytest-django already.

The problem gets triggered, because DATABASES is empty and therefore the dummy database is used.

From DatabaseErrorWrapper:

It must have a Database attribute defining PEP-249 exceptions.

class DatabaseErrorWrapper(object):
    """
    Context manager and decorator that re-throws backend-specific database
    exceptions using Django's common wrappers.
    """

    def __init__(self, wrapper):
        """
        wrapper is a database wrapper.

        It must have a Database attribute defining PEP-249 exceptions.
        """
        self.wrapper = wrapper

comment:3 Changed 13 months ago by timo

Thanks for the additional info. Can you provide a test case for Django's test suite that isn't dependent on py.test (or at least a sample project we can use to reproduce the error)? Is this a regression on master for something that worked with Django 1.6?

comment:4 Changed 13 months ago by blueyed

It's rather trivial: create a new project, an app, add a model and tests that use the model (and therefore the database).
Then remove the DATABASES setting, and run the tests.

This is constructed, of course, but I've run into this when DATABASES was not setup correctly by accident - and the error could have been friendlier.

Again, I think that the dummy backend has to provide the Database attribute required by DatabaseErrorWrapper - or it must never get wrapped in the first place (if that's an option).

comment:5 Changed 13 months ago by aaugustin

  • Triage Stage changed from Unreviewed to Accepted

comment:6 Changed 3 months ago by claudep

  • Has patch set

comment:7 Changed 3 months ago by timgraham

  • Triage Stage changed from Accepted to Ready for checkin

comment:8 Changed 3 months ago by Claude Paroz <claude@…>

  • Resolution set to fixed
  • Status changed from new to closed

In 3c5d1edb39020f549c58e0696b8ab2f03a88d753:

Fixed #22279 -- Prevented dummy backend going through DatabaseErrorWrapper

Thanks Daniel Hahler for the report and Tim Graham for the review.

Note: See TracTickets for help on using tickets.
Back to Top