anorack-0.2.4/0000755000000000000000000000000013277621757013152 5ustar00rootroot00000000000000anorack-0.2.4/.coveragerc0000644000000000000000000000014113277621751015261 0ustar00rootroot00000000000000[run] branch = true [report] show_missing = true exclude_lines = # no coverage # vim:ft=dosini anorack-0.2.4/.pylintrc0000644000000000000000000000052613277621751015014 0ustar00rootroot00000000000000[MESSAGES CONTROL] disable = bad-continuation, duplicate-code, invalid-name, locally-disabled, no-else-return, too-few-public-methods, [REPORTS] reports = no msg-template = {C}: {path}:{line}: {symbol} [{obj}] {msg} [FORMAT] max-line-length = 120 expected-line-ending-format = LF # vim:ft=dosini ts=4 sts=4 sw=4 et anorack-0.2.4/Makefile0000644000000000000000000000413713277621751014611 0ustar00rootroot00000000000000# Copyright © 2012-2018 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. PYTHON = python3 INSTALL = install PREFIX = /usr/local DESTDIR = exe = anorack bindir = $(PREFIX)/bin basedir = $(PREFIX)/share/$(exe) mandir = $(PREFIX)/share/man .PHONY: all all: ; .PHONY: install install: # binary: $(INSTALL) -d -m755 $(DESTDIR)$(bindir) python_exe=$$($(PYTHON) -c 'import sys; print(sys.executable)') && \ sed \ -e "1 s@^#!.*@#!$$python_exe@" \ -e "s#^basedir = .*#basedir = '$(basedir)/'#" \ $(exe) > $(DESTDIR)$(bindir)/$(exe) chmod 0755 $(DESTDIR)$(bindir)/$(exe) # library + data: ( find lib data -type f ! -name '*.py[co]' ) \ | xargs -t -I {} $(INSTALL) -p -D -m644 {} $(DESTDIR)$(basedir)/{} ifeq "$(wildcard doc/$(exe).1)" "" # run "$(MAKE) -C doc" to build the manpage else # manual page: $(INSTALL) -p -D -m644 doc/$(exe).1 $(DESTDIR)$(mandir)/man1/$(exe).1 endif .PHONY: test test: $(PYTHON) -c 'import nose; nose.main()' --verbose .PHONY: clean clean: find . -type f -name '*.py[co]' -delete find . -type d -name '__pycache__' -delete # vim:ts=4 sts=4 sw=4 noet anorack-0.2.4/anorack0000755000000000000000000000250413277621751014511 0ustar00rootroot00000000000000#!/usr/bin/env python3 # Copyright © 2016 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import sys basedir = None if basedir is not None: sys.path[:0] = [basedir] import lib.cli # pylint: disable=wrong-import-position if __name__ == '__main__': lib.cli.main() # vim:ts=4 sts=4 sw=4 et anorack-0.2.4/data/0000755000000000000000000000000013277621751014055 5ustar00rootroot00000000000000anorack-0.2.4/data/overrides0000644000000000000000000000015513277621751016003 0ustar00rootroot00000000000000EWMH E.W.M.H UCS U.C.S UDP U.D.P UTF U.T.F UTS U.T.S UUID U.U.I.D unary [[j'un@ri]] [[jˈunəɹi]] usr U.S.R anorack-0.2.4/doc/0000755000000000000000000000000013277621757013717 5ustar00rootroot00000000000000anorack-0.2.4/doc/LICENSE0000644000000000000000000000207413277621751014721 0ustar00rootroot00000000000000Copyright © 2012-2018 Jakub Wilk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. anorack-0.2.4/doc/Makefile0000644000000000000000000000273113277621751015354 0ustar00rootroot00000000000000# Copyright © 2014-2017 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. export LC_ALL=C rst2man = $(or $(shell which rst2man),rst2man.py) exe = anorack .PHONY: all all: $(exe).1 $(exe).1: manpage.rst $(rst2man) --input-encoding=UTF-8 < $(<) > $(@).tmp perl -pi -e '/^[.]BI\b/ and s/\\fP/\\fR/g' $(@).tmp # work-around for https://bugs.debian.org/806601 mv $(@).tmp $(@) .PHONY: clean clean: rm -f $(exe).1 *.tmp # vim:ts=4 sts=4 sw=4 noet anorack-0.2.4/doc/README0000644000000000000000000000236013277621751014572 0ustar00rootroot00000000000000Overview ======== The English language has two indefinite articles: + *a*: used before words that begin with a consonant sound (e.g., *a program*, *a host*, *a user*); + *an*: used before words that begin with a vowel sound (e.g., *an example*, *an hour*, *an undefined variable*). **anorack** is a specialized spell-checker that finds incorrect indefinite articles: .. code:: console $ cat test a Ubuntu user a 8-byte word an username $ anorack test test:1: a Ubuntu -> an Ubuntu /u:b'u:ntu:/ test:2: a 8 -> an 8 /'eIt/ test:3: an username -> a username /j'u:z3n,eIm/ Prerequisites ============= * Python ≥ 3.2 * `eSpeak NG`_ or eSpeak_ ≥ 1.47.08 .. _eSpeak NG: https://github.com/espeak-ng/espeak-ng .. _eSpeak: http://espeak.sourceforge.net/ Installation ============ You can use anorack without installing it, straight out of unpacked source tarball or a VCS checkout. It's also possible to install it system-wide with: .. code:: console # make install By default, ``make install`` installs the package to ``/usr/local``. You can specify a different installation prefix by setting the ``PREFIX`` variable, e.g.: .. code:: console $ make install PREFIX="$HOME/.local" .. vim:ft=rst ts=3 sts=3 sw=3 et anorack-0.2.4/doc/anorack.10000644000000000000000000000363213277621757015423 0ustar00rootroot00000000000000.\" Man page generated from reStructuredText. . .TH ANORACK 1 "2017-10-04" "anorack 0.2.4" "" .SH NAME anorack \- “a” vs “an” checker . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .SH SYNOPSIS .sp \fBanorack\fP [\fIoption\fP\&...] [\fIfile\fP\&...] .SH DESCRIPTION .sp The English language has two indefinite articles: .INDENT 0.0 .IP \(bu 2 \fIa\fP: used before words that begin with a consonant sound (e.g., \fIa program\fP, \fIa host\fP, \fIa user\fP); .IP \(bu 2 \fIan\fP: used before words that begin with a vowel sound (e.g., \fIan example\fP, \fIan hour\fP, \fIan undefined variable\fP). .UNINDENT .sp \fBanorack\fP is a specialized spell\-checker that finds incorrect indefinite articles. .SH OPTIONS .INDENT 0.0 .TP .B \-h\fP,\fB \-\-help Show the help message and exit. .TP .B \-\-version Show the program\(aqs version information and exit. .TP .B \-\-ipa Print phonemes using IPA (International Phonetic Alphabet) instead of ASCII phoneme mnemonics. .UNINDENT .SH EXAMPLE .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ cat test a Ubuntu user a 8\-byte word an username $ anorack test test:1: a Ubuntu \-> an Ubuntu /u:b\(aqu:ntu:/ test:2: a 8 \-> an 8 /\(aqeIt/ test:3: an username \-> a username /j\(aqu:z3n,eIm/ .ft P .fi .UNINDENT .UNINDENT .SH SEE ALSO .sp \fBespeak\fP(1) .\" vim:ts=3 sts=3 sw=3 . .\" Generated by docutils manpage writer. . anorack-0.2.4/doc/changelog0000644000000000000000000000347313277621751015572 0ustar00rootroot00000000000000anorack (0.2.4) unstable; urgency=low * Reset the SIGPIPE signal disposition. * Improve the build system. -- Jakub Wilk Fri, 18 May 2018 21:05:06 +0200 anorack (0.2.3) unstable; urgency=low * Rewrite shebang at install time. * Make the doc makefile more portable. * Add installation instructions to README. * Improve the test suite. -- Jakub Wilk Wed, 22 Mar 2017 18:46:51 +0100 anorack (0.2.2) unstable; urgency=low * Fix compatibility with eSpeak >= 1.48.11. * Add support for eSpeak NG. * Put license into a separate file. -- Jakub Wilk Wed, 19 Oct 2016 20:11:33 +0200 anorack (0.2.1) unstable; urgency=low * Explain the grammar rules in README and in the manual page. * Don't disable stdout/stderr line buffering. -- Jakub Wilk Sun, 21 Aug 2016 21:31:00 +0200 anorack (0.2) unstable; urgency=low * Fix word-splitting for compounds that include numbers or underscores. This fixes, among others, false positives involving acronyms such as “a UTF16”. * Retain original article's case in correction. * Add option for printing phonemes using IPA (--ipa). * Add Makefile. * Use /usr/bin/env in shebang. -- Jakub Wilk Mon, 18 Jul 2016 12:12:40 +0200 anorack (0.1.1) unstable; urgency=low * Add the manual page. * Add N (ŋ) to the consonants set. * Allow quotation character between the article and the other word. * Fix false positives for the following phrases: + an EWMH + a UCS + a UDP + a UTF + a UTS + a UUID + a unary + a usr * Improve the test suite. -- Jakub Wilk Mon, 11 Jul 2016 21:42:44 +0200 anorack (0.1) unstable; urgency=low * Initial release. -- Jakub Wilk Mon, 04 Jul 2016 21:04:36 +0200 anorack-0.2.4/doc/manpage.rst0000644000000000000000000000213113277621751016050 0ustar00rootroot00000000000000======= anorack ======= ------------------- “a” vs “an” checker ------------------- :manual section: 1 :version: anorack 0.2.4 :date: 2017-10-04 Synopsis -------- **anorack** [*option*...] [*file*...] Description ----------- The English language has two indefinite articles: + *a*: used before words that begin with a consonant sound (e.g., *a program*, *a host*, *a user*); + *an*: used before words that begin with a vowel sound (e.g., *an example*, *an hour*, *an undefined variable*). **anorack** is a specialized spell-checker that finds incorrect indefinite articles. Options ------- -h, --help Show the help message and exit. --version Show the program's version information and exit. --ipa Print phonemes using IPA (International Phonetic Alphabet) instead of ASCII phoneme mnemonics. Example ------- :: $ cat test a Ubuntu user a 8-byte word an username $ anorack test test:1: a Ubuntu -> an Ubuntu /u:b'u:ntu:/ test:2: a 8 -> an 8 /'eIt/ test:3: an username -> a username /j'u:z3n,eIm/ See also -------- **espeak**\ (1) .. vim:ts=3 sts=3 sw=3 anorack-0.2.4/lib/0000755000000000000000000000000013277621751013712 5ustar00rootroot00000000000000anorack-0.2.4/lib/__init__.py0000644000000000000000000000005513277621751016023 0ustar00rootroot00000000000000''' anorack's private modules ''' type(...) anorack-0.2.4/lib/articles.py0000644000000000000000000000314013277621751016070 0ustar00rootroot00000000000000# Copyright © 2016 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' English articles ''' from lib import phonetics accents = ''.join(phonetics.accents) def choose_art(phonemes): ''' choose correct article for the phonemes: return "a" or "an" or NotImplemented ''' try: p = phonemes.strip(accents)[0] except IndexError: return NotImplemented if p in phonetics.consonants: return 'a' elif p in phonetics.vowels: return 'an' else: return NotImplemented __all__ = ['choose_art'] # vim:ts=4 sts=4 sw=4 et anorack-0.2.4/lib/cli.py0000644000000000000000000000733113277621751015037 0ustar00rootroot00000000000000# Copyright © 2016-2017 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' the command-line interface ''' import argparse import io import signal import sys from lib.articles import choose_art from lib.io import ( get_encoding, open_file, ) from lib.misc import coerce_case, warn from lib.parser import parse_file from lib.phonetics import init as init_phonetics, text_to_phonemes from lib.version import __version__ class VersionAction(argparse.Action): ''' argparse --version action ''' def __init__(self, option_strings, dest=argparse.SUPPRESS): super().__init__( option_strings=option_strings, dest=dest, nargs=0, help="show program's version information and exit" ) def __call__(self, parser, namespace, values, option_string=None): from lib import espeak print('{prog} {0}'.format(__version__, prog=parser.prog)) print('+ Python {0}.{1}.{2}'.format(*sys.version_info)) print('+ eSpeak{ng} {0}'.format( espeak.version, ng=(' NG' if espeak.ng else '') )) parser.exit() def check_word(loc, art, word, *, ipa=False): ''' check if the word has correct article ''' phon = text_to_phonemes(word, ipa=ipa) correct_art = choose_art(phon) if correct_art is NotImplemented: warn("can't determine correct article for {word!r} /{phon}/".format(word=word, phon=phon)) elif art.lower() != correct_art: correct_art = coerce_case(art, correct_art) print('{loc}: {art} {word} -> {cart} {word} /{phon}/'.format( loc=loc, art=art, cart=correct_art, word=word, phon=phon, )) def main(): ''' run the program ''' signal.signal(signal.SIGPIPE, signal.SIG_DFL) ap = argparse.ArgumentParser(description='"a" vs "an" checker') ap.add_argument('--version', action=VersionAction) ap.add_argument('--ipa', action='store_true', help='use IPA instead of phoneme mnemonics') ap.add_argument('files', metavar='FILE', nargs='*', default=['-'], help='file to check (default: stdin)') options = ap.parse_args() encoding = get_encoding() sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding, line_buffering=sys.stdout.line_buffering) sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding, line_buffering=sys.stdout.line_buffering) init_phonetics() for path in options.files: file = open_file(path, encoding=encoding, errors='replace') with file: for loc, art, word in parse_file(file): check_word(loc, art, word, ipa=options.ipa) __all__ = ['main'] # vim:ts=4 sts=4 sw=4 et anorack-0.2.4/lib/espeak.py0000644000000000000000000001076013277621751015540 0ustar00rootroot00000000000000# Copyright © 2016 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' interface to eSpeak (NG) ''' import ctypes import distutils.version try: _shlib = ctypes.CDLL('libespeak-ng.so.1') ng = True # no coverage except OSError: _shlib = ctypes.CDLL('libespeak.so.1') ng = False # const char *espeak_Info(const char **path_data) _info = _shlib.espeak_Info _info.argtypes = [ctypes.POINTER(ctypes.c_char_p)] _info.restype = ctypes.c_char_p def info(): ''' return eSpeak version information ''' dummy = ctypes.c_char_p(b'') res = _info(ctypes.byref(dummy)) return res.decode('ASCII') version = distutils.version.LooseVersion(info().split()[0]) del info # int espeak_Initialize(espeak_AUDIO_OUTPUT output, int buflength, const char *path, int options) _initialize = _shlib.espeak_Initialize _initialize.argtypes = [ctypes.c_int, ctypes.c_int, ctypes.c_char_p, ctypes.c_int] _initialize.restype = ctypes.c_int def init(): ''' initialize eSpeak ''' rc = _initialize(0, 0, None, 0) if rc <= 0: raise RuntimeError('espeak_Initialize(): internal error') # no coverage # espeak_ERROR espeak_SetVoiceByName(const char *name) _set_voice_by_name = _shlib.espeak_SetVoiceByName _set_voice_by_name.argtypes = [ctypes.c_char_p] _set_voice_by_name.restype = ctypes.c_int def set_voice_by_name(s): ''' use this voice for synthesis ''' s = s.encode('ASCII') rc = _set_voice_by_name(s) if rc == 0: return else: # no coverage if rc == -1: msg = 'internal error' elif rc == 1: msg = 'the command could not be buffered' else: msg = 'unknown error {}'.format(rc) raise RuntimeError('espeak_SetVoiceByName(): ' + msg) if version >= '1.48.1': # const char *espeak_TextToPhonemes(const void **textptr, int textmode, int phonememode) _text_to_phonemes = _shlib.espeak_TextToPhonemes _text_to_phonemes.restype = ctypes.c_char_p _text_to_phonemes.argtypes = [ctypes.POINTER(ctypes.c_char_p), ctypes.c_int, ctypes.c_int] def text_to_phonemes(s, *, ipa=False): ''' translate text to phonemes ''' s = s.encode('UTF-8') z = ctypes.c_char_p(s) zptr = ctypes.pointer(z) assert zptr.contents is not None if version >= '1.48.11': ipa = ipa << 1 # no coverage else: ipa = ipa << 4 res = _text_to_phonemes(zptr, 1, ipa) if zptr.contents.value is not None: raise RuntimeError # no coverage return res.decode('UTF-8').strip() elif version >= '1.47.08': # no coverage # void espeak_TextToPhonemes(const void *text, char *buffer, int size, int textmode, int phonememode) _text_to_phonemes = _shlib.espeak_TextToPhonemes _text_to_phonemes.restype = ctypes.c_char_p _text_to_phonemes.argtypes = [ ctypes.c_char_p, ctypes.POINTER(ctypes.c_char), ctypes.c_int, ctypes.c_int, ctypes.c_int ] def text_to_phonemes(s, *, ipa=False): ''' translate text to phonemes ''' s = s.encode('UTF-8') bufsize = 250 buf = ctypes.create_string_buffer(bufsize) _text_to_phonemes(s, buf, bufsize, 1, ipa << 4) return buf.value.decode('UTF-8').strip() else: # no coverage raise RuntimeError('eSpeak >= 1.47.08 is required') __all__ = [ 'init', 'ng', 'set_voice_by_name', 'text_to_phonemes', 'version', ] # vim:ts=4 sts=4 sw=4 et anorack-0.2.4/lib/io.py0000644000000000000000000000376513277621751014706 0ustar00rootroot00000000000000# Copyright © 2016 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' I/O and encodings ''' import codecs import io import sys def enc_eq(e1, e2): ''' check if two encodings are equal ''' return ( codecs.lookup(e1).name == codecs.lookup(e2).name ) def get_encoding(): ''' get locale encoding (from sys.stdout); upgrade ASCII to UTF-8 ''' locale_encoding = sys.stdout.encoding if enc_eq(locale_encoding, 'ASCII'): return 'UTF-8' else: return locale_encoding def open_file(path, *, encoding, errors): ''' open() with special case for "-" ''' if path == '-': return io.TextIOWrapper( sys.stdin.buffer, encoding=encoding, errors=errors, ) else: return open( path, 'rt', encoding=encoding, errors=errors, ) __all__ = [ 'get_encoding', 'open_file', ] # vim:ts=4 sts=4 sw=4 et anorack-0.2.4/lib/misc.py0000644000000000000000000000343013277621751015217 0ustar00rootroot00000000000000# Copyright © 2016 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' miscellanea ''' import os import sys def warn(msg): ''' print warning message ''' prog = os.path.basename(sys.argv[0]) print('{prog}: warning: {msg}'.format(prog=prog, msg=msg), file=sys.stderr) def _coerce_case(src, word): ''' coerce word to the same case as src (simple version doesn't support title-case) ''' if src.isupper(): return word.upper() else: return word.lower() def coerce_case(src, word): ''' coerce word to the same case as src ''' return ( _coerce_case(src[:1], word[:1]) + _coerce_case(src[1:], word[1:]) ) __all__ = [ 'warn', 'coerce_case', ] # vim:ts=4 sts=4 sw=4 et anorack-0.2.4/lib/parser.py0000644000000000000000000000411213277621751015556 0ustar00rootroot00000000000000# Copyright © 2016 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' English parser ''' import re class Location(object): ''' location in a file ''' def __init__(self, file, lineno): self.file = file self.lineno = lineno def __str__(self): return '{path}:{n}'.format(path=self.file.name, n=self.lineno) find_articles = re.compile( r'''\b(an?)\s+(?:['‘"“]\s*)?(\d+|[^\W\d_]+)|\b(an?)\s*$''', re.IGNORECASE ).finditer def parse_file(file): ''' parse the file: return sequence of (,
, ) tuples ''' carry = '' for i, line in enumerate(file, start=1): cline = carry + line carry = '' for match in find_articles(cline): art, word, eol_art = match.groups() if art is not None: assert word is not None yield (Location(file, i), art, word) else: assert eol_art is not None carry = eol_art + ' ' __all__ = ['parse_file'] # vim:ts=4 sts=4 sw=4 et anorack-0.2.4/lib/phonetics.py0000644000000000000000000000473413277621751016270 0ustar00rootroot00000000000000# Copyright © 2016 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' English phonetics ''' import functools import os consonants = frozenset( 'DNSTZbdfghjklmnprstvwz' 'ðŋʃθʒbdfɡhjkɬmnpɹstvwz' ) vowels = frozenset( '03@AEIOUVaeiou' 'ɒɜəɑɛɪɔʊʌɐeiɔu' ) accents = frozenset( ",'" "ˌˈ" ) espeak = None overrides = {} def init(): ''' initialize underlying speech engine ''' global espeak # pylint: disable=global-statement from lib import espeak # pylint: disable=redefined-outer-name espeak.init() espeak.set_voice_by_name('en') here = os.path.dirname(__file__) # Ideally false positives should be fixed in eSpeak, # but as a stop-gap measure, we carry data file to correct some of them. path = '{here}/../data/overrides'.format(here=here) with open(path, 'rt', encoding='UTF-8') as file: for line in file: line = line.strip() (word, phon) = line.split('\t', 1) word = word.lower() overrides[word] = phon @functools.lru_cache(maxsize=9999) def text_to_phonemes(s, *, ipa=False): ''' translate text to phonemes ''' s = overrides.get(s.lower(), s) if s.startswith('[[') and s.endswith(']]'): return s.split('\t')[ipa][2:-2] else: return espeak.text_to_phonemes(s, ipa=ipa) __all__ = [ 'consonants', 'vowels', 'accents', 'text_to_phonemes', ] # vim:ts=4 sts=4 sw=4 et anorack-0.2.4/lib/version.py0000644000000000000000000000007213277621751015750 0ustar00rootroot00000000000000# pylint: disable=missing-docstring __version__ = '0.2.4' anorack-0.2.4/private/0000755000000000000000000000000013277621757014624 5ustar00rootroot00000000000000anorack-0.2.4/private/check-rst0000755000000000000000000000301213277621751016423 0ustar00rootroot00000000000000#!/bin/sh # Copyright © 2016-2018 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. here=$(dirname "$0") rst2xml=$(command -v rst2xml) \ || rst2xml=$(command -v rst2xml.py) \ || { printf 'rst2xml not found\n' >&2; exit 1; } options='--input-encoding=UTF-8 --output-encoding=UTF-8 --strict' if [ $# -eq 0 ] then find "$here/.." -type f -name '*.rst' grep -rwl 'ft[=]rst' "$here/.." else printf '%s\n' "$@" fi | xargs -L1 -t -I{} "$rst2xml" $options {} /dev/null # vim:ts=4 sts=4 sw=4 et anorack-0.2.4/private/run-pylint0000755000000000000000000000326513277621751016673 0ustar00rootroot00000000000000#!/bin/sh # Copyright © 2015-2018 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. set -e -u PYTHON=${PYTHON:-python3} "$PYTHON" -m pylint --version >/dev/null || exit 1 if [ $# -eq 0 ] then pyscripts=$(grep -l -r '^#!.*python' .) set -- lib tests $pyscripts fi if [ -n "${VIRTUAL_ENV:-}" ] then # https://github.com/PyCQA/pylint/issues/73 set -- --ignored-modules=distutils "$@" fi set -- --load-plugins=pylint.extensions.check_elif "$@" log=$(mktemp -t pylint.XXXXXX) "$PYTHON" -m pylint "$@" > "$log" || [ $? != 1 ] ! grep '^\w:' "$log" \ | grep -v -P '^\w: (?!lib/).*: missing-docstring ' \ | grep '.' || exit 1 rm "$log" # vim:ts=4 sts=4 sw=4 et anorack-0.2.4/private/update-coverage0000755000000000000000000000423413277621751017622 0ustar00rootroot00000000000000#!/usr/bin/env python3 # Copyright © 2014 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import io import os import sys import nose import nose.plugins.cover class Coverage(nose.plugins.cover.Coverage): stream = None def report(self, stream): return super().report(self.stream) basedir = os.path.join( os.path.dirname(__file__), os.pardir, ) def main(): argv = [ sys.argv[0], '--with-coverage', '--cover-package=lib', '--cover-erase', ] path = os.path.join( 'tests', 'coverage' ) plugin = Coverage() report_stream = plugin.stream = io.StringIO() print( 'Generated automatically by private/update-coverage. ' 'Do not edit.\n', file=report_stream ) ok = nose.run(argv=argv, plugins=[plugin]) if not ok: sys.exit(1) report_stream.seek(0) with open(path + '.tmp', 'wt', encoding='ASCII') as file: for line in report_stream: line = line.rstrip() print(line, file=file) os.rename(path + '.tmp', path) if __name__ == '__main__': main() # vim:ts=4 sts=4 sw=4 et anorack-0.2.4/private/update-version0000755000000000000000000000054713277621751017517 0ustar00rootroot00000000000000#!/bin/sh set -e -u version=${1:?"no version number provided"} date="$(date -u --rfc-3339=date)" PS4='$ ' set -x dch -m -v "$version" -u low -c doc/changelog export version date perl -pi -e 's/^__version__ = '"'"'\K[\w.]+/$ENV{version}/' lib/version.py perl -pi -e 's/^:version: \S+ \K[\w.]+/$ENV{version}/; s/^(:date:) \K[0-9-]+/$ENV{date}/' doc/manpage.rst anorack-0.2.4/tests/0000755000000000000000000000000013277621751014306 5ustar00rootroot00000000000000anorack-0.2.4/tests/__init__.py0000644000000000000000000000004513277621751016416 0ustar00rootroot00000000000000type(...) # Python >= 3 is required anorack-0.2.4/tests/coverage0000644000000000000000000000142113277621751016022 0ustar00rootroot00000000000000Generated automatically by private/update-coverage. Do not edit. Name Stmts Miss Branch BrPart Cover Missing -------------------------------------------------------------- lib/__init__.py 1 0 0 0 100% lib/articles.py 14 0 4 0 100% lib/cli.py 45 0 8 0 100% lib/espeak.py 46 0 0 0 100% lib/io.py 16 0 4 0 100% lib/misc.py 13 0 2 0 100% lib/parser.py 22 0 6 0 100% lib/phonetics.py 27 0 4 0 100% lib/version.py 1 0 0 0 100% -------------------------------------------------------------- TOTAL 185 0 28 0 100% anorack-0.2.4/tests/test_choose_art.py0000644000000000000000000000326513277621751020053 0ustar00rootroot00000000000000# Copyright © 2016 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. from nose.tools import ( assert_equal, ) import lib.articles as M def test_choose_a(): art = M.choose_art("sp'am") assert_equal(art, 'a') def test_choose_a_ipa(): art = M.choose_art("θˈɜːmɪdˌɔː") assert_equal(art, 'a') def test_choose_an(): art = M.choose_art("'Eg") assert_equal(art, 'an') def test_choose_an_ipa(): art = M.choose_art("ˈɛɡ") assert_equal(art, 'an') def test_choose_other(): art = M.choose_art('%') assert_equal(art, NotImplemented) art = M.choose_art('') assert_equal(art, NotImplemented) # vim:ts=4 sts=4 sw=4 et anorack-0.2.4/tests/test_cli.py0000644000000000000000000001272013277621751016470 0ustar00rootroot00000000000000# Copyright © 2016 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import contextlib import io import os import sys import tempfile try: import unittest.mock as mock except ImportError: import mock # pylint: disable=import-error from nose.tools import ( assert_equal, assert_not_equal, ) from tests.tools import isolation @contextlib.contextmanager def tmpcwd(): with tempfile.TemporaryDirectory(prefix='anorack.tests.') as tmpdir: orig_cwd = os.getcwd() os.chdir(tmpdir) try: yield finally: os.chdir(orig_cwd) def TextIO(s=None, *, name): fp = io.BytesIO(s) fp.name = name return io.TextIOWrapper(fp, encoding='UTF-8') def __run_main(argv, stdin): sys.argv = argv if stdin is not None: if isinstance(stdin, str): stdin = stdin.encode('UTF-8') sys.stdin = mock_stdin = TextIO(stdin, name=sys.__stdin__.name) else: mock_stdin = None sys.stdout = mock_stdout = TextIO(name=sys.__stdout__.name) sys.stderr = mock_stderr = TextIO(name=sys.__stderr__.name) import lib.cli try: lib.cli.main() except SystemExit as exc: if exc.code != 0: raise for fp in (sys.stdout, sys.stderr): fp.flush() s = fp.buffer.getvalue() # pylint: disable=no-member yield s.decode('UTF-8') del mock_stdin, mock_stdout, mock_stderr def _run_main(argv, stdin): # abuse mock to save&restore sys.argv, sys.stdin, etc.: with mock.patch.multiple(sys, argv=None, stdin=None, stdout=None, stderr=None): return tuple(__run_main(argv, stdin)) run_main = isolation(_run_main) def t(*, stdin=None, files=None, stdout, stdout_ipa=None, stderr='', stderr_ipa=None): if stdout_ipa is None: stdout_ipa = stdout if stderr_ipa is None: stderr_ipa = stderr argv = ['anorack'] if files is not None: for (name, content) in files: with open(name, 'wt', encoding='UTF-8') as file: file.write(content) argv += [name] (actual_stdout, actual_stderr) = run_main(argv, stdin) if '-@' in stdout: stdout = stdout.replace('-@', '@') actual_stdout = actual_stdout.replace('-@', '@') assert_equal(stdout, actual_stdout) assert_equal(stderr, actual_stderr) argv += ['--ipa'] (actual_stdout, actual_stderr) = run_main(argv, stdin) actual_stderr = actual_stderr.replace('t͡ʃ', 'tʃ') assert_equal(stdout_ipa, actual_stdout) assert_equal(stderr_ipa, actual_stderr) def test_stdin(): t( stdin=( 'It could be carried by an African swallow!\n' 'Oh, yeah, a African swallow maybe, but not an\n' 'European swallow.\n' ), stdout=( ":2: a African -> an African /'afrIk@n/\n" ":3: an European -> a European /j,U@r-@p'i@n/\n" ), stdout_ipa=( ":2: a African -> an African /ˈafɹɪkən/\n" ":3: an European -> a European /jˌʊəɹəpˈiən/\n" ), ) @tmpcwd() def test_files(): t( files=( ('holy', 'It could be carried by a African swallow!'), ('grail', 'Oh, yeah, an African swallow maybe, but not an European swallow.'), ), stdout=( "holy:1: a African -> an African /'afrIk@n/\n" "grail:1: an European -> a European /j,U@r-@p'i@n/\n" ), stdout_ipa=( "holy:1: a African -> an African /ˈafɹɪkən/\n" "grail:1: an European -> a European /jˌʊəɹəpˈiən/\n" ), ) def test_warning(): def dummy_choose_art(phon): # pylint: disable=unused-argument return NotImplemented with mock.patch('lib.cli.choose_art', dummy_choose_art): t( stdin='A scratch?!', stdout='', stderr="anorack: warning: can't determine correct article for 'scratch' /skr'atS/\n", stderr_ipa="anorack: warning: can't determine correct article for 'scratch' /skɹˈatʃ/\n", ) def test_changelog(): argv = ['anorack', 'doc/changelog'] (actual_stdout, actual_stderr) = run_main(argv, None) assert_equal('', actual_stdout) assert_equal('', actual_stderr) def test_version(): argv = ['anorack', '--version'] (actual_stdout, actual_stderr) = run_main(argv, None) assert_not_equal('', actual_stdout) assert_equal('', actual_stderr) # vim:ts=4 sts=4 sw=4 et anorack-0.2.4/tests/test_coerce_case.py0000644000000000000000000000301713277621751020153 0ustar00rootroot00000000000000# Copyright © 2016 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. from nose.tools import ( assert_equal, ) import lib.misc as M def t(src, word, exp): res = M.coerce_case(src, word) assert_equal(exp, res) def test_a(): t('a', 'a', 'a') t('A', 'a', 'A') t('an', 'a', 'a') t('An', 'a', 'A') t('AN', 'a', 'A') def test_an(): t('a', 'an', 'an') t('A', 'an', 'An') t('an', 'an', 'an') t('An', 'an', 'An') t('AN', 'an', 'AN') # vim:ts=4 sts=4 sw=4 et anorack-0.2.4/tests/test_get_encoding.py0000644000000000000000000000323213277621751020344 0ustar00rootroot00000000000000# Copyright © 2016 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. try: import unittest.mock as mock except ImportError: import mock # pylint: disable=import-error from nose.tools import ( assert_equal, ) import lib.io as M def t(src, dst): class mock_stdout: encoding = src with mock.patch('sys.stdout', mock_stdout): encoding = M.get_encoding() assert_equal(encoding, dst) def test_ascii(): t('ANSI_X3.4-1968', 'UTF-8') t('US-ASCII', 'UTF-8') t('ASCII', 'UTF-8') def test_8bit(): t('ISO-8859-2', 'ISO-8859-2') def test_utf8(): t('UTF-8', 'UTF-8') # vim:ts=4 sts=4 sw=4 et anorack-0.2.4/tests/test_open_file.py0000644000000000000000000000277313277621751017670 0ustar00rootroot00000000000000# Copyright © 2016 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import os from nose.tools import ( assert_equal, ) import lib.io as M def t(path): encoding = 'ISO-8859-2' errors = 'xmlcharrefreplace' with M.open_file(path, encoding=encoding, errors=errors) as file: assert_equal(file.encoding, encoding) assert_equal(file.errors, errors) def test_open_real_file(): t(os.devnull) def test_open_stdin(): t('-') # vim:ts=4 sts=4 sw=4 et anorack-0.2.4/tests/test_parse_file.py0000644000000000000000000000463713277621751020042 0ustar00rootroot00000000000000# Copyright © 2016 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import io from nose.tools import ( assert_equal, assert_is, assert_is_instance, ) import lib.parser as M def t(s, exp): if isinstance(exp, tuple): exp = [exp] file = io.StringIO(s) result = list(M.parse_file(file)) assert_equal(len(result), len(exp)) for (loc, art, word), (xi, xart, xword) in zip(result, exp): assert_is_instance(loc, M.Location) assert_is(loc.file, file) assert_equal(loc.lineno, xi) assert_equal(xart, art) assert_equal(xword, word) def test_mid_line(): t('Oh, yeah, an African swallow maybe,\nbut not a European swallow.\n', [ (1, 'an', 'African'), (2, 'a', 'European'), ]) def test_wrapped(): t('I thought we were an\nautonomous collective.', (2, 'an', 'autonomous')) def test_quotes(): t( "a 'scratch'\n" 'a ‘scratch’\n' 'a "scratch"\n' 'a “scratch”\n', [(i, 'a', 'scratch') for i in range(1, 5)] ) def test_underscore(): t('a European_swallow', (1, 'a', 'European')) def test_numbers(): t('an 8', (1, 'an', '8')) t('an 8bit', (1, 'an', '8')) t('an 8-bit', (1, 'an', '8')) t('an 8 bit', (1, 'an', '8')) t('a UTF16', (1, 'a', 'UTF')) t('a UTF-16', (1, 'a', 'UTF')) t('a UTF 16', (1, 'a', 'UTF')) # vim:ts=4 sts=4 sw=4 et anorack-0.2.4/tests/test_phonetics.py0000644000000000000000000000414213277621751017714 0ustar00rootroot00000000000000# Copyright © 2016 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import functools from nose.tools import ( assert_equal, ) from tests.tools import isolation import lib.phonetics as M def __test(word, xphon, xipa): M.init() phon = M.text_to_phonemes(word) assert_equal(xphon, phon) ipa = M.text_to_phonemes(word, ipa=True) ipa = ipa.replace('t͡ʃ', 'tʃ') assert_equal(xipa, ipa) _test = isolation(__test) def test_overrides(): def t(word, xphon, xipa): return ( functools.partial(_test, xphon=xphon, xipa=xipa), word ) yield t('EWMH', ",i:d,Vb@Lj,u:,Em'eItS", 'ˌiːdˌʌbəljˌuːˌɛmˈeɪtʃ') yield t('UCS', "j,u:s,i:;'Es", 'jˌuːsˌiːˈɛs') yield t('UDP', "j,u:d,i:p'i:", 'jˌuːdˌiːpˈiː') yield t('UTF', "j,u:t,i:;'Ef", 'jˌuːtˌiːˈɛf') yield t('UTS', "j,u:t,i:;'Es", 'jˌuːtˌiːˈɛs') yield t('UUID', "j,u:j,u:,aId'i:", 'jˌuːjˌuːˌaɪdˈiː') yield t('unary', "j'un@ri", "jˈunəɹi") yield t('usr', "j,u:,Es'A@", "jˌuːˌɛsˈɑː") # vim:ts=4 sts=4 sw=4 et anorack-0.2.4/tests/test_version.py0000644000000000000000000000304413277621751017405 0ustar00rootroot00000000000000# Copyright © 2012-2013 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import os from nose.tools import ( assert_equal, ) from lib.version import __version__ here = os.path.dirname(__file__) docdir = os.path.join(here, os.pardir, 'doc') def test_changelog(): path = os.path.join(docdir, 'changelog') with open(path, 'rt', encoding='UTF-8') as file: line = file.readline() changelog_version = line.split()[1].strip('()') assert_equal(changelog_version, __version__) # vim:ts=4 sts=4 sw=4 et anorack-0.2.4/tests/test_warn.py0000644000000000000000000000316713277621751016675 0ustar00rootroot00000000000000# Copyright © 2016 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import io try: import unittest.mock as mock except ImportError: import mock # pylint: disable=import-error from nose.tools import ( assert_equal, ) import lib.misc as M def test_warn(): stderr = io.StringIO() with mock.patch('sys.stderr', stderr): with mock.patch('sys.argv', ['/usr/bin/anorack']): M.warn('NOBODY expects the Spanish Inquisition!') assert_equal( stderr.getvalue(), 'anorack: warning: NOBODY expects the Spanish Inquisition!\n' ) # vim:ts=4 sts=4 sw=4 et anorack-0.2.4/tests/tools.py0000644000000000000000000000314713277621751016025 0ustar00rootroot00000000000000# Copyright © 2016 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import concurrent.futures import functools import sys def isolation(f): if 'coverage' in sys.modules: # Process isolation would break coverage measurements. # Oh well. FIXME. return f else: @functools.wraps(f) def wrapper(*args, **kwargs): with concurrent.futures.ProcessPoolExecutor() as executor: ftr = executor.submit(f, *args, **kwargs) return ftr.result() return wrapper __all__ = ['isolation'] # vim:ts=4 sts=4 sw=4 et