Подтвердить что ты не робот

Пакет Cython с __init __. Pyx: Возможно?

Возможно ли создать пакет Python 2.7 с помощью __init__.pyx (скомпилирован в __init__.so)? Если да, то как? Мне не удавалось заставить его работать.

Вот что я пробовал:

  • setup.py:

    #!/usr/bin/env python
    
    from distutils.core import setup
    from distutils.extension import Extension
    from Cython.Distutils import build_ext
    
    foo = Extension(name='foo.__init__', sources=['foo/__init__.pyx'])
    bar = Extension(name='foo.bar', sources=['foo/bar.pyx'])
    
    setup(name='foo',
          packages = ['foo'],
          cmdclass={'build_ext':build_ext},
          ext_modules = [foo, bar])
    
  • foo/__init__.pyx:

    import foo.bar
    
    cpdef hello_world():
        print "hello world"
        foo.bar.blah()
    
  • foo/bar.pyx:

    cpdef blah():
        print "blah"
    

Вышеприведенное имеет следующее поведение:

$ python -c 'import foo; foo.hello_world()'
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ImportError: No module named foo

Я увидел проблему Python № 15576, которая была исправлена ​​этим Hg commit. Глядя на эквивалентный Git commit в Git зеркало в хранилище Python Hg, я вижу что фиксация достижима из тега Python v2.7.5 (а также всех последующих версий v2.7.x). Был ли регресс?

4b9b3361

Ответ 1

В соответствии с это действительно старый список рассылки он работает, если у вас также есть файл __init__.py (файл __init__.py не используется, но, похоже, необходимо, чтобы каталог обрабатывался как модуль, и, следовательно, загружаемый файл __init__.so).

Если я добавлю __init__.py:

# an exception just to confirm that the .so file is loaded instead of the .py file
raise ImportError("__init__.py loaded when __init__.so should have been loaded")

то ваш пример работает на Linux Python 2.7.3:

$ python -c 'import foo; foo.hello_world()'
hello world
blah

У этого есть все признаки багги угла, поэтому, вероятно, не рекомендуется. Обратите внимание, что в Windows это не работает для меня, давая

ImportError: DLL load failed: %1 is not a valid Win32 application.

Добавление (для небольшого дополнительного контекста):

Такое поведение явно не документировано. В оригинальном описании пакетов со времени Python 1.5 они говорят:

без __init__.py, каталог не распознается как пакет

и

Совет: порядок поиска определяется списком суффиксов, возвращаемых функцией imp.get_suffixes(). Обычно суффиксы выполняются в следующем порядке: ".so", "module.so", ".py", ".pyc". Каталоги явно не встречаются в этом списке, но предшествуют всем элементам в нем.

Наблюдаемое поведение, безусловно, согласуется с этим. __init__.py необходимо обработать каталог как пакет, но файл .so загружен в предпочтение .py file — но это вряд ли однозначно.

С точки зрения Cython это поведение, по-видимому, используется для компиляции стандартной библиотеки (в этом случае __init__.py всегда присутствовало) или в тестовых таблицах, данных https://github.com/cython/cython/blob/master/tests/build/package_compilation.srctree (и еще несколько примеров). В них файл srctree выглядит расширенным в различные папки, содержащие __init__.py (и другие файлы), а затем скомпилированные. Возможно, что только __init__.so просто не тестировалось.

Ответ 2

Попробуйте использовать относительный импорт.

в __init__:

from . import bar

Может быть также from . import foo. Не использовали python 2 cython.