From 4e5c0131cf1d558e1b45467ea0a417a0f3570f15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Ma=C5=9Blanka?= <piotr.maslanka@henrietta.com.pl> Date: Wed, 18 Mar 2020 21:36:39 +0100 Subject: [PATCH] Feature/mako (#4) * try to use mako * install mako on Travis as well * try to use mako * try to use mako * render using mako * use mako --- .gitattributes | 1 + .travis.yml | 2 +- MANIFEST.in | 2 +- setup.py | 4 +- snakehouse/cdef.template | 2 - snakehouse/constants.py | 18 ------- snakehouse/initpy.template | 2 - snakehouse/multibuild.py | 50 +++++++++---------- .../bootstrap.mako} | 17 +++++-- snakehouse/templates/hfile.mako | 3 ++ snakehouse/templates/initpy.mako | 2 + 11 files changed, 49 insertions(+), 54 deletions(-) create mode 100644 .gitattributes delete mode 100644 snakehouse/cdef.template delete mode 100644 snakehouse/constants.py delete mode 100644 snakehouse/initpy.template rename snakehouse/{bootstrap.template => templates/bootstrap.mako} (73%) create mode 100644 snakehouse/templates/hfile.mako create mode 100644 snakehouse/templates/initpy.mako diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..78609ae --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.mako text eol=lf diff --git a/.travis.yml b/.travis.yml index b4f040e..a33377b 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 5b2a10f..901b331 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 c797b8e..3a0c073 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 0ff30ea..0000000 --- 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 ff69234..0000000 --- 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 20a0916..0000000 --- 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 2cda25f..48de6ba 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 2df11b8..508cb0f 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 0000000..aee3bff --- /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 0000000..020fe76 --- /dev/null +++ b/snakehouse/templates/initpy.mako @@ -0,0 +1,2 @@ +from ${module_name}.__bootstrap__ import bootstrap_cython_submodules +bootstrap_cython_submodules() -- GitLab