Code

Opened 6 years ago

Closed 2 years ago

#8740 closed Bug (invalid)

save(force_update=True) should raise a consistent exception when update is not possible

Reported by: Richard Davies <richard.davies@…> Owned by: nobody
Component: Database layer (models, ORM) Version: master
Severity: Normal Keywords:
Cc: richard.davies@… Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

At present save(force_update=True) raises different exceptions according to database backend when update is not possible. These should be unified so that calling code is not specific to the database backend, rather like IntegrityError is already. They could be unified onto IntegrityError itself or a different new error.

I attach a patch which adds an extra test, regressiontests/save_force_update. This test assumes that save(force_update=True) would raise IntegrityError. In the trace below you can see that different database backends actually each fail with different exceptions.

$ ./runtests.py --settings=sqlite save_force_update
======================================================================
FAIL: Doctest: regressiontests.save_force_update.models.__test__.API_TESTS
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/elastic/django-dev/trunk/django/test/_doctest.py", line 2180, in runTest
    raise self.failureException(self.format_failure(new.getvalue()))
AssertionError: Failed doctest test for regressiontests.save_force_update.models.__test__.API_TESTS
  File "/home/elastic/django-dev/trunk/tests/regressiontests/save_force_update/models.py", line unknown line number, in API_TESTS

----------------------------------------------------------------------
File "/home/elastic/django-dev/trunk/tests/regressiontests/save_force_update/models.py", line ?, in regressiontests.save_force_update.models.__test__.API_TESTS
Failed example:
    try:
       m = ManualPrimaryKeyTest(id=2, data='Different')
       m.save(force_update=True)
    except Exception, e:
       if isinstance(e, IntegrityError):
           print "Pass"
       else:
           print "Fail with %s" % type(e)
Expected:
    Pass
Got:
    Fail with <class 'sqlite3.DatabaseError'>


----------------------------------------------------------------------
Ran 1 test in 0.012s

FAILED (failures=1)



$ ./runtests.py --settings=postgresql_psycopg2 save_force_update
======================================================================
FAIL: Doctest: regressiontests.save_force_update.models.__test__.API_TESTS
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/elastic/django-dev/trunk/django/test/_doctest.py", line 2180, in runTest
    raise self.failureException(self.format_failure(new.getvalue()))
AssertionError: Failed doctest test for regressiontests.save_force_update.models.__test__.API_TESTS
  File "/home/elastic/django-dev/trunk/tests/regressiontests/save_force_update/models.py", line unknown line number, in API_TESTS

----------------------------------------------------------------------
File "/home/elastic/django-dev/trunk/tests/regressiontests/save_force_update/models.py", line ?, in regressiontests.save_force_update.models.__test__.API_TESTS
Failed example:
    try:
       m = ManualPrimaryKeyTest(id=2, data='Different')
       m.save(force_update=True)
    except Exception, e:
       if isinstance(e, IntegrityError):
           print "Pass"
       else:
           print "Fail with %s" % type(e)
Expected:
    Pass
Got:
    Fail with <class 'psycopg2.DatabaseError'>


----------------------------------------------------------------------
Ran 1 test in 0.067s

FAILED (failures=1)

Attachments (3)

save_force_update.diff (1.1 KB) - added by Richard Davies <richard.davies@…> 6 years ago.
Extra test case (note that the init.py must be created too)
8740_save_force_update.v2.diff (1013 bytes) - added by Richard Davies <richard.davies@…> 6 years ago.
Extra test case for force_update functionality only - can be used until we get a consistent exception
8740_r8911_save_force_update.v3.diff (821 bytes) - added by Richard Davies <richard.davies@…> 6 years ago.
Patch to modeltests/force_insert_update so that it will fail unless a consistent exception is raised

Download all attachments as: .zip

Change History (10)

Changed 6 years ago by Richard Davies <richard.davies@…>

Extra test case (note that the init.py must be created too)

comment:1 Changed 6 years ago by mtredinnick

  • milestone 1.0 deleted
  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset

Would probably be nice to do, but not critical for 1.0.

comment:2 Changed 6 years ago by mtredinnick

  • Triage Stage changed from Unreviewed to Accepted

By the way, cases where this doesn't raise an IntegrityError are arguably bugs with the particular database wrapper. We're already getting one of this fixed in cx_Oracle. Fixes should be made in the appropriate django/db/backends/ files so that IntegrityError is raised.

Changed 6 years ago by Richard Davies <richard.davies@…>

Extra test case for force_update functionality only - can be used until we get a consistent exception

comment:3 Changed 6 years ago by Richard Davies <richard.davies@…>

Forget that last attachment - turns out there's a test for force_update functionality already in modeltests/force_insert_update

Changed 6 years ago by Richard Davies <richard.davies@…>

Patch to modeltests/force_insert_update so that it will fail unless a consistent exception is raised

comment:4 Changed 3 years ago by lukeplant

  • Severity set to Normal
  • Type set to Bug

comment:5 Changed 2 years ago by aaugustin

  • UI/UX unset

Change UI/UX from NULL to False.

comment:6 Changed 2 years ago by aaugustin

  • Easy pickings unset

Change Easy pickings from NULL to False.

comment:7 Changed 2 years ago by akaariai

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

To me it seems this is no longer issue. We now check if a row was updated, if not raise a consistent error. I also tried a couple of combinations raising IntegerityErrors on PostgreSQL, and it seems these are correctly converted to django's exception types. As Malcolm said 4 years ago, if this conversion does not happen, then it is an error in the backend, not in save().

I will close this as invalid, although I am not sure if this should be resolved as "fixed" instead, as originally this wasn't invalid...

Add Comment

Modify Ticket

Change Properties
<Author field>
Action
as closed
as The resolution will be set. Next status will be 'closed'
The resolution will be deleted. Next status will be 'new'
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.