приложение py2app’ed работает должным образом в режиме псевдонима, но не в комплекте

#python #py2exe #monkeypatching #gevent #py2app

#python #py2exe #исправление ошибок #gevent #py2app

Вопрос:

У меня есть приложение pyobjc, работающее только в 32-разрядной сборке python, которая использует библиотеку gevent. Все отлично работает в режиме псевдонима py2app’ed, но как только я создаю пакет приложений, модуль gevent не может найти библиотеку httplib, даже если она была включена в каталог пакетов сайта.

 File "gevent/monkey.pyo", line 182, in patch_httplib
File "gevent/httplib.pyo", line 8, in <module>
ImportError: No module named httplib
  

Я попытался импортировать false, как было предложено (даже если модуль, похоже, был упакован), но безрезультатно. Он может найти модуль gevent.httplib, но не модуль, который он должен исправлять. может ли это быть проблемой с функцией исправления обезьяны?

РЕДАКТИРОВАТЬ: похоже, что find_module не работает должным образом с моим пакетом py2app. Есть ли обходной путь для этого? Я не думаю, что это проблема с точечными модулями, поскольку httplib не является точечным (это часть основных библиотек python)

РЕДАКТИРОВАТЬ 2: так что это определенно imp.find_module. Использование import(‘httplib’) вместо load_module исправляет это, но мне пришлось удалить ссылку на ‘httplib’ в sys.modules, потому что он не может обезьянничать, если он уже загружен. Я не думаю, что это правильный способ сделать это, хотя встроенный пакет приложений работает должным образом (httplib теперь исправлен и позволяет инициализировать с помощью HTTPSConnection). Есть ли какой-либо обходной путь / исправление этой проблемы py2app?

Ответ №1:

Это немного сложно и требует еще большего количества исправлений, но, безусловно, решаемо:

 def main():

    # Patch the imp standard library module to fix an incompatibility between
    # py2app and gevent.httplib while running a py2app build on Mac OS-X.
    # This patch must be executed before applying gevent's monkey patching.
    if getattr(sys, 'frozen', None) == 'macosx_app':

        import imp, httplib

        original_load_module = imp.load_module
        original_find_module = imp.find_module

        def custom_load_module(name, file, pathname, description):
            if name == '__httplib__':
                return httplib
            return original_load_module(name, file, pathname, description)

        def custom_find_module(name, path=None):
            if name == 'httplib':
                return (None, None, None)
            return original_find_module(name, path)

        imp.load_module = custom_load_module
        imp.find_module = custom_find_module

        # Verify that the patch is working properly (you can remove these lines safely)
        __httplib__ = imp.load_module('__httplib__', *imp.find_module('httplib'))
        assert __httplib__ is httplib

        # Your application here

if __name__ == '__main__':
    main()
  

Это решение сложнее, чем простое изменение gevent.httplib , но, по крайней мере, работает со стандартным дистрибутивом gevent 0.13. Я еще не пробовал это с недавно выпущенными альфа-версиями gevent 1.0.

Комментарии:

1. Еще один комментарий к моему решению: было бы намного лучше выяснить, почему imp.find_module в этом случае не работает. Я предполагаю, что py2app понадобится новый рецепт, но это только предположение. Есть идеи по этому поводу?

2. Вышеупомянутый взлом также требуется в Windows, по крайней мере, с gevent 0.13.7, Python 2.6.