Dynamically importing a module in a Celery task
<p>Is it possible to dynamically import a module in a Celery task?</p>

<p>For example, I have a module called <code>hello.py</code> in my working directory:</p>

<pre><code>$ cat hello.py 
def run():
    print('hello world')
</code></pre>

<p>I can import it dynamically with <code>importlib</code>:</p>

<pre><code>$ python3
Python 3.5.2 (default, Jul  5 2016, 12:43:10) 
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
&gt;&gt;&gt; import importlib
&gt;&gt;&gt; p = importlib.import_module('hello')
&gt;&gt;&gt; p.run()
hello world
</code></pre>

<p>I want to do the same as above from a Celery task:</p>

<pre><code>@celery.task()
def exec_module(module, args={}):
    print('celery task running: %s' % (module))
    print(args)
    print(os.getcwd())
    print(os.listdir())

    module = importlib.import_module('hello')
    module.run()
</code></pre>

<p>I get the following error when the task runs:</p>

<pre><code>[2016-09-11 17:51:48,132: WARNING/MainProcess] celery@user-HP-EliteBook-840-G2 ready.
[2016-09-11 17:52:05,516: INFO/MainProcess] Received task: web.tasks.exec_module[f24e3d03-5a17-41dc-afa9-541c99b60a35]
[2016-09-11 17:52:05,518: WARNING/Worker-1] celery task running: example_module
[2016-09-11 17:52:05,518: WARNING/Worker-1] {'example_file': '/tmp/tmpo4ks9ql0.xml', 'example_string': 'asd'}
[2016-09-11 17:52:05,518: WARNING/Worker-1] /home/user/Learning/vision-boilerplate
[2016-09-11 17:52:05,518: WARNING/Worker-1] ['run.py', 'requirements.txt', 'gulpfile.js', 'tsconfig.json', 'typings.json', 'package.json', 'vision_modules', 'typings', 'web', 'config', 'hello.py', 'docker-compose.yml', 'ng', 'node_modules', 'Dockerfile']
[2016-09-11 17:52:05,523: ERROR/MainProcess] Task web.tasks.exec_module[f24e3d03-5a17-41dc-afa9-541c99b60a35] raised unexpected: ImportError("No module named 'hello'",)
Traceback (most recent call last):
  File "/usr/local/lib/python3.5/dist-packages/celery/app/trace.py", line 240, in trace_task
    R = retval = fun(*args, **kwargs)
  File "/home/user/Learning/vision-boilerplate/web/__init__.py", line 21, in __call__
    return TaskBase.__call__(self, *args, **kwargs)
  File "/usr/local/lib/python3.5/dist-packages/celery/app/trace.py", line 438, in __protected_call__
    return self.run(*args, **kwargs)
  File "/home/user/Learning/vision-boilerplate/web/tasks.py", line 19, in exec_module
    module = importlib.import_module('hello')
  File "/usr/lib/python3.5/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "&lt;frozen importlib._bootstrap&gt;", line 986, in _gcd_import
  File "&lt;frozen importlib._bootstrap&gt;", line 969, in _find_and_load
  File "&lt;frozen importlib._bootstrap&gt;", line 956, in _find_and_load_unlocked
ImportError: No module named 'hello'
</code></pre>

<p>Note from the output of <code>print(os.listdir())</code> (line 6 in the debug output above) that we are definitely in the correct directory and <code>hello.py</code> is right there.</p>

<p><strong>Is it possible to dynamically import a module from within a Celery task?</strong></p>

<p>Is it possible to dynamically import a module in a Celery task?</p>

<p>Yes. Because I have done it.
When the module is single and not belong to any package, you should add the directory of the module to the sys path.</p>

<blockquote>
  <p>sys.path.append('path of the module')</p>
</blockquote>

<p>For example:</p>

<pre><code>import importlib
import os
import sys
import celery
from demo import celeryconfig

# add your path to the sys path
sys.path.append(os.getcwd())

app = celery.Celery('tasks',)
app.config_from_object(celeryconfig)


@celery.task()
def exec_module(module, args={}):
    print('celery task running: %s' % (module))
    print(args)
    print(os.getcwd())
    print(os.listdir())

    module = importlib.import_module('hello')
    module.run()
</code></pre>

<p>I hope it will be helpful for you. Thanks</p>

python celery python-importlib