commit 0fd248f8fe00c77357cab6a1c59f8368ca0fc30f Author: Lokendra Singh Date: Wed Jun 19 15:44:46 2019 +0530 Python wrapper in SWIG (#58) SWIG Python wrapper guarded by --enable-python-bindings. By Lokendra Singh diff --git a/.gitignore b/.gitignore index a849096..6353196 100644 --- a/.gitignore +++ b/.gitignore @@ -71,3 +71,11 @@ /lttoolbox/lttoolbox_config.h /lttoolbox/lt-tmxproc /lttoolbox/lt-expand +/python/Makefile +/python/Makefile.in +/python/lttoolbox_wrap.cpp +/python/lttoolbox.py +/python/setup.py +/python/build* +*.egg-info/ +*.egg diff --git a/.travis.yml b/.travis.yml index 7812f25..753e735 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,8 @@ os: compiler: - clang - gcc +before_install: + - if [ $TRAVIS_OS_NAME = linux ]; then sudo apt-get install -y swig python3-setuptools; else brew install swig; fi script: - ./autogen.sh - ./configure diff --git a/Makefile.am b/Makefile.am index 02e7cce..93b9ce2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3,6 +3,10 @@ ACLOCAL_AMFLAGS=-I m4 SUBDIRS = $(GENERIC_LIBRARY_NAME) DIST_SUBDIRS = $(GENERIC_LIBRARY_NAME) +if HAVE_PYTHON_BINDINGS +SUBDIRS += python +endif + pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = lttoolbox.pc diff --git a/configure.ac b/configure.ac index 3dfc70d..a10f9fe 100644 --- a/configure.ac +++ b/configure.ac @@ -140,6 +140,15 @@ static_assert(!is_same::value, "size_t == uint32_t"); static_assert(!is_same::value, "size_t == uint64_t"); ]])], [AC_DEFINE([SIZET_NOT_CSTDINT], [1], [size_t != (uint32_t, uint64_t)])]) -AM_PATH_PYTHON([2], [], [AC_MSG_WARN([Can't run 'make test' without Python installed.])]) +AM_PATH_PYTHON([3.4], [], [AC_MSG_WARN([Can't generate SWIG wrapper or run tests without Python])]) -AC_OUTPUT([Makefile lttoolbox.pc lttoolbox/Makefile]) +AC_CONFIG_FILES([python/setup.py]) + +AC_ARG_ENABLE([python-bindings], + AS_HELP_STRING([--enable-python-bindings], + [build python bindings (default=disabled)]), + [enable_python_bindings=$enableval], + [enable_python_bindings=no]) +AM_CONDITIONAL([HAVE_PYTHON_BINDINGS], [test x$enable_python_bindings = xyes]) + +AC_OUTPUT([Makefile lttoolbox.pc lttoolbox/Makefile python/Makefile]) diff --git a/python/Makefile.am b/python/Makefile.am new file mode 100644 index 0000000..f5f85bc --- /dev/null +++ b/python/Makefile.am @@ -0,0 +1,9 @@ +SWIG_INTERFACE = lttoolbox.i + +BUILT_SOURCES = lttoolbox_wrap.cpp lttoolbox.py + +lttoolbox_wrap.cpp: $(SWIG_INTERFACE) setup.py + $(PYTHON) setup.py build + +install-exec-local: + $(PYTHON) setup.py install diff --git a/python/lttoolbox.i b/python/lttoolbox.i new file mode 100644 index 0000000..ed1a660 --- /dev/null +++ b/python/lttoolbox.i @@ -0,0 +1,69 @@ +%module lttoolbox + +%{ +#define SWIG_FILE_WITH_INIT +#include +#include +#include +#include + +class FST: public FSTProcessor +{ +public: + /** + * Imitates functionality of lt-proc using file path + */ + void lt_proc(char arg, char *dictionary_path, char *input_path, char *output_path); +}; + + +void +FST::lt_proc(char arg, char *dictionary_path, char *input_path, char *output_path) +{ + FILE *in = fopen(dictionary_path, "rb"); + load(in); + FILE *input = fopen(input_path, "r"), *output = fopen(output_path, "w"); + switch(arg) + { + case 'g': + initGeneration(); + generation(input, output); + break; + case 'b': + initBiltrans(); + bilingual(input, output); + break; + case 'p': + initPostgeneration(); + intergeneration(input, output); + break; + case 'w': + setDictionaryCaseMode(true); + case 'a': + default: + initAnalysis(); + analysis(input, output); + break; + } + + fclose(in); + fclose(input); + fclose(output); +} + +%} + + +%include +%include +%include +%include + +class FST: public FSTProcessor +{ +public: + /** + * Imitates functionality of lt-proc using file path + */ + void lt_proc(char arg, char *dictionary_path, char *input_path, char *output_path); +}; diff --git a/python/setup.py.in b/python/setup.py.in new file mode 100644 index 0000000..3697604 --- /dev/null +++ b/python/setup.py.in @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 + +""" +Setup for SWIG Python bindings for lttoolbox +""" +from os import path +from setuptools import Extension, setup +from distutils.command.build import build + + +class CustomBuild(build): + sub_commands = [ + ('build_ext', build.has_ext_modules), + ('build_py', build.has_pure_modules), + ('build_clib', build.has_c_libraries), + ('build_scripts', build.has_scripts), + ] + + +def get_sources(): + sources = ['lttoolbox.i'] + cc_sources = ['alphabet.cc', 'compression.cc', 'fst_processor.cc', 'lt_locale.cc', + 'node.cc', 'state.cc', 'trans_exe.cc', 'xml_parse_util.cc'] + rel_path = '@top_srcdir@/lttoolbox/' + sources.extend(path.join(rel_path, f) for f in cc_sources) + return sources + +lttoolbox_module = Extension( + name='_lttoolbox', + sources=get_sources(), + swig_opts = ["-c++", "-I@top_srcdir@", "-Wall"], + include_dirs=['@top_srcdir@', '/usr/include/libxml2'], + library_dirs=['/usr/include/libxml2'], + extra_compile_args='@CXXFLAGS@'.split(), + extra_link_args=['-lxml2'], +) + +setup( + name='@PACKAGE@', + version='@PACKAGE_VERSION@', + description='SWIG interface to @PACKAGE_NAME@', + long_description="SWIG interface to @PACKAGE_NAME@ for use in apertium-python", + # TODO: author, maintainer, url + author_email='@PACKAGE_BUGREPORT@', + license='GPL-3.0+', + maintainer_email='@PACKAGE_BUGREPORT@', + cmdclass={'build': CustomBuild}, + ext_modules=[lttoolbox_module], + py_modules=['lttoolbox'], +)