From a1734aaff105ae56526f45ffd2fd0e0bc64e2be7 Mon Sep 17 00:00:00 2001 From: JPJPJPOPOP Date: Sat, 6 Jan 2018 23:12:06 -0800 Subject: [PATCH 01/11] Deconflicted files. --- modeSearch.py | 6 +++++- servlet.py | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/modeSearch.py b/modeSearch.py index 6239c9118..1708fc6dd 100644 --- a/modeSearch.py +++ b/modeSearch.py @@ -34,13 +34,17 @@ def searchPath(rootpath, include_pairs=True, verbosity=1): 'pair': re.compile(r'({0})-({0})\.mode'.format(lang_code)), 'analyzer': re.compile(r'(({0}(-{0})?)-(an)?mor(ph)?)\.mode'.format(lang_code)), 'generator': re.compile(r'(({0}(-{0})?)-gener[A-z]*)\.mode'.format(lang_code)), - 'tagger': re.compile(r'(({0}(-{0})?)-tagger)\.mode'.format(lang_code)) + 'tagger': re.compile(r'(({0}(-{0})?)-tagger)\.mode'.format(lang_code)), + 'spell': re.compile(r'(({0}(-{0})?)-spell)\.mode'.format(lang_code)), + 'tokenise': re.compile(r'(({0}(-{0})?)-tokenise)\.mode'.format(lang_code)) } modes = { 'pair': [], 'analyzer': [], 'generator': [], 'tagger': [], + 'spell': [], + 'tokenise': [], } # type: Dict[str, List[Tuple[str, str, str]]] real_root = os.path.abspath(os.path.realpath(rootpath)) diff --git a/servlet.py b/servlet.py index b80245e88..45b82aa04 100755 --- a/servlet.py +++ b/servlet.py @@ -102,6 +102,7 @@ class BaseHandler(tornado.web.RequestHandler): analyzers = {} # type: Dict[str, Tuple[str, str]] generators = {} # type: Dict[str, Tuple[str, str]] taggers = {} # type: Dict[str, Tuple[str, str]] + spellers = {} # type: Dict[str, Tuple[str, str]] # (l1, l2): [translation.Pipeline], only contains flushing pairs! pipelines = {} # type: Dict[str, List] pipelines_holding = [] # type: List @@ -295,6 +296,8 @@ def langs(foo): self.sendResponse({pair: modename for (pair, (path, modename)) in self.generators.items()}) elif query == 'taggers' or query == 'disambiguators': self.sendResponse({pair: modename for (pair, (path, modename)) in self.taggers.items()}) + elif query == 'spellers': + self.sendResponse({lang_src: modename for (lang_src, (path, modename)) in self.spellers.items()}) else: self.send_error(400, explanation='Expecting q argument to be one of analysers, generators, disambiguators, or pairs') @@ -908,6 +911,48 @@ def get(self): self.send_error(400, explanation='That mode is not installed') +class SpellerHandler(BaseHandler): + + @tornado.web.asynchronous + @gen.coroutine + def get(self): + in_text = self.get_argument('q') + '*' + in_mode = toAlpha3Code(self.get_argument('lang')) + logging.info(in_text) + logging.info(in_mode) + if in_mode in self.spellers: + [path, mode] = self.spellers[in_mode] + formatting = 'none' + commands = [['apertium', '-d', path, '-f', formatting, self.get_argument('lang')+'-tokenise']] + result = yield translation.translateSimple(in_text, commands) + + tokens = parse(result) + units = [] + for token in tokens: + if token.knownness == known: + units.append({'token': token.wordform, 'known': True, 'sugg': []}) + else: + suggestion = [] + commands = [['apertium', '-d', path, '-f', formatting, mode]] + + result = yield translation.translateSimple(token.wordform, commands) + foundSugg = False + for line in result.split('\n'): + if line.count('Corrections for'): + foundSugg = True + continue + if foundSugg and ' ' in line: + s, w = line.split(' ') + suggestion.append((s, w)) + + units.append({'token': token.wordform, 'known': False, 'sugg': suggestion}) + + self.sendResponse(units) + else: + logging.info('Spellchecker not working') + self.send_error(404, explanation="{} on spellchecker mode: {}".format('Error 404', 'Mode not installed')) + + class GenerateHandler(BaseHandler): def preproc_text(self, in_text): lexical_units = re.findall(r'(\^[^\$]*\$[^\^]*)', in_text) @@ -1277,6 +1322,9 @@ def setupHandler( Handler.generators[lang_pair] = (dirpath, modename) for dirpath, modename, lang_pair in modes['tagger']: Handler.taggers[lang_pair] = (dirpath, modename) + for dirpath, modename, lang_src in modes['spell']: + if (any(lang_src == elem[2] for elem in modes['tokenise'])): + Handler.spellers[lang_src] = (dirpath, modename) Handler.initPairsGraph() Handler.initPaths() @@ -1440,7 +1488,8 @@ def apply_config(args, apySection): (r'/identifyLang', IdentifyLangHandler), (r'/getLocale', GetLocaleHandler), (r'/pipedebug', PipeDebugHandler), - (r'/suggest', SuggestionHandler) + (r'/suggest', SuggestionHandler), + (r'/speller', SpellerHandler) ]) if args.bypass_token: From 0e0a87c5c9e8a14d589a39f7b3cf1cd5e55617f3 Mon Sep 17 00:00:00 2001 From: JPJPJPOPOP Date: Sat, 6 Jan 2018 23:13:05 -0800 Subject: [PATCH 02/11] Added submodule. --- .gitmodules | 3 +++ streamparser | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 streamparser diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..cdc608af3 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "streamparser"] + path = streamparser + url = https://github.com/goavki/streamparser.git diff --git a/streamparser b/streamparser new file mode 160000 index 000000000..fdc640947 --- /dev/null +++ b/streamparser @@ -0,0 +1 @@ +Subproject commit fdc640947f36738a19f944b8d73937371f670f70 From 00d0d45ff4fe12a1cb74dd80ceee80282b5b3234 Mon Sep 17 00:00:00 2001 From: JPJPJPOPOP Date: Sat, 6 Jan 2018 23:18:42 -0800 Subject: [PATCH 03/11] Add submodule import. --- servlet.py | 1 + 1 file changed, 1 insertion(+) diff --git a/servlet.py b/servlet.py index 45b82aa04..90076db11 100755 --- a/servlet.py +++ b/servlet.py @@ -28,6 +28,7 @@ from urllib.parse import urlparse, urlunsplit import zipfile +from streamparser/streamparser import parse,known import tornado from tornado import escape from tornado import gen From 329c75bfd59633e80b462b2f58986dc88de15257 Mon Sep 17 00:00:00 2001 From: JPJPJPOPOP Date: Sat, 6 Jan 2018 23:51:34 -0800 Subject: [PATCH 04/11] Fix lint errors. --- .flake8 | 2 +- gateway.py | 9 +++++---- servlet.py | 17 +++++++++++------ util.py | 3 ++- 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/.flake8 b/.flake8 index 4f63d3f17..c3609377c 100644 --- a/.flake8 +++ b/.flake8 @@ -1,3 +1,3 @@ [flake8] max-line-length = 180 -exclude = toro.py +exclude = toro.py, streamparser diff --git a/gateway.py b/gateway.py index 1aa263d60..53a13a2d3 100755 --- a/gateway.py +++ b/gateway.py @@ -84,8 +84,9 @@ def get(self): logging.info('Redirecting %s?%s to %s%s?%s' % (path, query, server_port, path, query)) http = tornado.httpclient.AsyncHTTPClient() - http.fetch(server_port + path + "?" + query, functools.partial(self._on_download, - (server, port), langPair), validate_cert=verifySSLCert, headers=headers) + http.fetch(server_port + path + "?" + query, + functools.partial(self._on_download, (server, port), langPair), + validate_cert=verifySSLCert, headers=headers) self.balancer.inform('start', (server, port), url=path) def _on_download(self, server, langPair, response): @@ -318,8 +319,8 @@ def inform(self, action, server, *args, **kwargs): if mode in self.serverlist: if action == 'complete': if self.serverlist[mode][server]: - self.serverlist[mode][server] = (self.serverlist[mode][server] * (self.numResponses - - 1) + requestTime / responseLen) / self.numResponses + self.serverlist[mode][server] = ((self.serverlist[mode][server] * + (self.numResponses - 1) + requestTime / responseLen) / self.numResponses) else: self.serverlist[mode][server] = requestTime / responseLen / self.numResponses elif action == 'drop': diff --git a/servlet.py b/servlet.py index 90076db11..1c8f06ae4 100755 --- a/servlet.py +++ b/servlet.py @@ -28,7 +28,7 @@ from urllib.parse import urlparse, urlunsplit import zipfile -from streamparser/streamparser import parse,known +from streamparser.streamparser import parse, known import tornado from tornado import escape from tornado import gen @@ -1388,17 +1388,21 @@ def apply_config(args, apySection): parser.add_argument('-k', '--ssl-key', help='path to SSL Key File', default=None) parser.add_argument('-t', '--timeout', help='timeout for requests (default = 10)', type=int, default=10) parser.add_argument('-j', '--num-processes', - help='number of processes to run (default = 1; use 0 to run one http server per core, where each http server runs all available language pairs)', + help='number of processes to run (default = 1; use 0 to run one http server per core,' + ' where each http server runs all available language pairs)', nargs='?', type=int, default=1) parser.add_argument( - '-d', '--daemon', help='daemon mode: redirects stdout and stderr to files apertium-apy.log and apertium-apy.err ; use with --log-path', action='store_true') + '-d', '--daemon', help='daemon mode: redirects stdout and stderr to files apertium-apy.log' + ' and apertium-apy.err ; use with --log-path', action='store_true') parser.add_argument('-P', '--log-path', help='path to log output files to in daemon mode; defaults to local directory', default='./') parser.add_argument('-i', '--max-pipes-per-pair', help='how many pipelines we can spin up per language pair (default = 1)', type=int, default=1) parser.add_argument('-n', '--min-pipes-per-pair', - help='when shutting down pipelines, keep at least this many open per language pair (default = 0)', type=int, default=0) + help='when shutting down pipelines, keep at least this many' + ' open per language pair (default = 0)', type=int, default=0) parser.add_argument('-u', '--max-users-per-pipe', - help='how many concurrent requests per pipeline before we consider spinning up a new one (default = 5)', type=int, default=5) + help='how many concurrent requests per pipeline before we consider' + ' spinning up a new one (default = 5)', type=int, default=5) parser.add_argument('-m', '--max-idle-secs', help='if specified, shut down pipelines that have not been used in this many seconds', type=int, default=0) parser.add_argument('-r', '--restart-pipe-after', @@ -1407,7 +1411,8 @@ def apply_config(args, apySection): parser.add_argument('-V', '--version', help='show APY version', action='version', version="%(prog)s version " + __version__) parser.add_argument('-S', '--scalemt-logs', help='generates ScaleMT-like logs; use with --log-path; disables', action='store_true') parser.add_argument('-M', '--unknown-memory-limit', - help="keeps unknown words in memory until a limit is reached; use with --missing-freqs (default = 1000)", type=int, default=1000) + help='keeps unknown words in memory until a limit is reached; use' + ' with --missing-freqs (default = 1000)', type=int, default=1000) parser.add_argument('-T', '--stat-period-max-age', help='How many seconds back to keep track request timing stats (default = 3600)', type=int, default=3600) parser.add_argument('-wp', '--wiki-password', help="Apertium Wiki account password for SuggestionHandler", default=None) diff --git a/util.py b/util.py index 709a33e8e..55bf61cfb 100644 --- a/util.py +++ b/util.py @@ -145,7 +145,8 @@ def getCoverage(text, mode, modeDir, penalize=False): if len(lexicalUnits) and not penalize: return len(analyzedLexicalUnits) / len(lexicalUnits) elif len(lexicalUnits) and len(text) and penalize: - return len(analyzedLexicalUnits) / len(lexicalUnits) - (1 - sum([len(lexicalUnit[0].split('/')[0]) for lexicalUnit in lexicalUnits]) / len(text)) + return (len(analyzedLexicalUnits) / len(lexicalUnits) + - (1 - sum([len(lexicalUnit[0].split('/')[0]) for lexicalUnit in lexicalUnits]) / len(text))) else: return -1 From c162427e6843f3f5f73850a5a1b4a4397ab615f7 Mon Sep 17 00:00:00 2001 From: JPJPJPOPOP Date: Sun, 7 Jan 2018 00:24:53 -0800 Subject: [PATCH 05/11] Removed some non-needed changes. --- gateway.py | 9 ++++----- servlet.py | 15 +++++---------- util.py | 3 +-- 3 files changed, 10 insertions(+), 17 deletions(-) diff --git a/gateway.py b/gateway.py index 53a13a2d3..1aa263d60 100755 --- a/gateway.py +++ b/gateway.py @@ -84,9 +84,8 @@ def get(self): logging.info('Redirecting %s?%s to %s%s?%s' % (path, query, server_port, path, query)) http = tornado.httpclient.AsyncHTTPClient() - http.fetch(server_port + path + "?" + query, - functools.partial(self._on_download, (server, port), langPair), - validate_cert=verifySSLCert, headers=headers) + http.fetch(server_port + path + "?" + query, functools.partial(self._on_download, + (server, port), langPair), validate_cert=verifySSLCert, headers=headers) self.balancer.inform('start', (server, port), url=path) def _on_download(self, server, langPair, response): @@ -319,8 +318,8 @@ def inform(self, action, server, *args, **kwargs): if mode in self.serverlist: if action == 'complete': if self.serverlist[mode][server]: - self.serverlist[mode][server] = ((self.serverlist[mode][server] * - (self.numResponses - 1) + requestTime / responseLen) / self.numResponses) + self.serverlist[mode][server] = (self.serverlist[mode][server] * (self.numResponses - + 1) + requestTime / responseLen) / self.numResponses else: self.serverlist[mode][server] = requestTime / responseLen / self.numResponses elif action == 'drop': diff --git a/servlet.py b/servlet.py index 1c8f06ae4..2493bbfb8 100755 --- a/servlet.py +++ b/servlet.py @@ -1388,21 +1388,17 @@ def apply_config(args, apySection): parser.add_argument('-k', '--ssl-key', help='path to SSL Key File', default=None) parser.add_argument('-t', '--timeout', help='timeout for requests (default = 10)', type=int, default=10) parser.add_argument('-j', '--num-processes', - help='number of processes to run (default = 1; use 0 to run one http server per core,' - ' where each http server runs all available language pairs)', + help='number of processes to run (default = 1; use 0 to run one http server per core, where each http server runs all available language pairs)', nargs='?', type=int, default=1) parser.add_argument( - '-d', '--daemon', help='daemon mode: redirects stdout and stderr to files apertium-apy.log' - ' and apertium-apy.err ; use with --log-path', action='store_true') + '-d', '--daemon', help='daemon mode: redirects stdout and stderr to files apertium-apy.log and apertium-apy.err ; use with --log-path', action='store_true') parser.add_argument('-P', '--log-path', help='path to log output files to in daemon mode; defaults to local directory', default='./') parser.add_argument('-i', '--max-pipes-per-pair', help='how many pipelines we can spin up per language pair (default = 1)', type=int, default=1) parser.add_argument('-n', '--min-pipes-per-pair', - help='when shutting down pipelines, keep at least this many' - ' open per language pair (default = 0)', type=int, default=0) + help='when shutting down pipelines, keep at least this many open per language pair (default = 0)', type=int, default=0) parser.add_argument('-u', '--max-users-per-pipe', - help='how many concurrent requests per pipeline before we consider' - ' spinning up a new one (default = 5)', type=int, default=5) + help='how many concurrent requests per pipeline before we consider spinning up a new one (default = 5)', type=int, default=5) parser.add_argument('-m', '--max-idle-secs', help='if specified, shut down pipelines that have not been used in this many seconds', type=int, default=0) parser.add_argument('-r', '--restart-pipe-after', @@ -1411,8 +1407,7 @@ def apply_config(args, apySection): parser.add_argument('-V', '--version', help='show APY version', action='version', version="%(prog)s version " + __version__) parser.add_argument('-S', '--scalemt-logs', help='generates ScaleMT-like logs; use with --log-path; disables', action='store_true') parser.add_argument('-M', '--unknown-memory-limit', - help='keeps unknown words in memory until a limit is reached; use' - ' with --missing-freqs (default = 1000)', type=int, default=1000) + help='keeps unknown words in memory until a limit is reached; use with --missing-freqs (default = 1000)', type=int, default=1000) parser.add_argument('-T', '--stat-period-max-age', help='How many seconds back to keep track request timing stats (default = 3600)', type=int, default=3600) parser.add_argument('-wp', '--wiki-password', help="Apertium Wiki account password for SuggestionHandler", default=None) diff --git a/util.py b/util.py index 55bf61cfb..709a33e8e 100644 --- a/util.py +++ b/util.py @@ -145,8 +145,7 @@ def getCoverage(text, mode, modeDir, penalize=False): if len(lexicalUnits) and not penalize: return len(analyzedLexicalUnits) / len(lexicalUnits) elif len(lexicalUnits) and len(text) and penalize: - return (len(analyzedLexicalUnits) / len(lexicalUnits) - - (1 - sum([len(lexicalUnit[0].split('/')[0]) for lexicalUnit in lexicalUnits]) / len(text))) + return len(analyzedLexicalUnits) / len(lexicalUnits) - (1 - sum([len(lexicalUnit[0].split('/')[0]) for lexicalUnit in lexicalUnits]) / len(text)) else: return -1 From 7f2f7f5aa474a3003c4ef7a78be96477020acd02 Mon Sep 17 00:00:00 2001 From: JPJPJPOPOP Date: Sun, 7 Jan 2018 14:15:40 -0800 Subject: [PATCH 06/11] Fix mypy errors. --- mypy.ini | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 mypy.ini diff --git a/mypy.ini b/mypy.ini new file mode 100644 index 000000000..7c085c7d9 --- /dev/null +++ b/mypy.ini @@ -0,0 +1,4 @@ +[mypy] + +[mypy-streamparser] +ignore_errors = True From 998368a00cde7b3ccd9a4017cd30c32686ebb519 Mon Sep 17 00:00:00 2001 From: Sushain Cherivirala Date: Sun, 7 Jan 2018 16:20:47 -0600 Subject: [PATCH 07/11] Style --- servlet.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/servlet.py b/servlet.py index 2493bbfb8..73f24f508 100755 --- a/servlet.py +++ b/servlet.py @@ -28,7 +28,6 @@ from urllib.parse import urlparse, urlunsplit import zipfile -from streamparser.streamparser import parse, known import tornado from tornado import escape from tornado import gen @@ -44,20 +43,19 @@ from tornado.log import enable_pretty_logging except ImportError: # 2.1 from tornado.options import enable_pretty_logging # type: ignore +try: + import cld2full as cld2 # type: ignore +except ImportError as _e: + cld2 = None from modeSearch import searchPath from keys import getKey from util import (getLocalizedLanguages, stripTags, processPerWord, getCoverage, getCoverages, toAlpha3Code, toAlpha2Code, scaleMtLog, TranslationInfo, removeDotFromDeformat) - import systemd import missingdb import translation # type: ignore - -try: - import cld2full as cld2 # type: ignore -except ImportError as _e: - cld2 = None +from streamparser.streamparser import parse, known RECAPTCHA_VERIFICATION_URL = 'https://www.google.com/recaptcha/api/siteverify' bypassToken = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(24)) @@ -913,8 +911,6 @@ def get(self): class SpellerHandler(BaseHandler): - - @tornado.web.asynchronous @gen.coroutine def get(self): in_text = self.get_argument('q') + '*' From 2191c8838631549240cc9fbd5011b6c6d96e2893 Mon Sep 17 00:00:00 2001 From: JPJPJPOPOP Date: Sun, 7 Jan 2018 15:38:16 -0800 Subject: [PATCH 08/11] Fix review comments. --- modeSearch.py | 2 +- servlet.py | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/modeSearch.py b/modeSearch.py index 1708fc6dd..89ea10bf2 100644 --- a/modeSearch.py +++ b/modeSearch.py @@ -36,7 +36,7 @@ def searchPath(rootpath, include_pairs=True, verbosity=1): 'generator': re.compile(r'(({0}(-{0})?)-gener[A-z]*)\.mode'.format(lang_code)), 'tagger': re.compile(r'(({0}(-{0})?)-tagger)\.mode'.format(lang_code)), 'spell': re.compile(r'(({0}(-{0})?)-spell)\.mode'.format(lang_code)), - 'tokenise': re.compile(r'(({0}(-{0})?)-tokenise)\.mode'.format(lang_code)) + 'tokenise': re.compile(r'(({0}(-{0})?)-tokenise)\.mode'.format(lang_code)), } modes = { 'pair': [], diff --git a/servlet.py b/servlet.py index 73f24f508..6d123de10 100755 --- a/servlet.py +++ b/servlet.py @@ -298,7 +298,7 @@ def langs(foo): elif query == 'spellers': self.sendResponse({lang_src: modename for (lang_src, (path, modename)) in self.spellers.items()}) else: - self.send_error(400, explanation='Expecting q argument to be one of analysers, generators, disambiguators, or pairs') + self.send_error(400, explanation='Expecting q argument to be one of analysers, generators, spellers, disambiguators, or pairs') class StatsHandler(BaseHandler): @@ -934,12 +934,12 @@ def get(self): result = yield translation.translateSimple(token.wordform, commands) foundSugg = False - for line in result.split('\n'): + for line in result.splitlines(): if line.count('Corrections for'): foundSugg = True continue - if foundSugg and ' ' in line: - s, w = line.split(' ') + if foundSugg and '\t' in line: + s, w = line.split('\t') suggestion.append((s, w)) units.append({'token': token.wordform, 'known': False, 'sugg': suggestion}) @@ -1486,7 +1486,7 @@ def apply_config(args, apySection): (r'/getLocale', GetLocaleHandler), (r'/pipedebug', PipeDebugHandler), (r'/suggest', SuggestionHandler), - (r'/speller', SpellerHandler) + (r'/speller', SpellerHandler), ]) if args.bypass_token: From 9daf2eaaa232b92746801291fc727c537a36d948 Mon Sep 17 00:00:00 2001 From: JPJPJPOPOP Date: Sun, 7 Jan 2018 19:36:12 -0800 Subject: [PATCH 09/11] Fix logging. --- servlet.py | 1 - 1 file changed, 1 deletion(-) diff --git a/servlet.py b/servlet.py index 6d123de10..d6a9c22ae 100755 --- a/servlet.py +++ b/servlet.py @@ -946,7 +946,6 @@ def get(self): self.sendResponse(units) else: - logging.info('Spellchecker not working') self.send_error(404, explanation="{} on spellchecker mode: {}".format('Error 404', 'Mode not installed')) From 5cf827155581918e99e8d39d733970eff8562ad7 Mon Sep 17 00:00:00 2001 From: JPJPJPOPOP Date: Sun, 7 Jan 2018 20:20:10 -0800 Subject: [PATCH 10/11] Changed error message. --- servlet.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/servlet.py b/servlet.py index d6a9c22ae..c947b1e0e 100755 --- a/servlet.py +++ b/servlet.py @@ -946,7 +946,7 @@ def get(self): self.sendResponse(units) else: - self.send_error(404, explanation="{} on spellchecker mode: {}".format('Error 404', 'Mode not installed')) + self.send_error(404, explanation="{} on spellchecker mode: {}".format('Error 404', 'Spelling mode for ' + in_mode + ' is not installed')) class GenerateHandler(BaseHandler): From 802f5e8f1f542e00e50183a8181420fd6ccc71b3 Mon Sep 17 00:00:00 2001 From: JPJPJPOPOP Date: Mon, 8 Jan 2018 18:12:11 -0800 Subject: [PATCH 11/11] Add print statements. --- servlet.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/servlet.py b/servlet.py index c947b1e0e..800e0d990 100755 --- a/servlet.py +++ b/servlet.py @@ -916,9 +916,14 @@ def get(self): in_text = self.get_argument('q') + '*' in_mode = toAlpha3Code(self.get_argument('lang')) logging.info(in_text) + logging.info(self.get_argument('lang')) logging.info(in_mode) + logging.info(self.spellers) if in_mode in self.spellers: + logging.info(self.spellers[in_mode]) [path, mode] = self.spellers[in_mode] + logging.info(path) + logging.info(mode) formatting = 'none' commands = [['apertium', '-d', path, '-f', formatting, self.get_argument('lang')+'-tokenise']] result = yield translation.translateSimple(in_text, commands)