Opened 4 years ago

Closed 3 years ago

#22839 closed Cleanup/optimization (invalid)

Many to many hasattr check fails with python 3

Reported by: web-chib@… Owned by: nobody
Component: Database layer (models, ORM) Version: 1.6
Severity: Normal Keywords:
Cc: Kevin Brown, cmawebsite@… Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no


Example model:

class CommentModel(models.Model):
    users_liked = models.ManyToManyField(UserModel, blank=True, null=True)
    text = models.CharField(max_length=200)

With python 2 it's ok:

hasattr(CommentModel(text='hello'), 'users_liked')  # => True

With python 3 it fails:

hasattr(CommentModel(text='hello'), 'users_liked')

Traceback (most recent call last):
  File "", line 33, in test_should_use_default_saving_without_partial
    hasattr(CommentModel(text='hello'), 'users_liked')
  File ".tox/django1.6.2/lib/python3.4/site-packages/django/db/models/fields/", line 825, in __get__
  File ".tox/django1.6.2/lib/python3.4/site-packages/django/db/models/fields/", line 522, in __init__
    (instance, source_field_name))
ValueError: "<CommentModel: CommentModel object>" needs to have a value for field "commentmodel" before this many-to-many relationship can be used.

As i understood ValueError is caught somewhere in python 2, but not caught in python 3.

Change History (5)

comment:1 Changed 4 years ago by Baptiste Mispelon

Triage Stage: UnreviewedAccepted
Type: UncategorizedCleanup/optimization


I tried your example and while I get the same error on Python 3, I get a different result on Python 2 (`
hasattr(CommentModel(text='hello'), 'users_liked')` is False for me).

I'll mark this as accepted on the basis that there shouldn't be an inconsistency between Python 2 and 3 but I'm not sure which of the outcomes is the correct one.


comment:2 Changed 4 years ago by anonymous

Sorry, it return False, as you wrote, because it's descriptor binded to the class.

comment:3 Changed 4 years ago by Kevin Brown

Cc: Kevin Brown added

comment:4 Changed 4 years ago by linovia

This is the expected behavior for hasattr in Python 3:
"The arguments are an object and a string. The result is True if the string is the name of one of the object’s attributes, False if not. (This is implemented by calling getattr(object, name) and seeing whether it raises an AttributeError or not.)"

While in Python 2 hasatttr would return false on any exception, not just AttributeError.

I've been bitten by this while porting Raven to python3.

comment:5 Changed 3 years ago by Collin Anderson

Cc: cmawebsite@… added
Resolution: invalid
Status: newclosed

As linovia said, hasattr returns False on all exceptions on python 2, and only returns False on AttributeError on python 3. Feel free to reopen if that isn't the issue.

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