﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
29226	@modify_settings append/remove/prepend is affected by dictionary order	Manuel Kaufmann	benjaoming	"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"	Bug	closed	Testing framework	2.0	Normal	fixed	tests, modify_settings	humitos@…	Accepted	1	0	0	1	0	0
