#29226: @modify_settings append/remove/prepend is affected by dictionary order
-------------------------------------+-------------------------------------
               Reporter:  Manuel     |          Owner:  nobody
  Kaufmann                           |
                   Type:             |         Status:  new
  Uncategorized                      |
              Component:  Testing    |        Version:  2.0
  framework                          |       Keywords:  tests,
               Severity:  Normal     |  modify_settings
           Triage Stage:             |      Has patch:  0
  Unreviewed                         |
    Needs documentation:  0          |    Needs tests:  0
Patch needs improvement:  0          |  Easy pickings:  0
                  UI/UX:  0          |
-------------------------------------+-------------------------------------
 I found a weird behaviour when using `@modify_settings` with `append` and
 `remove` at the same time for the same elements. I used this because I
 needed to modify the order of the MIDDLEWARES classes: inject a middleware
 before one that it's already defined in that seeing. To do that, it's
 needed to remove all the middleware after that one (including it) and the
 re-add them by prepending your own.

 Example:


 {{{
 # Original settings
 MIDDLEWARES = [
     '1',
     '2',
     '3',
     '4',
     '5',
 ]
 }}}

 and I need this:

 {{{
 # Expected settings
 MIDDLEWARES = [
     '1',
     '2',
     '3',
     'MyOwnMiddlewareHere',
     '4',
     '5',
 ]
 }}}

 I would use `@modify_settings` in this way:

 {{{
 @modify_settings(MIDDLEWARES={
     'append': [
         'MyOwnMiddlewareHere',
         '4',
         '5',
     ],
     'remove': [
         '4',
         '5',
     ],
 })
 class FooBarTest(TestCase):
     ....
 }}}

 This cause different behaviours depending on the Python version we are
 using:

 * Python < 3.6 this will randmly works since it could
    - first remove and then append the items: this will produce the
 expected result
    - first append and then remove the items: this won't produce the
 expected result
 * Python >= 3.6 this will always produce the enexpected result because 3.6
 has "insertion ordering" and append will be applied first all the times
    - we can change this behaviour in 3.6 by putting the remove key first,
 and it will always produce the expected result.

 NOTE: other Python implementation (not CPython) will also experiment this
 problem depending on their implementation.

 I fixed this in my own code by using `collections.OrderedDict` but I think
 this should be at least mentioned in the documentation to avoid other
 people having this issue. Otherwise, it could require an OrderedDict.

 I wrote some tests that I'm attaching the patch with some comments and
 explanations on why this is happening. I'm running the tests like this:
 `tox -e py35,py36 -- tests.settings_tests.tests`

 NOTE: this affects multiple versions of Django

-- 
Ticket URL: <https://code.djangoproject.com/ticket/29226>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/050.07391979b03bbc93dae8711bd0c0ba48%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to