Celery Tutorial在标准的iPython shell中正常工作,但在使用Django的嵌入式iPython shell时却没有

时间:2013-05-17 05:48:44

标签: python django celery django-celery django-shell

我一直在设置一个django-celery的测试实例并浏览一些基本的芹菜示例,并且遇到了一些奇怪的东西。

我首先在这里浏览了“Django的第一步”芹菜页面:http://docs.celeryproject.org/en/latest/django/first-steps-with-django.html

一切正常,标准芹菜教程的前几节中的基本示例也是如此。

python manage.py shell

一旦我开始尝试Django shell中的一些画布原语,我得到一个NameError,如下所示:

$ python manage.py shell
In [1]: from celerytest.tasks import add
In [2]: from celery import group
In [3]: group(add.s(i, i) for i in xrange(10))().get()
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
/Users/jacinda/envs/testproj/lib/python2.7/site-packages/django/core/management/commands/shell.pyc in <module>()
----> 1 group(add.s(i, i) for i in xrange(10))().get()
/Users/jacinda/envs/testproj/lib/python2.7/site-packages/celery/canvas.pyc in __call__(self, *partial_args, **options)
    397
    398     def __call__(self, *partial_args, **options):
--> 399         tasks = [task.clone() for task in self.tasks]
    400         if not tasks:
    401             return
/Users/jacinda/envs/testproj/lib/python2.7/site-packages/celery/utils/functional.pyc in __iter__(self)
    286
    287     def __iter__(self):  # needed for Python 2.5
--> 288         return iter(self.data)
/Users/jacinda/envs/testproj/lib/python2.7/site-packages/kombu/utils/__init__.pyc in __get__(self, obj, type)
    292             return obj.__dict__[self.__name__]
    293         except KeyError:
--> 294             value = obj.__dict__[self.__name__] = self.__get(obj)
    295             return value
    296
/Users/jacinda/envs/testproj/lib/python2.7/site-packages/celery/utils/functional.pyc in data(self)
    283     @cached_property
    284     def data(self):
--> 285         return list(self.__it)
    286
    287     def __iter__(self):  # needed for Python 2.5
/Users/jacinda/envs/testproj/lib/python2.7/site-packages/django/core/management/commands/shell.pyc in <genexpr>((i,))
----> 1 group(add.s(i, i) for i in xrange(10))().get()
NameError: global name 'add' is not defined

但下一行有效:

In [4]: add.delay(2,2).get()
Out[4]: 4

明确列出子任务:

In [5]: group([add.s(1,2), add.s(3,4)])().get()
Out[5]: [3, 7]

IPython的

如果我使用常规的Python shell并手动导入设置而不是使用manage.py shell,那么一切正常。即。

$ ipython
In [1]: from testproj import settings
In [2]: from celerytest.tasks import add
In [3]: from celery import group
In [4]: group(add.s(i, i) for i in xrange(10))().get()
Out[4]: [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

我看过epdb的失败案例,无法确切知道发生了什么。

我已经用Google搜索过了,我发现的唯一100%类似的引用就是芹菜的github页面上的这个问题:https://github.com/celery/celery/issues/1222。海报提到了我遇到的同样问题,但只说他的“Python / Django shell做了一些奇怪的事情”,并没有进一步阐述。关于导致这种情况的原因或是否有其他地方我应该看的任何想法?

2 个答案:

答案 0 :(得分:2)

经过大量的挖掘后,我找到了问题的根源,它实际上已经修复了Django主干(当然不是在当前的1.5版本中,这就是我正在使用的)。

事实证明,Django的shell命令会像这样启动iPython(在django / core / management / commands / shell.py中)

from IPython import embed
embed()

但是,在函数内部调用embed()会导致iPython以单独的本地和全局命名空间(iPython Github Issue 62)开始。因此lambda函数和生成器表达式(如组)失败。

为了解决这个问题,iPython提供了一种不同方式来启动没有这种副作用的shell。

from IPython.frontend.terminal.ipapp import TerminalIPythonApp
app = TerminalIPythonApp.instance()
app.initialize(argv=[])
app.start()

Diff on Django's github site

这应该会出现在即将发布的版本中(Django Issue)。我测试了这个应用于1.5.1的补丁,并且我的原始代码在应用时正常工作。

答案 1 :(得分:1)

这也发生在我身上,但仅限于使用ipython / django shell时。如果Django使用默认shell或bpython一切正常。

所以如果你现在想绕过这个问题,我建议你使用另一个shell(我使用bpython)。如果您使用的是virtualenv:

$ pip install bpython