From 9c6508a8a38bed449c213fb2b3cf573b92537bb5 Mon Sep 17 00:00:00 2001 From: Nitin Madnani Date: Fri, 3 Oct 2014 22:14:42 -0400 Subject: [PATCH] pip-friendly and better organization - Added setup.py to make zpar pip installable - Reorganized code to hide the ctypes stuff from the user and make zpar easier to use. --- Makefile | 4 +- setup.py | 93 ++++++++++++++++++++++++++ src/zpar.lib.cpp | 8 +++ zpar/DepParser.py | 44 +++++++++++++ zpar/Parser.py | 44 +++++++++++++ zpar/Tagger.py | 45 +++++++++++++ zpar/__init__.py | 74 +++++++++++++++++++++ zpar_client.py | 4 +- zpar_example.py | 122 ++++++---------------------------- zpar_server.py | 165 +++++++++------------------------------------- 10 files changed, 362 insertions(+), 241 deletions(-) create mode 100644 setup.py create mode 100644 zpar/DepParser.py create mode 100644 zpar/Parser.py create mode 100644 zpar/Tagger.py create mode 100644 zpar/__init__.py diff --git a/Makefile b/Makefile index 73aebec..9bcc42f 100644 --- a/Makefile +++ b/Makefile @@ -11,8 +11,8 @@ python-zpar: clean /tmp/zpar.zip cp src/Makefile /tmp/zpar cp src/reader.h /tmp/zpar/src/include/reader.h make -C /tmp/zpar zpar.so - mkdir -p dist - cp /tmp/zpar/dist/zpar.so dist/ + mkdir -p zpar/dist + cp /tmp/zpar/dist/zpar.so zpar/dist/ /tmp/zpar.zip: wget -N http://sourceforge.net/projects/zpar/files/latest/zpar.zip -O /tmp/zpar.zip diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..35029a3 --- /dev/null +++ b/setup.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python + +# Adapted from https://github.com/Turbo87/py-xcsoar/blob/master/setup.py + +import os +from setuptools import setup +from setuptools.command.install import install +from distutils.command.build import build +from subprocess import call + +import sys + +BASEPATH = os.path.dirname(os.path.abspath(__file__)) +ZPAR_PATH = os.path.join(BASEPATH, 'zpar') +ZPAR_LIB_PATH = os.path.join(ZPAR_PATH, 'dist') + +class build_zpar(build): + def run(self): + + # run original build code + build.run(self) + + sys.stderr.write('running build_zpar\n') + + # for now the compilation is just calling make + cmd = ['make'] + + # compile the shared library path + def compile(): + sys.stderr.write('*' * 80 + '\n') + call(cmd) + sys.stderr.write('*' * 80 + '\n') + self.execute(compile, [], 'compiling zpar library') + + # copy resulting tool to library build folder + self.mkpath(self.build_lib) + + if not self.dry_run: + self.copy_tree(ZPAR_PATH, self.build_lib) + +class install_zpar(install): + + def initialize_options(self): + install.initialize_options(self) + self.build_scripts = None + + def finalize_options(self): + install.finalize_options(self) + self.set_undefined_options('build', ('build_scripts', 'build_scripts')) + + def run(self): + # run original install code + install.run(self) + + # install ZPar executables + sys.stderr.write('running install_zpar\n') + install_path = os.path.join(self.install_lib, 'zpar') + self.mkpath(install_path) + self.copy_tree(self.build_lib, install_path) + + +def read(fname): + return open(os.path.join(os.path.dirname(__file__), fname)).read() + + +setup( + name='zpar', + version='0.1', + description='A Wrapper around the ZPar statistical tagger/parser for English', + maintainer='Nitin Madnani', + maintainer_email='nmadnani@ets.org', + license='MIT', + url='http://www.github.com/EducationalTestingService/python-zpar', + long_description=read('README.md'), + classifiers=['Intended Audience :: Science/Research', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: MIT License', + 'Programming Language :: Python', + 'Topic :: Software Development', + 'Topic :: Scientific/Engineering', + 'Operating System :: POSIX', + 'Operating System :: Unix', + 'Operating System :: MacOS', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.3', + ], + cmdclass={ + 'build': build_zpar, + 'install': install_zpar, + } +) diff --git a/src/zpar.lib.cpp b/src/zpar.lib.cpp index 1270daf..f7f4ac0 100644 --- a/src/zpar.lib.cpp +++ b/src/zpar.lib.cpp @@ -142,6 +142,14 @@ extern "C" int load_parser(const char *sFeaturePath) { // The function to load the dependency parser model extern "C" int load_depparser(const char *sFeaturePath) { + // If the tagger is not already loaded, then we need to load + // it since the parser requires the tagger + if (!zpm->tagger) { + if (load_tagger(sFeaturePath)) { + return 1; + } + } + CDepParser *depparser; std::string sDepParserFeatureFile = std::string(sFeaturePath) + "/depparser"; std::cerr << "Loading dependency parser from " << sDepParserFeatureFile << std::endl; diff --git a/zpar/DepParser.py b/zpar/DepParser.py new file mode 100644 index 0000000..08d7478 --- /dev/null +++ b/zpar/DepParser.py @@ -0,0 +1,44 @@ +# License: MIT +''' +:author: Nitin Madnani (nmadnani@ets.org) +:organization: ETS +''' + +import ctypes as c + +class DepParser(object): + """The ZPar English Dependency Parser""" + + def __init__(self, modelpath, libptr): + super(DepParser, self).__init__() + + # get the library method that loads the parser models + self._load_depparser = libptr.load_depparser + self._load_depparser.restype = c.c_int + self._load_depparser.argtypes = [c.c_char_p] + + # get the library methods that parse sentences and files + self._dep_parse_sentence = libptr.dep_parse_sentence + self._dep_parse_sentence.restype = c.c_char_p + self._dep_parse_sentence.argtypes = [c.c_char_p] + + self._parse_file = libptr.dep_parse_file + self._parse_file.restype = None + self._parse_file.argtypes = [c.c_char_p, c.c_char_p] + + if self._load_depparser(modelpath.encode('utf-8')): + raise OSError('Cannot find dependency parser model at {}\n'.format(modelpath)) + + def parse_sentence(self, sentence): + zpar_compatible_sentence = sentence.strip() + "\n " + zpar_compatible_sentence = zpar_compatible_sentence.encode('utf-8') + parsed_sent = self._dep_parse_sentence(zpar_compatible_sentence) + return parsed_sent.decode('utf-8') + + def parse_file(self, inputfile, outputfile): + self._parse_file(inputfile.encode('utf-8'), outputfile.encode('utf-8')) + + def cleanup(self): + self._load_depparser = None + self._dep_parse_sentence = None + self._parse_file = None diff --git a/zpar/Parser.py b/zpar/Parser.py new file mode 100644 index 0000000..c13c53c --- /dev/null +++ b/zpar/Parser.py @@ -0,0 +1,44 @@ +# License: MIT +''' +:author: Nitin Madnani (nmadnani@ets.org) +:organization: ETS +''' + +import ctypes as c + +class Parser(object): + """The ZPar English Constituency Parser""" + + def __init__(self, modelpath, libptr): + super(Parser, self).__init__() + + # get the library method that loads the parser models + self._load_parser = libptr.load_parser + self._load_parser.restype = c.c_int + self._load_parser.argtypes = [c.c_char_p] + + # get the library methods that parse sentences and files + self._parse_sentence = libptr.parse_sentence + self._parse_sentence.restype = c.c_char_p + self._parse_sentence.argtypes = [c.c_char_p] + + self._parse_file = libptr.parse_file + self._parse_file.restype = None + self._parse_file.argtypes = [c.c_char_p, c.c_char_p] + + if self._load_parser(modelpath.encode('utf-8')): + raise OSError('Cannot find parser model at {}\n'.format(modelpath)) + + def parse_sentence(self, sentence): + zpar_compatible_sentence = sentence.strip() + "\n " + zpar_compatible_sentence = zpar_compatible_sentence.encode('utf-8') + parsed_sent = self._parse_sentence(zpar_compatible_sentence) + return parsed_sent.decode('utf-8') + + def parse_file(self, inputfile, outputfile): + self._parse_file(inputfile.encode('utf-8'), outputfile.encode('utf-8')) + + def cleanup(self): + self._load_parser = None + self._parse_sentence = None + self._parse_file = None diff --git a/zpar/Tagger.py b/zpar/Tagger.py new file mode 100644 index 0000000..7b331ae --- /dev/null +++ b/zpar/Tagger.py @@ -0,0 +1,45 @@ +# License: MIT +''' +:author: Nitin Madnani (nmadnani@ets.org) +:organization: ETS +''' + +import ctypes as c + +class Tagger(object): + """The ZPar English POS Tagger""" + + def __init__(self, modelpath, libptr): + super(Tagger, self).__init__() + + # get the library method that loads the tagger models + self._load_tagger = libptr.load_tagger + self._load_tagger.restype = c.c_int + self._load_tagger.argtypes = [c.c_char_p] + + # get the library methods that tag sentences and files + self._tag_sentence = libptr.tag_sentence + self._tag_sentence.restype = c.c_char_p + self._tag_sentence.argtypes = [c.c_char_p] + + self._tag_file = libptr.tag_file + self._tag_file.restype = None + self._tag_file.argtypes = [c.c_char_p, c.c_char_p] + + if self._load_tagger(modelpath.encode('utf-8')): + raise OSError('Cannot find tagger model at {}\n'.format(modelpath)) + + def tag_sentence(self, sentence): + zpar_compatible_sentence = sentence.strip() + "\n " + zpar_compatible_sentence = zpar_compatible_sentence.encode('utf-8') + tagged_sent = self._tag_sentence(zpar_compatible_sentence) + return tagged_sent.decode('utf-8') + + def tag_file(self, inputfile, outputfile): + self._tag_file(inputfile.encode('utf-8'), outputfile.encode('utf-8')) + + def cleanup(self): + self._load_tagger = None + self._tag_sentence = None + self._tag_file = None + diff --git a/zpar/__init__.py b/zpar/__init__.py new file mode 100644 index 0000000..f2f9fcf --- /dev/null +++ b/zpar/__init__.py @@ -0,0 +1,74 @@ +# License: MIT +''' +:author: Nitin Madnani (nmadnani@ets.org) +:organization: ETS +''' + +import _ctypes +import ctypes as c +import os + +from .Tagger import Tagger +from .Parser import Parser +from .DepParser import DepParser + +__all__ = ['Tagger', 'Parser', 'DepParser'] + +class ZPar(object): + """The ZPar wrapper object""" + + def __init__(self, modelpath): + super(ZPar, self).__init__() + + # get a pointer to the zpar shared library + base_path = os.path.dirname(os.path.abspath(__file__)) + zpar_path = os.path.join(base_path, 'dist', 'zpar.so') + self.libptr = c.cdll.LoadLibrary(zpar_path) + self.modelpath = modelpath + self.tagger = None + self.parser = None + self.depparser = None + + def close(self): + # unload the models on the C++ side + self.libptr.unload_models() + + # clean up the data structures on the python side + if self.tagger: + self.tagger.cleanup() + + if self.parser: + self.parser.cleanup() + + if self.depparser: + self.depparser.cleanup() + + # set all the fields to none to enable clean reuse + self.tagger = None + self.parser = None + self.depparser = None + self.modelpath = None + + # clean up the CDLL object too so that upon reuse, we get a new one + _ctypes.dlclose(self.libptr._handle) + + def __enter__(self): + """Enable ZPar to be used as a ContextManager""" + return self + + def __exit__(self, type, value, traceback): + """Clean up when done""" + self.close() + + def get_tagger(self): + self.tagger = Tagger(self.modelpath, self.libptr) + return self.tagger + + def get_parser(self): + self.parser = Parser(self.modelpath, self.libptr) + return self.parser + + def get_depparser(self): + self.depparser = DepParser(self.modelpath, self.libptr) + return self.depparser + diff --git a/zpar_client.py b/zpar_client.py index 531b08d..a7e6ad4 100755 --- a/zpar_client.py +++ b/zpar_client.py @@ -60,14 +60,14 @@ logging.info("Output: {}".format(tagged_sent)) logging.info('Dep Parsing "{}"'.format(test_sentence)) - dep_parsed_sent = proxy.dep_parse_sentence(test_sentence) + dep_parsed_sent = proxy.parse_sentence(test_sentence) logging.info("Output: {}".format(dep_parsed_sent)) logging.info('Tagging file {} into {}'.format(test_file, tag_outfile)) proxy.tag_file(test_file, tag_outfile) logging.info('Dep Parsing file {} into {}'.format(test_file, dep_outfile)) - proxy.dep_parse_file(test_file, dep_outfile) + proxy.parse_file(test_file, dep_outfile) except socket.error as err: sys.stderr.write("{}\n".format(err)) diff --git a/zpar_example.py b/zpar_example.py index 3cad6af..7ee7012 100755 --- a/zpar_example.py +++ b/zpar_example.py @@ -1,20 +1,13 @@ #!/usr/bin/env python3 import argparse -import ctypes as c -import logging -import os -import sys - from six import print_ +from zpar import ZPar + if __name__ == '__main__': # set up an argument parser parser = argparse.ArgumentParser(prog='zpar_example.py') - parser.add_argument('--zpar', dest='zpar', - help="Path to the zpar library file zpar.so", - required=False, default=os.getcwd()) - parser.add_argument('--modeldir', dest='modeldir', help="Path to directory containing zpar English models", required=True) @@ -22,101 +15,26 @@ # parse given command line arguments args = parser.parse_args() - # set up the logging - logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.INFO) - - # link to the zpar library - zpar_library_path = os.path.join(args.zpar, 'zpar.so') - - # Create a wrapper data structure that the functionality as methods - zpar = c.cdll.LoadLibrary(zpar_library_path) - - # define the argument and return types for all - # the functions we want to expose to the client - load_models = zpar.load_models - load_models.restype = c.c_int - load_models.argtypes = [c.c_char_p] - - load_tagger = zpar.load_tagger - load_tagger.restype = c.c_int - load_tagger.argtypes = [c.c_char_p] - - load_parser = zpar.load_parser - load_parser.restype = c.c_int - load_parser.argtypes = [c.c_char_p] - - load_depparser = zpar.load_depparser - load_depparser.restype = c.c_int - load_depparser.argtypes = [c.c_char_p] - - tag_sentence = zpar.tag_sentence - tag_sentence.restype = c.c_char_p - tag_sentence.argtypes = [c.c_char_p] - - parse_sentence = zpar.parse_sentence - parse_sentence.restype = c.c_char_p - parse_sentence.argtypes = [c.c_char_p] - - dep_parse_sentence = zpar.dep_parse_sentence - dep_parse_sentence.restype = c.c_char_p - dep_parse_sentence.argtypes = [c.c_char_p] - - tag_file = zpar.tag_file - tag_file.restype = None - tag_file.argtypes = [c.c_char_p, c.c_char_p] - - parse_file = zpar.parse_file - parse_file.restype = None - parse_file.argtypes = [c.c_char_p, c.c_char_p] - - dep_parse_file = zpar.dep_parse_file - dep_parse_file.restype = None - dep_parse_file.argtypes = [c.c_char_p, c.c_char_p] - - unload_models = zpar.unload_models - unload_models.restype = None - - # Load just the tagger and the dependency parser. - # To load the constituency parser, use load_parser(). - # If you want to load all three models, use - # load_models() instead. - if load_tagger(args.modeldir.encode('utf-8')): - sys.stderr.write('Cannot find tagger model at {}\n'.format(args.modeldir)) - zpar.unload_models() - sys.exit(1) - if load_parser(args.modeldir.encode('utf-8')): - sys.stderr.write('Cannot find parser model at {}\n'.format(args.modeldir)) - zpar.unload_models() - sys.exit(1) - if load_depparser(args.modeldir.encode('utf-8')): - sys.stderr.write('Cannot find depparser model at {}\n'.format(args.modeldir)) - zpar.unload_models() - sys.exit(1) - - # Tag a sentence. Note that the sentence does not need to be tokenized - # but needs to have a newline and a space after it because of the - # way that zpar word tokenizer is written. We also need - # to convert the output back from bytes to strings. - tagged_sent = tag_sentence("I am going to the market.\n ".encode("utf-8")) - print_(tagged_sent.decode('utf-8')) - - parsed_sent = parse_sentence("I am going to the market.\n ".encode("utf-8")) - print_(parsed_sent.decode('utf-8')) + # use the zpar wrapper as a context manager + with ZPar(args.modeldir) as z: - parsed_sent = parse_sentence("Would you like to come with me?\n ".encode("utf-8")) - print_(parsed_sent.decode('utf-8')) + # get the parser and the dependency parser models + tagger = z.get_tagger() + depparser = z.get_depparser() - # Compute the dependency parse of the sentence - dep_parsed_sent = dep_parse_sentence("I am going to the market.\n ".encode("utf-8")) - print_(dep_parsed_sent.decode('utf-8')) + # tag a sentence + tagged_sent = tagger.tag_sentence("I am going to the market.") + print_(tagged_sent) - # compute POS tags for all sentences in a file - # note that the file contains a single sentence - # per line. The sentences need not be word tokenized - tag_file(b"test.txt", b"test.tag") + # get the dependency parse of the same sentence + dep_parsed_sent = depparser.parse_sentence("I am going to the market.") + print_(dep_parsed_sent) - # compute dependency parses for all sentences in a file - dep_parse_file(b"test.txt", b"test.dep") + # compute POS tags for all sentences in "test.txt" + # and write the output to "test.tag". Note that the + # file contains a single sentence per line. + # The sentences need not be word tokenized + tagger.tag_file("test.txt", "test.tag") - # unload all the models from memory once you are done - unload_models() + # compute dependency parses for all sentences in "test.txt" + depparser.parse_file("test.txt", "test.dep") diff --git a/zpar_server.py b/zpar_server.py index a3e7e97..743ddb2 100755 --- a/zpar_server.py +++ b/zpar_server.py @@ -1,11 +1,13 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python + import argparse -import ctypes as c import logging import os import six import sys +from zpar import ZPar + if six.PY2: from SimpleXMLRPCServer import SimpleXMLRPCServer else: @@ -31,89 +33,33 @@ class StoppableServer(_baseclass): allow_reuse_address = True - def __init__(self, addr, zpar_ref, zpar_model_path, model_list, *args, **kwds): + def __init__(self, addr, zpar_model_path, model_list, *args, **kwds): + + super(StoppableServer, self).__init__(addr) # store the hostname and port number self.myhost, self.myport = addr # store the link to the loaded zpar object - self.zpar_ref = zpar_ref - - # define the argument and return types for all - # the functions we want to expose to the client - self.zpar_ref.load_models.restype = c.c_int - self.zpar_ref.load_models.argtypes = [c.c_char_p] - - self.zpar_ref.load_tagger.restype = c.c_int - self.zpar_ref.load_tagger.argtypes = [c.c_char_p] - - self.zpar_ref.load_parser.restype = c.c_int - self.zpar_ref.load_parser.argtypes = [c.c_char_p] - - self.zpar_ref.load_depparser.restype = c.c_int - self.zpar_ref.load_depparser.argtypes = [c.c_char_p] - - self.zpar_ref.tag_sentence.restype = c.c_char_p - self.zpar_ref.tag_sentence.argtypes = [c.c_char_p] - - self.zpar_ref.parse_sentence.restype = c.c_char_p - self.zpar_ref.parse_sentence.argtypes = [c.c_char_p] - - self.zpar_ref.dep_parse_sentence.restype = c.c_char_p - self.zpar_ref.dep_parse_sentence.argtypes = [c.c_char_p] - - self.zpar_ref.tag_file.restype = None - self.zpar_ref.tag_file.argtypes = [c.c_char_p, c.c_char_p] - - self.zpar_ref.parse_file.restype = None - self.zpar_ref.parse_file.argtypes = [c.c_char_p, c.c_char_p] - - self.zpar_ref.dep_parse_file.restype = None - self.zpar_ref.dep_parse_file.argtypes = [c.c_char_p, c.c_char_p] - - self.zpar_ref.unload_models.restype = None + self.z = ZPar(zpar_model_path) # initialize the parent class _baseclass.__init__(self, addr, *args, **kwds) - # load the models we were asked to. If the list of - # given models is empty or if it contains all the models - # then call the function that loads all the models and - # registers all the functions - if not model_list or sorted(model_list) == ['depparser', - 'parser', - 'tagger']: - if self.zpar_ref.load_models(zpar_model_path): - raise ModelNotFoundError("all", zpar_model_path.decode('utf-8')) - else: - self.register_function(self.tag_sentence) - self.register_function(self.parse_sentence) - self.register_function(self.dep_parse_sentence) - self.register_function(self.tag_file) - self.register_function(self.parse_file) - self.register_function(self.dep_parse_file) - - # otherwise call the individual loading functions + # Call the individual loading functions # and only register the appropriate methods - else: - if 'tagger' in model_list: - if self.zpar_ref.load_tagger(zpar_model_path): - raise ModelNotFoundError("tagger", zpar_model_path.decode('utf-8')) - else: - self.register_function(self.tag_sentence) - self.register_function(self.tag_file) - if 'parser' in model_list: - if self.zpar_ref.load_parser(zpar_model_path): - raise ModelNotFoundError("parser", zpar_model_path.decode('utf-8')) - else: - self.register_function(self.parse_sentence) - self.register_function(self.parse_file) - if 'depparser' in model_list: - if self.zpar_ref.load_depparser(zpar_model_path): - raise ModelNotFoundError("depparser", zpar_model_path.decode('utf-8')) - else: - self.register_function(self.dep_parse_sentence) - self.register_function(self.dep_parse_file) + if 'tagger' in model_list: + tagger = self.z.get_tagger() + self.register_function(tagger.tag_sentence) + self.register_function(tagger.tag_file) + if 'parser' in model_list: + parser = self.z.get_parser() + self.register_function(parser.parse_sentence) + self.register_function(parser.parse_file) + if 'depparser' in model_list: + parser = self.z.get_depparser() + self.register_function(parser.parse_sentence) + self.register_function(parser.parse_file) # register the function to remotely stop the server self.register_function(self.stop_server) @@ -127,39 +73,9 @@ def serve_forever(self): except KeyboardInterrupt: print("\nKeyboard interrupt received, exiting.") break - self.zpar_ref.unload_models() + self.z.close() self.server_close() - def tag_sentence(self, sentence): - # We need to add a newline to the sentence - # given how zpar's tokenization works - out = self.zpar_ref.tag_sentence(sentence.encode('utf-8') + b'\n ') - return out.decode('utf-8') - - def parse_sentence(self, sentence): - # We need to add a newline to the sentence - # given how zpar's tokenization works - out = self.zpar_ref.parse_sentence(sentence.encode('utf-8') + b'\n ') - return out.decode('utf-8') - - def dep_parse_sentence(self, sentence): - # We need to add a newline to the sentence - # given how zpar's tokenization works - out = self.zpar_ref.dep_parse_sentence(sentence.encode('utf-8') + b'\n ') - return out.decode('utf-8') - - def tag_file(self, input_filename, output_filename): - self.zpar_ref.tag_file(input_filename.encode('utf-8'), - output_filename.encode('utf-8')) - - def parse_file(self, input_filename, output_filename): - self.zpar_ref.parse_file(input_filename.encode('utf-8'), - output_filename.encode('utf-8')) - - def dep_parse_file(self, input_filename, output_filename): - self.zpar_ref.dep_parse_file(input_filename.encode('utf-8'), - output_filename.encode('utf-8')) - def stop_server(self): self.quit = True return 0, "Server terminated on host %r, port %r" % (self.myhost, self.myport) @@ -169,17 +85,13 @@ def stop_server(self): # set up an argument parser parser = argparse.ArgumentParser(prog='zpar_server.py') - parser.add_argument('--zpar', dest='zpar', - help="Path to the zpar library file zpar.so", - required=False, default=os.getcwd()) - parser.add_argument('--modeldir', dest='modeldir', help="Path to directory containing zpar English models", required=True) parser.add_argument('--models', dest='models', nargs='+', help="Load only these models", - default=None) + required=True) parser.add_argument('--host', dest='hostname', help="Hostname or IP address", @@ -201,36 +113,19 @@ def stop_server(self): # check to make sure that the specified models # are those we know about - if args.models: - if set(args.models).difference(['tagger', 'parser', 'depparser']): - sys.stderr.write('Error: invalid model(s) specified. Choices are: "tagger", "parser", and "depparser".\n') - sys.exit(1) + if set(args.models).difference(['tagger', 'parser', 'depparser']): + sys.stderr.write('Error: invalid model(s) specified. Choices are: "tagger", "parser", and "depparser".\n') + sys.exit(1) # set up the logging logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.INFO) - # link to the zpar library - zpar_library_path = os.path.join(args.zpar, 'zpar.so') - - # Create a wrapper data structure that the functionality as methods - zparobj = c.cdll.LoadLibrary(zpar_library_path) - # Create a server that is built on top of this ZPAR data structure logging.info('Initializing server ...') - try: - server = StoppableServer((args.hostname, args.port), - zparobj, args.modeldir.encode('utf-8'), - args.models, logRequests=args.log, - allow_none=True) - except ModelNotFoundError as err: - sys.stderr.write("{}\n".format(err)) - zparobj.unload_models() - sys.exit(1) - except: - sys.stderr.write('Error: Could not create server\n') - zparobj.unload_models() - sys.exit(1) - + server = StoppableServer((args.hostname, args.port), + args.modeldir, args.models, + logRequests=args.log, + allow_none=True) # Register introspection functions with the server logging.info('Registering introspection ...')