Opened 10 years ago

Closed 10 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

Description

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 "tests.py", 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/related.py", line 825, in __get__
    through=self.field.rel.through,
  File ".tox/django1.6.2/lib/python3.4/site-packages/django/db/models/fields/related.py", 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 by Baptiste Mispelon, 10 years ago

Triage Stage: UnreviewedAccepted
Type: UncategorizedCleanup/optimization

Hi,

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.

Thanks.

comment:2 by anonymous, 10 years ago

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

comment:3 by Kevin Brown, 10 years ago

Cc: Kevin Brown added

comment:4 by linovia, 10 years ago

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.)"
https://docs.python.org/3/library/functions.html#hasattr

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 by Collin Anderson, 10 years ago

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