Opened 7 years ago

Closed 7 years ago

Last modified 4 years ago

#10249 closed (fixed)

Cannot create a consistent method resolution order (MRO) for bases FieldFile, File

Reported by: kmtracey Owned by: mitsuhiko
Component: Database layer (models, ORM) Version: 1.2-beta
Severity: Keywords:
Cc: marcelo@… Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: UI/UX:

Description (last modified by kmtracey)

Originally reported here:

Easily recreatable:

Python 2.5.1 (r251:54863, Jul 31 2008, 23:17:40) 
[GCC 4.1.3 20070929 (prerelease) (Ubuntu 4.1.2-16ubuntu2)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from ttt.models import FileT
>>> from django.core.files import File
>>> f = open('ttt/')
"from django.db import models\n\n# Create your models here.\nclass FileT(models.Model):\n    name = models.CharField(max_length=22)\n    file = models.FileField(upload_to='tmp')\n\n"
>>> FileT.objects.create(name='x',file=File(f))
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/home/kmt/tmp/django/trunk/django/db/models/", line 99, in create
    return self.get_query_set().create(**kwargs)
  File "/home/kmt/tmp/django/trunk/django/db/models/", line 352, in create
  File "/home/kmt/tmp/django/trunk/django/db/models/", line 328, in save
    self.save_base(force_insert=force_insert, force_update=force_update)
  File "/home/kmt/tmp/django/trunk/django/db/models/", line 388, in save_base
    values = [(f, f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, True))) for f in meta.local_fields if not isinstance(f, AutoField)]
  File "/home/kmt/tmp/django/trunk/django/db/models/fields/", line 184, in pre_save
    file = super(FileField, self).pre_save(model_instance, add)
  File "/home/kmt/tmp/django/trunk/django/db/models/fields/", line 179, in pre_save
    return getattr(model_instance, self.attname)
  File "/home/kmt/tmp/django/trunk/django/db/models/fields/", line 135, in __get__
    (file.__class__, FieldFile), {})
TypeError: Cannot create a consistent method resolution
order (MRO) for bases FieldFile, File

