Repository: celery/celery

Issue:
Django fixup appends to PYTHONPATH instead of prepending
Hi,

## Environment & Settings
**Celery version**: 4.2.1  (windowlicker)

# Steps to Reproduce

We are using Celery + Django in [dissemin](https://github.com/dissemin/dissemin/). We have a Django app named "statistics" which is actually a name conflicting with a Python 3 package from standard library. This should be fine in principle as long as the `PYTHONPATH` is set so that the local modules have precedence over the system ones.

When running Celery CLI, the system wide module has precedence over the local ones apparently.

I traced this issue back to [this `sys.path` tweak](https://github.com/celery/celery/blob/072dab85261599234341cc714b0d6f0caca20f00/celery/fixups/django.py#L60-L61), which is actually **appending** local path instead of prepending it.

I may have missed something, but is it important for some reason to append it and not prepend it in this context?

# Expected Behavior

Celery should load the local module as expected.

# Actual Behavior

```
# When going through celery CLI
sys.path == ['/Users/lverney/.local/share/virtualenvs/dissemin3/bin', '/Users/lverney/.local/share/virtualenvs/dissemin3/lib/python36.zip', '/Users/lverney/.local/share/virtualenvs/dissemin3/lib/python3.6', '/Users/lverney/.local/share/virtualenvs/dissemin3/lib/python3.6/lib-dynload', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6', '/Users/lverney/.local/share/virtualenvs/dissemin3/lib/python3.6/site-packages', '/Users/lverney/.local/share/virtualenvs/dissemin3/src/django-allauth', '/Users/lverney/tmp/dissemin']

# Without celery
sys.path == ['', '/Users/lverney/.local/share/virtualenvs/dissemin3/lib/python36.zip', '/Users/lverney/.local/share/virtualenvs/dissemin3/lib/python3.6', '/Users/lverney/.local/share/virtualenvs/dissemin3/lib/python3.6/lib-dynload', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6', '/Users/lverney/.local/share/virtualenvs/dissemin3/lib/python3.6/site-packages', '/Users/lverney/.local/share/virtualenvs/dissemin3/src/django-allauth']
```

We can see that current path is actually appended, not prepended. Therefore, "system" modules have precedence on the ones from the local project.


# Workaround

For people experiencing this issue, `PYTHONPATH=$(pwd) celery …` is a workaround.


Best,

/cc @wetneb who first noticed this issue.


Discussion:
could you come with a possible fix?
@auvipy fixing is easy - use `prepend` instead of `append`. I am more worried about the sort of testing you would expect for that kind of bug? It looks a bit hard to test to me. Happy to provide a PR otherwise.

Resolving patch:
diff --git a/celery/fixups/django.py b/celery/fixups/django.py
--- a/celery/fixups/django.py
+++ b/celery/fixups/django.py
@@ -57,8 +57,10 @@ def __init__(self, app):
         self._worker_fixup = None
 
     def install(self):
-        # Need to add project directory to path
-        sys.path.append(os.getcwd())
+        # Need to add project directory to path.
+        # The project directory has precedence over system modules,
+        # so we prepend it to the path.
+        sys.path.prepend(os.getcwd())
 
         self._settings = symbol_by_name('django.conf:settings')
         self.app.loader.now = self.now


Test patch:
diff --git a/t/unit/fixups/test_django.py b/t/unit/fixups/test_django.py
--- a/t/unit/fixups/test_django.py
+++ b/t/unit/fixups/test_django.py
@@ -91,7 +91,7 @@ def test_install(self, patching):
             f.install()
             self.sigs.worker_init.connect.assert_called_with(f.on_worker_init)
             assert self.app.loader.now == f.now
-            self.p.append.assert_called_with('/opt/vandelay')
+            self.p.prepend.assert_called_with('/opt/vandelay')
 
     def test_now(self):
         with self.fixup_context(self.app) as (f, _, _):