Using cythonized code causing "TypeError: hasattr(): attribute name must be string"
Using cythonized code causing "TypeError: hasattr(): attribute name must be string"
我有一个 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
root/__init__.py
root/pm0/__init__.py
from .f0 import do_thing
all = [
do_thing,
]
root/pm0/f0.py
def do_thing():
print("doing thing 0")
root/pm1/__init__.py
from .f0 import subsubsub
root/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
- 适用于 运行ning
setup.py
的 Visual C++ 2015 x86 x64 交叉构建工具命令提示符(在 EDM shell 中)
问题是 __all__
是字符串列表,而不是函数列表。
如果你让它看起来像这样:
__all__ = [
'do_thing',
]
它应该可以正常工作。
我有一个 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
root/__init__.py
root/pm0/__init__.py
from .f0 import do_thing
all = [
do_thing,
]
root/pm0/f0.py
def do_thing():
print("doing thing 0")
root/pm1/__init__.py
from .f0 import subsubsub
root/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
- 适用于 运行ning
setup.py
的 Visual C++ 2015 x86 x64 交叉构建工具命令提示符(在 EDM shell 中)
问题是 __all__
是字符串列表,而不是函数列表。
如果你让它看起来像这样:
__all__ = [
'do_thing',
]
它应该可以正常工作。