Использование цитонизированного кода, вызывающего «TypeError: hasattr (): имя атрибута должно быть строкой» - PullRequest
0 голосов
/ 17 января 2019

У меня есть проект Python, который я хотел бы скомпилировать с использованием Cython. После запуска сценария установки я пытаюсь запустить test.py и получаю следующую ошибку:

Traceback (most recent call last):
  File "test.py", line 1, in <module>
    from root.pm1 import subsubsub as method
  File "C:\parent_path\root\pm1\__init__.py", line 1, in <module>
    from .f0 import subsubsub
  File "root\pm1\f0.py", line 1, in init root.pm1.f0
    import root.pm0 as runner
  File "<frozen importlib._bootstrap>", line 1006, in _handle_fromlist
TypeError: hasattr(): attribute name must be string

Когда я использую вторую строку root\pm1\f1.py вместо первой, тестовый скрипт работает как положено.

Мне не повезло с изменением language_level в директивах компилятора, и я не уверен, в чем проблема. Я что-то делаю неправильно? Если нет, то есть ли способ для меня скомпилировать код, чтобы я мог использовать первый тип импорта вместо второго?

Следующий код также можно найти по адресу: https://github.com/bpolinsky/example



Структура проекта:

setup.py
test.py
root
  L __init__.py
  L pm0
     L __init__.py
     L f0.py
  L pm1
     L __init__.py
     L f0.py

корень / __ __ INIT. Ру


корень / PM0 / __ __ INIT. Ру

from .f0 import do_thing

all = [
    do_thing,
]

корень / PM0 / f0.py

def do_thing():
    print("doing thing 0")

корень / pm1 / __ __ INIT. Ру

from .f0 import subsubsub

корень / pm1 / f0.py

import root.pm0 as runner
#import root.pm0.f0 as runner  # This one works!!

def subsubsub():
    runner.do_thing()

setup.py

from distutils.core import setup
from distutils.extension import Extension
import os
import sys

from Cython.Build import cythonize
from Cython.Distutils import build_ext
from Cython.Compiler import Options

Options.emit_code_commments = False
Options.generate_cleanup_code = True


TOP_DIR = "root"
NAME = "root"
PACKAGES = [
"root",
]
INCLUDE = []

file_ending = ".py"
COMPILE_ARGS = ["-O3", "-Wall"]
LINK_ARGS = ["-g"]


def get_extensions(directory):
    extensions = list()

    for f in os.listdir(directory):
        path = os.path.join(directory, f)
        if os.path.isfile(path) and path.endswith(file_ending):
            path_split = os.path.split(path)

            ext_name = path_split[0].replace(os.path.sep, ".")

            module_name = path_split[1][:-len(file_ending)]
            if module_name != "__init__":
                ext_name += "." + str(module_name)


            extensions.append(
                Extension(
                    ext_name,
                    [
                        path,
                    ],
                    include_dirs=[
                        ".",
                    ],
                    extra_compile_args=COMPILE_ARGS,
                    extra_link_args=LINK_ARGS,
                )
            )
        elif os.path.isdir(path):
            extensions.extend(get_extensions(path))

    return extensions


# Build Extension objects
extensions = get_extensions(TOP_DIR)

# Do setup
setup(
    name=NAME,
    packages=PACKAGES,
    ext_modules=cythonize(
        extensions,
        compiler_directives={
            "language_level": "3",
        },
    ),
    include_dirs=INCLUDE,
    cmdclass={
        "build_ext": build_ext,
    },
)

test.py

from root.pm1 import subsubsub as method

method()

Дополнительная информация:

  • Python 3.6.0 (менеджер развертывания Enthought)
  • Windows 10
  • Cython версия 0.28.5
  • Командная строка инструментов кросс-сборки Visual C ++ 2015 x86 x64 (в оболочке EDM) для запуска setup.py

1 Ответ

0 голосов
/ 18 января 2019

Проблема в том, что __all__ - это список строк, а не список функций.

Если вы сделаете так, как это выглядит:

__all__ = [
    'do_thing',
]

Это должно работать нормально.

...