Behavior was introduced in r9766, the create() works in r9765. I do not know enough about the code here to know if any fix for the other r9766-related tickets (#10121, #10179, #10196) would fix this, figured it might be worth its own ticket.

Attachments (1)

10249.diff (706 bytes) - added by kmtracey 7 years ago.

Download all attachments as: .zip

Change History (11)

comment:1 Changed 7 years ago by rokclimb15

  • Cc rokclimb15@… added
  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset

comment:2 Changed 7 years ago by kmtracey

The problem is with this code in source:django/trunk/django/db/models/fields/ in the FileDescriptor class (around line 130):

        elif isinstance(file, File) and not isinstance(file, FieldFile):
            # Other types of files may be assigned as well, but they need to
            # have the FieldFile interface added to them
            file_copy = copy.copy(file)
            file_copy.__class__ = type(file.__class__.__name__, 
                                       (file.__class__, self.field.attr_class), {})

self.field.attr_class is going to be FieldFile in the specific case noted here (it can also be ImageFieldFile). But FieldFile is based on File, so that code is essentially trying to do:

>>> class File(object): pass
>>> class FieldFile(File): pass
>>> class X(File, FieldFile): pass
Traceback (most recent call last):
  File "<console>", line 1, in <module>
TypeError: Error when calling the metaclass bases
    Cannot create a consistent method resolution
order (MRO) for bases FieldFile, File

Specifying File first contradicts the lookup order specified by the fact that FieldFile derives from File, and Python complains. Reversing the order works:

>>> class X(FieldFile, File): pass

But I'm questioning whether this code is really the right approach to 'add the FieldFile interface' to something. Based on what's being seen in #10300 it is also having the effect of causing the FieldFile methods to be called for routines that used to get resolved via inheritance in the class being copied here, with unexpected results. That is, it isn't just adding some missing methods, but changing how some existing ones are resolved. Perhaps there is some cleaner way to just add methods, which seems to be what the comment (and possibly the order in which the bases are currently listed) implies is the intent of the code? Mucking with an object's __class__ is messing with a level of Python I'm not really comfortable with, so feedback from someone with more Python depth would be useful here.

comment:3 Changed 7 years ago by Alex

  • Triage Stage changed from Unreviewed to Accepted

comment:4 Changed 7 years ago by kmtracey

  • Description modified (diff)
  • milestone set to 1.1

Changed 7 years ago by kmtracey

comment:5 Changed 7 years ago by kmtracey

Attached a patch that fixes the MRO problem by reversing the order of the bases listed when setting file_copy's __class__.

This does introduce at least one problem that I noticed when combining this patch with the one I added to #10300. In that case the Storage backend _save() is calling With this patch, the bases for content are:

content.__class__.__bases__ is: (<class 'django.db.models.fields.files.FieldFile'>, <class 'django.core.files.uploadedfile.InMemoryUploadedFile'>)

whereas before this patch, those were reversed. Meaning before this patch, went directly to InMemoryUploadedFile's open:

    def open(self):

With this patch however, the backend's call to takes a detour through FieldFile's open:

    def open(self, mode='rb'):
        return super(FieldFile, self).open(mode)
    # open() doesn't alter the file's contents, but it does reset the pointer
    open.alters_data = True

resulting in an error since that open routine adds on a mode parameter that isn't expected nor supported by the InMemoryUploadedFile's open routine. Not sure whether the fix for this is to:

  • Add support for the mode parameter in all the various UploadedFile open methods. "Support" here would mean callers could specify it, but it would have no actual effect on anything. That seems like it might be potentially confusing, but the base django.core.files.base.File, which all of the various UploadedFile classes inherit from, does support mode on open. So it seems kinda wrong for them all to fail to support that argument in their over-riding open methods.
  • Change FieldFile's open to not insert a mode into args when the caller didn't actually specify it. Then at least you'd only get an error when some calling code actually tried to specify mode when the actual object in use didn't support it.
  • Abandon this approach to fixing the MRO problem entirely.

Anyone got a better clue than me?

comment:7 Changed 7 years ago by mitsuhiko

  • Owner changed from nobody to mitsuhiko

I assign that to myself, it's fixed in the branch of Alex and me already.

comment:8 Changed 7 years ago by jacob

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

Fixed in [10717].

comment:9 Changed 5 years ago by Marcelo_MV

  • Cc marcelo@… added; rokclimb15@… removed
  • Component changed from File uploads/storage to Database layer (models, ORM)
  • Version changed from 1.0 to 1.2-beta

Hello everyone,

I was looking on google about this error and I found this tracker. Today, I also tried to use multiple inheritance with a class used as a main class for my Django admin classes. In my case I used djago-reversion package ( class VersionAdmin? as the second class in the inheritance line. The code is as follows:

class MuchTourModelAdmin?(admin.ModelAdmin?, VersionAdmin?):

#class body

However, after restarting the django runserver and trying to access my site I got the following trace:

Traceback (most recent call last):

File "C:\Python25\Lib\site-packages\django\core\servers\", line 674, in call

return self.application(environ, start_response)

File "C:\Python25\Lib\site-packages\django\core\handlers\", line 241, in call

response = self.get_response(request)

File "C:\Python25\Lib\site-packages\django\core\handlers\", line 142, in get_response

return self.handle_uncaught_exception(request, resolver, exc_info)

File "C:\Python25\Lib\site-packages\django\core\handlers\", line 166, in handle_uncaught_exception

return debug.technical_500_response(request, *exc_info)

File "C:\Python25\Lib\site-packages\django\core\handlers\", line 80, in get_response

response = middleware_method(request)

File "C:\Python25\Lib\site-packages\django\middleware\", line 57, in process_request

if (not _is_valid_path(request.path_info, urlconf) and

File "C:\Python25\Lib\site-packages\django\middleware\", line 143, in _is_valid_path

urlresolvers.resolve(path, urlconf)

File "C:\Python25\Lib\site-packages\django\core\", line 301, in resolve

return get_resolver(urlconf).resolve(path)

File "C:\Python25\Lib\site-packages\django\core\", line 214, in resolve

for pattern in self.url_patterns:

File "C:\Python25\Lib\site-packages\django\core\", line 243, in _get_url_patterns

patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)

File "C:\Python25\Lib\site-packages\django\core\", line 238, in _get_urlconf_module

self._urlconf_module = import_module(self.urlconf_name)

File "C:\Python25\Lib\site-packages\django\utils\", line 35, in import_module


File "C:\doisxt\muchtour\djsite\", line 18, in <module>


File "C:\Python25\Lib\site-packages\django\contrib\admin\", line 24, in autodiscover

import_module('%s.admin' % app)

File "C:\Python25\Lib\site-packages\django\utils\", line 35, in import_module


File "C:\doisxt\muchtour\djsite\admin\cidade\", line 13, in <module>

from djsite.util.admin import MuchTourModelAdmin?

File "C:\doisxt\muchtour\djsite\util\", line 48, in <module>

class MuchTourModelAdmin?(admin.ModelAdmin?, VersionAdmin?):

File "C:\Python25\Lib\site-packages\django\forms\", line 127, in new


TypeError?: Error when calling the metaclass bases

Cannot create a consistent method resolution

order (MRO) for bases ModelAdmin?, VersionAdmin?

If I change the order of the inheritance line it works fine, even though I haven't tested the whole system:

class MuchTourModelAdmin?(VersionAdmin?, admin.ModelAdmin?):

#class body

Django version: Django version 1.2.1 SVN-202

Perhaps I didn't pay enought attention in some subject discussed above. Is there anything I should do? I'm a bit concerned about the possibility that this error could arise again, even changing the inheritance order.

Thanks to all. Regards.

comment:10 Changed 4 years ago by jacob

  • milestone 1.1 deleted

Milestone 1.1 deleted

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