Opened 15 months ago

Closed 8 months 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 Changed 15 months ago by bmispelon

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Triage Stage changed from Unreviewed to Accepted
  • Type changed from Uncategorized to Cleanup/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 Changed 15 months ago by anonymous

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

comment:3 Changed 15 months ago by kevin-brown

  • Cc kevin-brown added

comment:4 Changed 15 months 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.)"
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 Changed 8 months ago by collinanderson

  • Cc cmawebsite@… added
  • Resolution set to invalid
  • Status changed from new to closed

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