diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000000000000000000000000000000000..78609aefac4b1681829f2d8ac66fd1b778d2787d --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.mako text eol=lf diff --git a/.travis.yml b/.travis.yml index b4f040ec2ad66772a06f5a2026642f18b93278e2..a33377b7d64100817b8783e08ed4e17793263ac1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,5 +10,5 @@ script: - cd example - python setup.py test install: - - pip install Cython + - pip install Cython mako - python setup.py install diff --git a/MANIFEST.in b/MANIFEST.in index 5b2a10f6436e7e872a60783ac226cd7dd05ec924..901b33197d29e68ddd60768cfb46c6fbf0748ec8 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,4 @@ include LICENSE include README.md include CONTRIBUTORS.md -include snakehouse/*.template +include snakehouse/templates/*.mako diff --git a/setup.py b/setup.py index c797b8e32debb9395a8e70fdca578bd61348c1f3..3a0c0731896fa1aa636ee40b2d875270ede49b17 100644 --- a/setup.py +++ b/setup.py @@ -6,11 +6,11 @@ setup(keywords=['cython', 'extension', 'multiple', 'pyx'], packages=find_packages(include=['snakehouse']), version=__version__, install_requires=[ - 'Cython' + 'Cython', 'mako' ], python_requires='!=2.7.*,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*', package_data={ - 'snakehouse': ['*.template'] + 'snakehouse': ['templates/*.mako'] }, package_dir={'snakehouse': 'snakehouse'}, ) diff --git a/snakehouse/cdef.template b/snakehouse/cdef.template deleted file mode 100644 index 0ff30ea3714eb10a2926a4eb42de5bac1d5f7d22..0000000000000000000000000000000000000000 --- a/snakehouse/cdef.template +++ /dev/null @@ -1,2 +0,0 @@ -cdef extern from "%s": - object PyInit_%s() diff --git a/snakehouse/constants.py b/snakehouse/constants.py deleted file mode 100644 index ff692348da9aa90b284df34b80e519d232d9753a..0000000000000000000000000000000000000000 --- a/snakehouse/constants.py +++ /dev/null @@ -1,18 +0,0 @@ -import logging -import typing as tp - -logger = logging.getLogger(__name__) - - -BOOTSTRAP_PYX_GET_DEFINITION_IF = """ if name == %s: - return %s -""" - -BOOTSTRAP_PYX_GET_DEFINITION_ELIF = """ elif name == %s: - return %s -""" - -INCLUDE_PYTHON_H = '#include "Python.h"\n' - -INCLUDE_PYINIT = 'PyObject* PyInit_%s(void);' - diff --git a/snakehouse/initpy.template b/snakehouse/initpy.template deleted file mode 100644 index 20a09167ca8d172a4e29a7e3e5df17ba862e9f8a..0000000000000000000000000000000000000000 --- a/snakehouse/initpy.template +++ /dev/null @@ -1,2 +0,0 @@ -from {module_name}.__bootstrap__ import bootstrap_cython_submodules -bootstrap_cython_submodules() diff --git a/snakehouse/multibuild.py b/snakehouse/multibuild.py index 2cda25fbec87f0b7474c30c15985ce80d74abe94..48de6ba1c35695ac4eaa3c7f49b70b3db5800a15 100644 --- a/snakehouse/multibuild.py +++ b/snakehouse/multibuild.py @@ -1,8 +1,19 @@ import os +import collections import pkg_resources +from mako.template import Template from setuptools import Extension -from .constants import BOOTSTRAP_PYX_GET_DEFINITION_IF, \ - BOOTSTRAP_PYX_GET_DEFINITION_ELIF, INCLUDE_PYTHON_H, INCLUDE_PYINIT + +CdefSection = collections.namedtuple('CdefSection', ('h_file_name', 'module_name')) +GetDefinitionSection = collections.namedtuple('GetDefinitionSection', ( + 'module_name', 'pyinit_name' +)) + + +def render_mako(template_name: str, **kwargs) -> str: + tpl = Template(pkg_resources.resource_string( + 'snakehouse', os.path.join('templates', template_name)).decode('utf8')) + return tpl.render(**kwargs) class Multibuild: @@ -34,25 +45,21 @@ class Multibuild: module_name = name.replace('.pyx', '') h_name = name.replace('.pyx', '.h') - exported_line = INCLUDE_PYINIT % (module_name,) if os.path.exists(h_name): with open(os.path.join(path, h_name), 'r') as f_in: data = f_in.read() - if INCLUDE_PYTHON_H not in data: - data = INCLUDE_PYTHON_H+data - - if exported_line not in data: - data = data+'\n'+exported_line+'\n' + if 'PyObject* PyInit_' not in data: + data = render_mako('hfile.mako', initpy_name=module_name) + data else: - data = INCLUDE_PYTHON_H+'\n'+exported_line+'\n' + data = render_mako('hfile.mako', initpy_name=module_name) with open(os.path.join(path, h_name), 'w') as f_out: f_out.write(data) def generate_bootstrap(self) -> str: - bootstrap_contents = pkg_resources.resource_string('snakehouse', 'bootstrap.template').decode('utf8') + cdef_section = [] for filename in self.pyx_files: path, name = os.path.split(filename) @@ -64,8 +71,7 @@ class Multibuild: replace('\\', '\\\\') else: h_path_name = name.replace('.pyx', '.h') - cdef_template = pkg_resources.resource_string('snakehouse', 'cdef.template').decode('utf8') - cdef_section.append(cdef_template % (h_path_name, module_name)) + cdef_section.append(CdefSection(h_path_name, module_name)) if path: complete_module_name = self.extension_name+'.'+'.'.join(path[1:].split( @@ -73,27 +79,21 @@ class Multibuild: else: complete_module_name = self.extension_name + '.'+module_name - self.modules.add((complete_module_name, 'PyInit_%s()' % (module_name, ))) + self.modules.add((complete_module_name, module_name, )) get_definition = [] - modules = iter(self.modules) - mod_name, init_fun_name = next(modules) - get_definition.append(BOOTSTRAP_PYX_GET_DEFINITION_IF % (repr(mod_name), init_fun_name)) - for mod_name, init_fun_name in modules: - get_definition.append(BOOTSTRAP_PYX_GET_DEFINITION_ELIF % ( - repr(mod_name), init_fun_name)) + for mod_name, init_fun_name in self.modules: + get_definition.append(GetDefinitionSection(mod_name, init_fun_name)) - return bootstrap_contents.format(cdef_section=''.join(cdef_section), - get_definition_section=''.join(get_definition), - module_set=repr(set(x[0] for x in self.modules))) + return render_mako('bootstrap.mako', cdef_sections=cdef_section, + get_definition_sections=get_definition, + module_set=repr(set(x[0] for x in self.modules))) def write_bootstrap_file(self): with open(os.path.join(self.bootstrap_directory, '__bootstrap__.pyx'), 'w') as f_out: f_out.write(self.generate_bootstrap()) def alter_init(self): - pyinit_contents = pkg_resources.resource_string('snakehouse', 'initpy.template').decode('utf8') - if os.path.exists(os.path.join(self.bootstrap_directory, '__init__.py')): with open(os.path.join(self.bootstrap_directory, '__init__.py'), 'r') as f_in: data = f_in.read() @@ -101,7 +101,7 @@ class Multibuild: data = '' if 'bootstrap_cython_submodules' not in data: - data = pyinit_contents.format(module_name=self.extension_name) + data + data = render_mako('initpy.mako', module_name=self.extension_name) + data with open(os.path.join(self.bootstrap_directory, '__init__.py'), 'w') as f_out: f_out.write(data) diff --git a/snakehouse/bootstrap.template b/snakehouse/templates/bootstrap.mako similarity index 73% rename from snakehouse/bootstrap.template rename to snakehouse/templates/bootstrap.mako index 2df11b8002e94239c572027e5fd049272a25e79c..508cb0f70e04988ebced27ff1facd0b58675bf0f 100644 --- a/snakehouse/bootstrap.template +++ b/snakehouse/templates/bootstrap.mako @@ -6,10 +6,21 @@ cdef extern from "Python.h": object PyModule_FromDefAndSpec(PyModuleDef *definition, object spec) int PyModule_ExecDef(object module, PyModuleDef* definition) -{cdef_section} +% for cdef_section in cdef_sections: +cdef extern from "${cdef_section.h_file_name}": + object PyInit_${cdef_section.module_name}() +% endfor cdef object get_definition_by_name(str name): -{get_definition_section} +% for i, getdef_section in enumerate(get_definition_sections): +% if i == 0: + if name == "${getdef_section.module_name}": + return PyInit_${getdef_section.pyinit_name}() +% else: + elif name == "${getdef_section.module_name}": + return PyInit_${getdef_section.pyinit_name}() +% endif +% endfor import sys @@ -49,5 +60,5 @@ class CythonPackageMetaPathFinder: pass def bootstrap_cython_submodules(): - modules_set = {module_set} + modules_set = ${module_set} sys.meta_path.append(CythonPackageMetaPathFinder(modules_set)) diff --git a/snakehouse/templates/hfile.mako b/snakehouse/templates/hfile.mako new file mode 100644 index 0000000000000000000000000000000000000000..aee3bff7ad1e6aa6077af0a70b8baae8425b3587 --- /dev/null +++ b/snakehouse/templates/hfile.mako @@ -0,0 +1,3 @@ +#include "Python.h" + +PyObject* PyInit_${initpy_name}(void); diff --git a/snakehouse/templates/initpy.mako b/snakehouse/templates/initpy.mako new file mode 100644 index 0000000000000000000000000000000000000000..020fe76eeae514935ba3395ee559fa37bda17d8c --- /dev/null +++ b/snakehouse/templates/initpy.mako @@ -0,0 +1,2 @@ +from ${module_name}.__bootstrap__ import bootstrap_cython_submodules +bootstrap_cython_submodules()