diff --git a/.gitignore b/.gitignore index 891d71d..6e4090b 100644 --- a/.gitignore +++ b/.gitignore @@ -54,3 +54,9 @@ docs/_build/ # Cython-generated hunspell.c* + +# Downloaded content +external +libs/gcc +libs/unix +libs/tmp diff --git a/README.md b/README.md index 507f54a..aa2099b 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,6 @@ cython to link between the C++ and Python code, with some additional features. T library will cache any corrections, you can use persistent caching by adding the `use_disk_cache` argument to a Hunspell constructor, otherwise it uses in-memory caching. -NOTE: This repository only works on Unix environments until pthreads can be replicated with an -mthread implementaiton. - ## Dependencies cacheman -- for persistent caching @@ -33,8 +30,6 @@ All unit tests for the repo. * Object Oriented (with a few exceptions) ## TODO -* Add mthreads alongside pthreads for bulk operations -* Fix blocking issues for Windows usage (see above) * Remove cacheman dependency ## Author diff --git a/find_library.py b/find_library.py index d1949ef..c1a62b3 100644 --- a/find_library.py +++ b/find_library.py @@ -7,6 +7,16 @@ import platform import re import commands +import sys +import shutil +from subprocess import check_call +from tar_download import download_and_extract + +if __name__ == '__main__': + download_and_extract('http://downloads.sourceforge.net/hunspell/hunspell-1.3.3.tar.gz', 'external') + +def get_architecture(): + return 'x64' if sys.maxsize > 2**32 else 'x86' def form_possible_names(lib, exts): ret = [] @@ -27,9 +37,10 @@ def do_search(paths, names=[], test_fn=None): for filepath in globbed: if test_fn: if test_fn(filepath): - return filepath + return filepath, pn elif os.path.exists(filepath): - return filepath + return filepath, pn + return None, None def is_library(filepath, acceptable_exts): # TODO - This is broken for ".dll.a" @@ -39,13 +50,17 @@ def is_header(filepath): return os.path.isfile(filepath) def include_dirs(): - # TODO - Windows? dirs = [ - os.path.abspath(os.curdir), - "/usr/local/include", - "/opt/include", - "/usr/include", + os.path.abspath(os.path.join(os.curdir, 'hunspell')), + # Download path for windows if missing + os.path.abspath(os.path.join(os.curdir, 'external', 'hunspell-1.3.3', 'src')), ] + if platform.system() != 'Windows': + dirs.extend([ + '/usr/local/include', + '/opt/include', + '/usr/include' + ]) return [path for path in dirs if os.path.isdir(path)] def library_dirs(): @@ -57,11 +72,14 @@ def library_dirs(): os.path.join(os.environ.get('SystemRoot'), 'system'), os.path.join(os.environ.get('SystemRoot'), 'system32'), os.environ.get('SystemRoot'), + # Built binaries home + os.path.join(os.path.dirname(__file__), 'libs', 'msvc') ]) dirs.extend(list(set(os.environ.get('PATH').split(os.path.pathsep)))) dirs = [os.path.abspath(path) for path in dirs] else: dirs.extend([ + os.path.join(os.path.dirname(__file__), 'libs', 'unix'), '/usr/local/lib64', '/usr/local/lib', '/usr/local/libdata', @@ -90,25 +108,73 @@ def get_library_path(lib): if platform.system() == 'Windows': acceptable_exts = [ '', - '.dll', - '.dll.a' + '.lib' ] elif platform.system() == 'Darwin': acceptable_exts.append('.dylib') names = form_possible_names(lib, acceptable_exts) - - return do_search(paths, names, lambda filepath: is_library(filepath, acceptable_exts)) + found_lib, found_path = do_search(paths, names, lambda filepath: is_library(filepath, acceptable_exts)) + if found_lib and platform.system() == 'Windows': + found_lib = os.path.splitext(found_lib)[0] + return found_lib, found_path def get_library_linker_name(lib): - lib_path = get_library_path('hunspell') - if lib_path: - return re.sub(r'^lib|.dylib$|.so$|.dll$|.dll.a$|.a$', '', lib_path.split(os.path.sep)[-1]) + found_lib, found_path = get_library_path(lib) + if not found_lib: + # Try x86 or x64 + found_lib, found_path = get_library_path(lib + get_architecture()) + + if found_lib: + found_lib = re.sub(r'.dylib$|.so$|.dll$|.dll.a$|.a$', '', found_lib.split(os.path.sep)[-1]) + if platform.system() != 'Windows': + found_lib = re.sub(r'^lib|', '', found_lib) + + return found_lib, found_path + +def package_found(package, include_dirs): + for idir in include_dirs: + package_path = os.path.join(idir, package) + if os.path.exists(package_path) and os.access(package_path, os.R_OK): + return True + return False + +def build_package(package, directory): + tmp_lib_path = os.path.abspath(os.path.join(os.path.dirname(__file__), 'libs', 'tmp')) + if not os.path.exists(tmp_lib_path): + os.makedirs(tmp_lib_path) + + olddir = os.getcwd() + try: + os.chdir(directory) + check_call(['./configure', '--prefix='+tmp_lib_path]) + check_call('make') + check_call(['make', 'install']) + finally: + os.chdir(olddir) + + lib_path = os.path.abspath(os.path.join(os.path.dirname(__file__), 'libs', 'unix')) + if not os.path.exists(lib_path): + os.makedirs(lib_path) + + if package == 'hunspell': + shutil.copyfile( + os.path.join(tmp_lib_path, 'lib', 'libhunspell-1.3.so.0.0.0'), + os.path.join(lib_path, 'libhunspell.so')) + shutil.rmtree(tmp_lib_path) + +def append_links(pkg, kw): + linker_name, linker_path = get_library_linker_name(pkg) + if linker_name: + kw['libraries'].append(linker_name) + if linker_path: + kw['library_dirs'].append(linker_path) + return linker_name def pkgconfig(*packages, **kw): try: flag_map = {'-I': 'include_dirs', '-L': 'library_dirs', '-l': 'libraries'} - status, response = commands.getstatusoutput("pkg-config --libs --cflags %s" % ' '.join(packages)) + status, response = commands.getstatusoutput("pkg-config --libs --cflags {}".format(' '.join(packages))) if status != 0: raise Exception(response) for token in response.split(): @@ -122,14 +188,20 @@ def pkgconfig(*packages, **kw): kw['extra_link_args'] = list(set(kw['extra_link_args'])) except: kw['include_dirs'] = include_dirs() - kw['library_dirs'] = library_dirs() - libraries = [get_library_linker_name(pkg) for pkg in packages] - try: - while True: - libraries.remove(None) - except ValueError: - pass - - kw['libraries'] = libraries + kw['library_dirs'] = [] + kw['libraries'] = [] + + if 'hunspell' in packages and not package_found('hunspell', kw['include_dirs']): + # Prepare for hunspell if it's missing + download_and_extract('http://downloads.sourceforge.net/hunspell/hunspell-1.3.3.tar.gz', 'external') + + for pkg in packages: + if not append_links(pkg, kw): + if pkg == 'hunspell' and platform.system() != 'Windows': + build_package(pkg, os.path.join('external', 'hunspell-1.3.3')) + if not append_links(pkg, kw): + print "Couldn't find lib dependency after building: {}".format(pkg) + else: + print "Couldn't find lib dependency: {}".format(pkg) return kw diff --git a/hunspell/hunspell.pxd b/hunspell/hunspell.pxd index c99ab56..616daba 100644 --- a/hunspell/hunspell.pxd +++ b/hunspell/hunspell.pxd @@ -1,9 +1,9 @@ cdef extern from "hunspell/hunspell.hxx": cdef cppclass Hunspell: - Hunspell(const char *affpath, const char *dpath, const char *key = NULL) + Hunspell(const char *affpath, const char *dpath, const char *key = NULL) nogil # load extra dictionaries (only dic files) - int add_dic(const char * dpath, const char * key = NULL) + int add_dic(const char * dpath, const char * key = NULL) nogil # spell(word) - spellcheck word # output: 0 = bad word, not 0 = good word @@ -14,7 +14,7 @@ cdef extern from "hunspell/hunspell.hxx": # SPELL_FORBIDDEN = an explicit forbidden word # root: root (stem), when input is a word with affix(es) - bint spell(const char * word, int * info = NULL, char ** root = NULL) + bint spell(const char * word, int * info = NULL, char ** root = NULL) nogil # suggest(suggestions, word) - search suggestions # input: pointer to an array of strings pointer and the (bad) word @@ -23,23 +23,23 @@ cdef extern from "hunspell/hunspell.hxx": # a newly allocated array of strings (*slts will be NULL when number # of suggestion equals 0.) - int suggest(char*** slst, const char * word) + int suggest(char*** slst, const char * word) nogil # deallocate suggestion lists - void free_list(char *** slst, int n) + void free_list(char *** slst, int n) nogil - char * get_dic_encoding() + char * get_dic_encoding() nogil # morphological functions # analyze(result, word) - morphological analysis of the word - int analyze(char*** slst, const char * word) + int analyze(char*** slst, const char * word) nogil # stem(result, word) - stemmer function - int stem(char*** slst, const char * word) + int stem(char*** slst, const char * word) nogil # stem(result, analysis, n) - get stems from a morph. analysis # example: @@ -47,11 +47,11 @@ cdef extern from "hunspell/hunspell.hxx": # int n1 = analyze(&result, "words"); # int n2 = stem(&result2, result, n1); - int stem(char*** slst, char ** morph, int n) + int stem(char*** slst, char ** morph, int n) nogil # generate(result, word, word2) - morphological generation by example(s) - int generate(char*** slst, const char * word, const char * word2) + int generate(char*** slst, const char * word, const char * word2) nogil # generate(result, word, desc, n) - generation by morph. description(s) # example: @@ -60,7 +60,7 @@ cdef extern from "hunspell/hunspell.hxx": # int n = generate(&result, "word", &affix, 1); # for (int i = 0; i < n; i++) printf("%s\n", result[i]); - int generate(char*** slst, const char * word, char ** desc, int n) + int generate(char*** slst, const char * word, char ** desc, int n) nogil # # functions for run-time modification of the dictionary @@ -68,14 +68,14 @@ cdef extern from "hunspell/hunspell.hxx": # add word to the run-time dictionary - int add(const char * word) + int add(const char * word) nogil # add word to the run-time dictionary with affix flags of # the example (a dictionary word): Hunspell will recognize # affixed forms of the new word, too. - int add_with_affix(const char * word, const char * example) + int add_with_affix(const char * word, const char * example) nogil # remove word from the run-time dictionary - int remove(const char * word) + int remove(const char * word) nogil diff --git a/hunspell/hunspell.pyx b/hunspell/hunspell.pyx index 2350b68..33efb2f 100644 --- a/hunspell/hunspell.pyx +++ b/hunspell/hunspell.pyx @@ -9,7 +9,7 @@ from libc.stdio cimport * from cython.operator cimport dereference as deref # Use full path for cimport ONLY! -from hunspell.pthread cimport * +from hunspell.thread cimport * #////////////////////////////////////////////////////////////////////////////// # General Utilities @@ -80,7 +80,7 @@ cdef struct ThreadWorkerArgs: # Thread Worker Functions #////////////////////////////////////////////////////////////////////////////// -cdef void *hunspell_suggest_worker(void *argument): +cdef void *hunspell_suggest_worker(void *argument) nogil: cdef ThreadWorkerArgs args cdef int i args = deref(argument) @@ -90,7 +90,7 @@ cdef void *hunspell_suggest_worker(void *argument): return NULL -cdef void *hunspell_stem_worker(void *argument): +cdef void *hunspell_stem_worker(void *argument) nogil: cdef ThreadWorkerArgs args cdef int i args = deref(argument) @@ -249,13 +249,11 @@ cdef class HunspellWrap(object): # C realm thread dispatcher # cdef int _c_bulk_action(self, basestring action, char **word_array, char ***output_array, int n_words, int *output_counts) except +: - cdef pthread_t *threads - cdef ThreadWorkerArgs *thread_args + # Allocate all memory per thread + cdef thread_t **threads = calloc(self.n_cpus, sizeof(thread_t *)) + cdef ThreadWorkerArgs *thread_args = calloc(self.n_cpus, sizeof(ThreadWorkerArgs)) cdef int rc, i, stride - # Allocate all memory per thread - thread_args = calloc(self.n_cpus, sizeof(ThreadWorkerArgs)) - threads = calloc(self.n_cpus, sizeof(pthread_t)) if thread_args is NULL or threads is NULL: raise MemoryError() @@ -288,18 +286,18 @@ cdef class HunspellWrap(object): # Create thread if action == "stem": - rc = pthread_create(&threads[i], NULL, hunspell_stem_worker, &thread_args[i]) + threads[i] = thread_create(&hunspell_stem_worker, &thread_args[i]) else: # suggest - rc = pthread_create(&threads[i], NULL, hunspell_suggest_worker, &thread_args[i]) - if rc: - raise OSError(rc, "Could not create pthread") + threads[i] = thread_create(&hunspell_suggest_worker, &thread_args[i]) + if threads[i] is NULL: + raise OSError("Could not create thread") # wait for each thread to complete for i from 0 <= i < self.n_cpus: # block until thread i completes - rc = pthread_join(threads[i], NULL) + rc = thread_join(threads[i]) if rc: - raise OSError(rc, "Could not join pthread") + raise OSError(rc, "Could not join thread") # Free Hunspell Dict del thread_args[i].hspell @@ -307,7 +305,7 @@ cdef class HunspellWrap(object): finally: # Free top level stuff free(thread_args) - free(threads) + dealloc_threads(threads, self.n_cpus) # Parse the return of a bulk action cdef void _parse_bulk_results(self, dict ret_dict, list unknown_words, int *output_counts, char ***output_array) except +: diff --git a/hunspell/pthread.pxd b/hunspell/pthread.pxd deleted file mode 100644 index 0b4c332..0000000 --- a/hunspell/pthread.pxd +++ /dev/null @@ -1,83 +0,0 @@ -cdef extern from "pthread.h": - ctypedef void * pthread_t - ctypedef struct pthread_attr_t: - pass - - #int pthread_atfork(void (*)(), void (*)(), void (*)()) - #int pthread_attr_destroy(pthread_attr_t *) - #int pthread_attr_getdetachstate(const pthread_attr_t *, int *) - #int pthread_attr_getguardsize(const pthread_attr_t *, size_t *) - #int pthread_attr_getinheritsched(const pthread_attr_t *, int *) - #int pthread_attr_getschedparam(const pthread_attr_t *, struct sched_param *) - #int pthread_attr_getschedpolicy(const pthread_attr_t *, int *) - #int pthread_attr_getscope(const pthread_attr_t *, int *) - #int pthread_attr_getstack(const pthread_attr_t *, void **, size_t *) - #int pthread_attr_getstackaddr(const pthread_attr_t *, void **) - #int pthread_attr_getstacksize(const pthread_attr_t *, size_t *) - #int pthread_attr_init(pthread_attr_t *) - #int pthread_attr_setdetachstate(pthread_attr_t *, int) - #int pthread_attr_setguardsize(pthread_attr_t *, size_t) - #int pthread_attr_setinheritsched(pthread_attr_t *, int) - #int pthread_attr_setschedparam(pthread_attr_t *, const struct sched_param *) - #int pthread_attr_setschedpolicy(pthread_attr_t *, int) - #int pthread_attr_setscope(pthread_attr_t *, int) - #int pthread_attr_setstack(pthread_attr_t *, void *, size_t) - #int pthread_attr_setstackaddr(pthread_attr_t *, void *) - #int pthread_attr_setstacksize(pthread_attr_t *, size_t) - #int pthread_cancel(pthread_t) - #int pthread_cond_broadcast(pthread_cond_t *) - #int pthread_cond_destroy(pthread_cond_t *) - #int pthread_cond_init(pthread_cond_t *, const pthread_condattr_t *) - #int pthread_cond_signal(pthread_cond_t *) - #int pthread_cond_timedwait(pthread_cond_t *, pthread_mutex_t *, const struct timespec *) - #int pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *) - #int pthread_condattr_destroy(pthread_condattr_t *) - #int pthread_condattr_init(pthread_condattr_t *) - #int pthread_condattr_getpshared(const pthread_condattr_t *, int *) - #int pthread_condattr_setpshared(pthread_condattr_t *, int) - int pthread_create(pthread_t *, const pthread_attr_t *, void *(*)(void *), void *) - #int pthread_detach(pthread_t) - int pthread_equal(pthread_t, pthread_t) - void pthread_exit(void *) - #int pthread_getconcurrency() - #int pthread_getschedparam(pthread_t , int *, struct sched_param *) - #void* pthread_getspecific(pthread_key_t) - int pthread_join(pthread_t , void **) - #int pthread_key_create(pthread_key_t *, void (*)(void *)) - #int pthread_key_delete(pthread_key_t) - #int pthread_mutex_destroy(pthread_mutex_t *) - #int pthread_mutex_getprioceiling(const pthread_mutex_t *, int *) - #int pthread_mutex_init(pthread_mutex_t *, const pthread_mutexattr_t *) - #int pthread_mutex_lock(pthread_mutex_t *) - #int pthread_mutex_setprioceiling(pthread_mutex_t *, int, int *) - #int pthread_mutex_trylock(pthread_mutex_t *) - #int pthread_mutex_unlock(pthread_mutex_t *) - #int pthread_mutexattr_destroy(pthread_mutexattr_t *) - #int pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *, int *) - #int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *, int *) - #int pthread_mutexattr_getpshared(const pthread_mutexattr_t *, int *) - #int pthread_mutexattr_gettype(const pthread_mutexattr_t *, int *) - #int pthread_mutexattr_init(pthread_mutexattr_t *) - #int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *, int) - #int pthread_mutexattr_setprotocol(pthread_mutexattr_t *, int) - #int pthread_mutexattr_setpshared(pthread_mutexattr_t *, int) - #int pthread_mutexattr_settype(pthread_mutexattr_t *, int) - #int pthread_once(pthread_once_t *, void (*)()) - #int pthread_rwlock_destroy(pthread_rwlock_t *) - #int pthread_rwlock_init(pthread_rwlock_t *, const pthread_rwlockattr_t *) - #int pthread_rwlock_rdlock(pthread_rwlock_t *) - #int pthread_rwlock_tryrdlock(pthread_rwlock_t *) - #int pthread_rwlock_trywrlock(pthread_rwlock_t *) - #int pthread_rwlock_wrlock(pthread_rwlock_t *) - #int pthread_rwlock_unlock(pthread_rwlock_t *) - #int pthread_rwlockattr_destroy(pthread_rwlockattr_t *) - #int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *, int *) - #int pthread_rwlockattr_init(pthread_rwlockattr_t *) - #int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *, int) - #pthread_t pthread_self() - #int pthread_setcancelstate(int , int *) - #int pthread_setcanceltype(int , int *) - #int pthread_setconcurrency(int) - #int pthread_setschedparam(pthread_t, int, const struct sched_param *) - #int pthread_setspecific(pthread_key_t , const void *) - #void pthread_testcancel() diff --git a/hunspell/thread.hpp b/hunspell/thread.hpp new file mode 100644 index 0000000..cc89d72 --- /dev/null +++ b/hunspell/thread.hpp @@ -0,0 +1,63 @@ +#ifndef AGNOSTIC_THREAD_HPP_ +#define AGNOSTIC_THREAD_HPP_ + +typedef void * thread_t; + +#ifdef _MSC_VER +#include +void dealloc_threads(thread_t **threads, int num_threads) { + for (int i = 0; i < num_threads; i++) { + CloseHandle(threads[i]); + } + free(threads); +} + +struct WorkerWrapperArgs { + void *(*worker)(void *); + void *data; +}; + +unsigned long __cdecl worker_wrapper(void *args) { + void *data = ((WorkerWrapperArgs *)args)->data; + void *(*worker)(void *) = ((WorkerWrapperArgs *)args)->worker; + free(args); + + void *worker_result = worker(data); + return worker_result == NULL ? 0 : 1; +} + +thread_t *thread_create(void *(*worker)(void *), void *data) { + unsigned long id_holder; + WorkerWrapperArgs *args = (WorkerWrapperArgs *)malloc(sizeof(WorkerWrapperArgs)); + args->worker = worker; + args->data = data; + return (thread_t *)CreateThread(NULL, 0, &worker_wrapper, args, 0, &id_holder); +} + +int thread_join(thread_t *thread) { + return WaitForSingleObject(thread, INFINITE); +} +#else +#include +void dealloc_threads(thread_t **threads, int num_threads) { + for (int i = 0; i < num_threads; i++) { + free(threads[i]); + } + free(threads); +} + +thread_t *thread_create(void *(*worker)(void *), void *data) { + pthread_t *thread = (pthread_t *)malloc(sizeof(pthread_t)); + if (pthread_create(thread, NULL, worker, data)) { + free(thread); + thread = NULL; + } + return (thread_t *)thread; +} + +int thread_join(thread_t *thread) { + return pthread_join((pthread_t)*thread, NULL); +} +#endif + +#endif /* AGNOSTIC_THREAD_HPP_ */ diff --git a/hunspell/thread.pxd b/hunspell/thread.pxd new file mode 100644 index 0000000..2ff08bf --- /dev/null +++ b/hunspell/thread.pxd @@ -0,0 +1,6 @@ +cdef extern from "thread.hpp": + ctypedef void *thread_t + + void dealloc_threads(thread_t **threads, int num_threads) + thread_t *thread_create(void *(*worker)(void *), void *data) + int thread_join(thread_t *thread) diff --git a/libs/README b/libs/README new file mode 100644 index 0000000..2676678 --- /dev/null +++ b/libs/README @@ -0,0 +1,5 @@ +The compiled libraries for Microsoft Visual Studio are included, because they are very difficult to build automatically. + +For other platforms besides windows, if Hunspell is not already installed then the source code is downloaded and built. + +The hunspell license is included for the two compiled binaries -- its compatible with tihs repositories license. diff --git a/libs/license.hunspell b/libs/license.hunspell new file mode 100644 index 0000000..8f998bd --- /dev/null +++ b/libs/license.hunspell @@ -0,0 +1,55 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Hunspell, based on MySpell. + * + * The Initial Developers of the Original Code are + * Kevin Hendricks (MySpell) and Németh László (Hunspell). + * Portions created by the Initial Developers are Copyright (C) 2002-2005 + * the Initial Developers. All Rights Reserved. + * + * Contributor(s): + * David Einstein + * Davide Prina + * Giuseppe Modugno + * Gianluca Turconi + * Simon Brouwer + * Noll János + * Bíró Árpád + * Goldman Eleonóra + * Sarlós Tamás + * Bencsáth Boldizsár + * Halácsy Péter + * Dvornik László + * Gefferth András + * Nagy Viktor + * Varga Dániel + * Chris Halls + * Rene Engelhard + * Bram Moolenaar + * Dafydd Jones + * Harri Pitkänen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ diff --git a/libs/msvc/libhunspellx64.lib b/libs/msvc/libhunspellx64.lib new file mode 100644 index 0000000..fac1140 Binary files /dev/null and b/libs/msvc/libhunspellx64.lib differ diff --git a/libs/msvc/libhunspellx86.lib b/libs/msvc/libhunspellx86.lib new file mode 100644 index 0000000..a8226f2 Binary files /dev/null and b/libs/msvc/libhunspellx86.lib differ diff --git a/setup.py b/setup.py index 4c66d9b..9262461 100644 --- a/setup.py +++ b/setup.py @@ -1,15 +1,12 @@ import os import sys -import glob -import shutil -import imp +import platform from setuptools import setup, find_packages, Extension -from distutils.command.install import install from setuptools.command.egg_info import egg_info from subprocess import check_call from find_library import pkgconfig -VERSION = '1.0.1' +VERSION = '1.1.0' requirements_file = os.path.join(os.path.dirname(__file__), 'requirements.txt') @@ -38,16 +35,17 @@ def readMD(fname): else: return read(fname) -datatypes = ['*.aff', '*.dic', '*.pxd', '*.pyx', '*.so'] +datatypes = ['*.aff', '*.dic', '*.pxd', '*.pyx', '*.pyd', '*.so', '*.lib', '*hpp'] packages = find_packages(exclude=['*.tests', '*.tests.*', 'tests.*', 'tests']) -packages.append('dictionaries') +packages.extend(['dictionaries', 'libs.msvc']) required = [req.strip() for req in read('requirements.txt').splitlines() if req.strip()] +build_args = ['-O3', '-g0'] if platform.system() != 'Windows' else ['/EHsc', '/DHUNSPELL_STATIC'] ext_modules = cythonize([ Extension( - os.path.join('hunspell', 'hunspell'), + 'hunspell.hunspell', [os.path.join('hunspell', 'hunspell.pyx')], - extra_compile_args=['-O3', '-g0'], + extra_compile_args=build_args, **pkgconfig('hunspell', language='c++') ) ]) @@ -73,7 +71,7 @@ def run(self): cmdclass={ 'build_ext': build_ext, 'egg_info': egg_build }, license='New BSD', packages=packages, - scripts=['find_library.py'], + scripts=['find_library.py', 'tar_download.py'], test_suite='tests', zip_safe=False, url='https://github.com/OpenGov/cython_hunspell', diff --git a/tar_download.py b/tar_download.py new file mode 100644 index 0000000..d380f82 --- /dev/null +++ b/tar_download.py @@ -0,0 +1,33 @@ +import os +import sys +import urllib +import tarfile + +def file_name_from_url(url, directory=None): + file_name = url.split('/')[-1] + if directory: + file_name = os.path.join(directory, file_name) + return file_name + +def download_tar(url, directory=None): + if not os.path.exists(directory): + os.makedirs(directory) + + file_name = file_name_from_url(url, directory) + print "Downloading {} to {}".format(url, file_name) + sys.stdout.flush() + urllib.urlretrieve(url, file_name) + +def extract_contents(file_name, destination='.'): + if not os.path.exists(destination): + os.makedirs(destination) + + print "Extracting {} to {}".format(file_name, destination) + sys.stdout.flush() + tar = tarfile.open(file_name) + tar.extractall(destination) + tar.close() + +def download_and_extract(url, directory=None): + download_tar(url, directory) + extract_contents(file_name_from_url(url, directory), directory)