jezdez / django-discover-runner

A Django test runner based on unittest2's test discovery.
http://pypi.python.org/pypi/django-discover-runner
Other
132 stars 13 forks source link

"DatabaseError: duplicate column name" - bug with custom model's abstract class #16

Open user0007 opened 11 years ago

user0007 commented 11 years ago

Hi,

I have a problem with django-discover-runner and custom model's abtrsact class.

Example:

lib.py

from django.db import models

class ModelAbstract(models.base.ModelBase):
    def __new__(cls, name, bases, attrs):
        dateable = False
        if 'Meta' in attrs:
            if hasattr(attrs['Meta'], 'dateable'):
                dateable = attrs['Meta'].dateable
                delattr(attrs['Meta'], 'dateable')

     super_new = super(ModelAbstract, cls).__new__(cls, name, bases, attrs)

     if hasattr(super_new, '_meta') and not super_new._meta.abstract:
         if hasattr(super_new._meta, 'dateable'):
             dateable = super_new._meta.dateable
         else:
             super_new._meta.dateable = dateable

         if dateable:
             super_new.add_to_class('created_date',
                 models.DateTimeField('created at', auto_now_add=True))
       return super_new

class BaseModel(models.Model):
    __metaclass__ = ModelAbstract

    class Meta:
        abstract = True

models.py

class MyModel(BaseModel):
    name = models.CharField(max_length=100)

    class Meta:
        dateable = True

tests.py

from django.test import TestCase
from .models import MyModel

class SetUpProjectTestCase(TestCase):
    def setUp(self):
        self.obj = MyModel()
        self.obj.name = '...'
        self.obj.save()

    def tearDown(self):
        self.obj.delete()

settings.py

INSTALLED_APPS = (
    'discover_runner',
    'myapp',
)
TEST_RUNNER = 'discover_runner.DiscoverRunner'

django-discover-runner (whole project):

python manage.py test --settings=mysettings

Creating test database for alias 'default'... DatabaseError: duplicate column name: created_date

:(

django-discover-runner (per app):

python manage.py test myapp --settings=mysettings

OK

Django default test (whole project):

python manage.py test --settings=mysettings

OK

Django default test (per app):

python manage.py test myapp --settings=mysettings

OK

What is wrong with django-discover-runner and test for whole project?

jezdez commented 11 years ago

Can you run the tests with the --traceback option and paste it here?

user0007 commented 11 years ago

Of course.

Traceback (most recent call last):
  File "/home/venvs/local/lib/python2.7/site-packages/django/core/management/base.py", line 222, in run_from_argv
    self.execute(*args, **options.__dict__)
  File "/home/venvs/local/lib/python2.7/site-packages/django/core/management/commands/test.py", line 72, in execute
    super(Command, self).execute(*args, **options)
  File "/home/venvs/local/lib/python2.7/site-packages/django/core/management/base.py", line 255, in execute
    output = self.handle(*args, **options)
  File "/home/venvs/local/lib/python2.7/site-packages/django/core/management/commands/test.py", line 89, in handle
    failures = test_runner.run_tests(test_labels)
  File "/home/venvs/local/lib/python2.7/site-packages/discover_runner/runner.py", line 154, in run_tests
    old_config = self.setup_databases()
  File "/home/venvs/local/lib/python2.7/site-packages/discover_runner/runner.py", line 116, in setup_databases
    return setup_databases(self.verbosity, self.interactive, **kwargs)
  File "/home/venvs/local/lib/python2.7/site-packages/discover_runner/runner.py", line 289, in setup_databases
    verbosity, autoclobber=not interactive)
  File "/home/venvs/local/lib/python2.7/site-packages/django/db/backends/creation.py", line 293, in create_test_db
    load_initial_data=False)
  File "/home/venvs/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 161, in call_command
    return klass.execute(*args, **defaults)
  File "/home/venvs/local/lib/python2.7/site-packages/django/core/management/base.py", line 255, in execute
    output = self.handle(*args, **options)
  File "/home/venvs/local/lib/python2.7/site-packages/django/core/management/base.py", line 385, in handle
    return self.handle_noargs(**options)
  File "/home/venvs/local/lib/python2.7/site-packages/django/core/management/commands/syncdb.py", line 102, in handle_noargs
    cursor.execute(statement)
  File "/home/venvs/local/lib/python2.7/site-packages/django/db/backends/sqlite3/base.py", line 366, in execute
    six.reraise(utils.DatabaseError, utils.DatabaseError(*tuple(e.args)), sys.exc_info()[2])
  File "/home/venvs/local/lib/python2.7/site-packages/django/db/backends/sqlite3/base.py", line 362, in execute
    return Database.Cursor.execute(self, query, params)
DatabaseError: duplicate column name: created_date
carljm commented 11 years ago

In order to debug this, I would insert an import pdb; pdb.set_trace() in your metaclass and use the bt command to try to understand how or why it's being run twice. My guess is that due to import weirdness (which could be specific to your project, if you're mucking with sys.path at all or still using a Django 1.3-era manage.py) some module is being imported twice under two different import paths. I think unittest discovery can cause additional imports too, which might be why this is only triggered under discover-runner. But it's going to be very hard to debug this type of issue without access to the actual project.

user0007 commented 11 years ago

I found solution! The error is caused by relative import in tests.py:

from .models import MyModel

raises error, but:

from apps.myapp.models import MyModel

works fine o_O

The same error occurring in Django 1.6b1