| # Liblouis Python ctypes bindings |
| # |
| # Copyright (C) 2009-2010 James Teh <jamie@jantrid.net> |
| # Copyright (C) 2010-2012 Michael Whapples <mwhapples@gmail.com> |
| # Copyright (C) 2012-2024 Christian Egli <christian.egli@sbs.ch> |
| # Copyright (C) 2015-2016 Davy Kager <mail@davykager.nl> |
| # Copyright (C) 2016 matt venn <matt@mattvenn.net> |
| # Copyright (C) 2018-2025 Leonard de Ruijter <alderuijter@gmail.com> |
| # Copyright (C) 2018 Bue Vester-Andersen <bue@vester-andersen.dk> |
| # Copyright (C) 2019 Dave Mielke <dave@mielke.cc> |
| # Copyright (C) 2019-2020 André-Abush Clause <dev@andreabc.net> |
| # Copyright (C) 2019 Bert Frees <bertfrees@gmail.com> |
| # Copyright (C) 2023 Rob Beezer <beezer@ups.edu> |
| # Copyright (C) 2024 Daniel Garcia Moreno <daniel.garcia@suse.com> |
| # |
| # This file is part of liblouis. |
| # |
| # liblouis is free software: you can redistribute it and/or modify it |
| # under the terms of the GNU Lesser General Public License as published |
| # by the Free Software Foundation, either version 2.1 of the License, or |
| # (at your option) any later version. |
| # |
| # liblouis is distributed in the hope that it will be useful, but |
| # WITHOUT ANY WARRANTY; without even the implied warranty of |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| # Lesser General Public License for more details. |
| # |
| # You should have received a copy of the GNU Lesser General Public |
| # License along with liblouis. If not, see <http://www.gnu.org/licenses/>. |
| # |
| |
| """Liblouis Python ctypes bindings |
| These bindings allow you to use the liblouis braille translator and back-translator library |
| from within Python. |
| This documentation is only related to the Python helper. |
| Please see the liblouis documentation for more information. |
| |
| Most of these functions take a C{tableList} argument which specifies |
| a list of translation tables to use. Please see the liblouis documentation |
| concerning the C{tableList} parameter to the C{lou_translateString} |
| function for information about how liblouis searches for these tables. |
| |
| :author: Michael Curran <mick@kulgan.net> |
| :author: James Teh <jamie@jantrid.net> |
| :author: Eitan Isaacson <eitan@ascender.com> |
| :author: Michael Whapples <mwhapples@aim.com> |
| :author: Davy Kager <mail@davykager.nl> |
| :author: Leonard de Ruijter <alderuijter@gmail.com> |
| :author: Babbage B.V. <info@babbage.com> |
| :author: Andre-Abush Clause <dev@andreabc.net> |
| """ |
| |
| from atexit import register |
| from collections.abc import Generator, Iterable, Sequence |
| from ctypes import ( |
| Array, |
| CFUNCTYPE, |
| POINTER, |
| c_char, |
| c_char_p, |
| c_int, |
| c_ushort, |
| cdll, |
| create_string_buffer, |
| string_at, |
| ) |
| from sys import ( |
| byteorder, |
| getdefaultencoding, |
| getfilesystemencoding, |
| platform, |
| ) |
| |
| try: # Native win32 |
| from ctypes import WINFUNCTYPE, windll |
| |
| _loader, _functype = windll, WINFUNCTYPE |
| except ImportError: # Unix/Cygwin |
| _loader, _functype = cdll, CFUNCTYPE |
| liblouis = _loader["###LIBLOUIS_SONAME###"] |
| _is_windows = platform == "win32" |
| _endianness = "be" if byteorder == "big" else "le" |
| |
| # { Module Configuration |
| wideCharBytes: int = liblouis.lou_charSize() |
| """ |
| Specifies the charSize (in bytes) used by liblouis. |
| This is fetched once using `liblouis.lou_charSize`. |
| Call it directly, since `charSize` is not yet defined. |
| """ |
| outlenMultiplier: int = 4 + wideCharBytes * 2 |
| """ |
| Specifies the number by which the input length should be multiplied |
| to calculate the maximum output length. |
| The default will handle the case where every input character is |
| undefined in the translation table. |
| """ |
| fileSystemEncoding: str = "mbcs" if _is_windows else getfilesystemencoding() |
| """Specifies the encoding to use when encode/decode file/dir name.""" |
| conversionEncoding: str = "utf_%d_%s" % (wideCharBytes * 8, _endianness) |
| """Specifies the encoding to use when converting from byte strings to unicode strings.""" |
| |
| |
| # Some general utility functions |
| TableListT = list[str | bytes] |
| |
| |
| def _createTableBuf(tablesList: TableListT) -> Array[c_char]: |
| """Creates a tables string for liblouis calls""" |
| return create_string_buffer( |
| b",".join( |
| [ |
| x.encode(fileSystemEncoding) if isinstance(x, str) else bytes(x) |
| for x in tablesList |
| ] |
| ) |
| ) |
| |
| |
| def _createTypeformbuf( |
| length: int, |
| typeform: Iterable[int] | None = None, |
| ) -> Array[c_ushort]: |
| """Creates a typeform buffer for liblouis calls""" |
| return (c_ushort * length)(*typeform) if typeform else (c_ushort * length)() |
| |
| |
| ENCODING_ERROR_HANDLER = "surrogatepass" |
| |
| |
| def _createEncodedBuf( |
| x: str, |
| encoding: str = conversionEncoding, |
| errors: str = ENCODING_ERROR_HANDLER, |
| ) -> Array[c_char]: |
| return create_string_buffer(x.encode(encoding, errors)) |
| |
| |
| def _processTableFiles(stringArray: Sequence[bytes] | None) -> Generator[str]: |
| if not stringArray: |
| return |
| i = 0 |
| while stringArray[i] is not None: |
| yield stringArray[i].decode(fileSystemEncoding, errors=ENCODING_ERROR_HANDLER) |
| i += 1 |
| liblouis.lou_freeTableFiles(stringArray) |
| |
| |
| def _createQueryStringBuf(dct: dict[str, str]) -> Array[c_char]: |
| """Create a query string from a dictionary""" |
| if not isinstance(dct, dict): |
| raise TypeError("Query should be a dictionary") |
| return create_string_buffer( |
| " ".join( |
| f"{k}:{v}" |
| for k, v in dct.items() |
| if isinstance(k, str) and isinstance(v, str) |
| ).encode(getdefaultencoding(), errors=ENCODING_ERROR_HANDLER) |
| ) |
| |
| |
| register(liblouis.lou_free) |
| |
| liblouis.lou_version.restype = c_char_p |
| liblouis.lou_version.argtypes = () |
| |
| liblouis.lou_charSize.restype = c_int |
| liblouis.lou_charSize.argtypes = () |
| |
| liblouis.lou_translateString.restype = c_int |
| liblouis.lou_translateString.argtypes = ( |
| c_char_p, |
| POINTER(c_char), |
| POINTER(c_int), |
| POINTER(c_char), |
| POINTER(c_int), |
| POINTER(c_ushort), |
| POINTER(c_char), |
| c_int, |
| ) |
| |
| liblouis.lou_translate.restype = c_int |
| liblouis.lou_translate.argtypes = ( |
| c_char_p, |
| POINTER(c_char), |
| POINTER(c_int), |
| POINTER(c_char), |
| POINTER(c_int), |
| POINTER(c_ushort), |
| POINTER(c_char), |
| POINTER(c_int), |
| POINTER(c_int), |
| POINTER(c_int), |
| c_int, |
| ) |
| |
| liblouis.lou_backTranslateString.restype = c_int |
| liblouis.lou_backTranslateString.argtypes = ( |
| c_char_p, |
| POINTER(c_char), |
| POINTER(c_int), |
| POINTER(c_char), |
| POINTER(c_int), |
| POINTER(c_ushort), |
| POINTER(c_char), |
| c_int, |
| ) |
| |
| liblouis.lou_backTranslate.restype = c_int |
| liblouis.lou_backTranslate.argtypes = ( |
| c_char_p, |
| POINTER(c_char), |
| POINTER(c_int), |
| POINTER(c_char), |
| POINTER(c_int), |
| POINTER(c_ushort), |
| POINTER(c_char), |
| POINTER(c_int), |
| POINTER(c_int), |
| POINTER(c_int), |
| c_int, |
| ) |
| |
| liblouis.lou_hyphenate.restype = c_int |
| liblouis.lou_hyphenate.argtypes = ( |
| c_char_p, |
| POINTER(c_char), |
| c_int, |
| POINTER(c_char), |
| c_int, |
| ) |
| |
| liblouis.lou_checkTable.restype = c_int |
| liblouis.lou_checkTable.argtypes = (c_char_p,) |
| |
| liblouis.lou_compileString.restype = c_int |
| liblouis.lou_compileString.argtypes = (c_char_p, c_char_p) |
| |
| liblouis.lou_getTypeformForEmphClass.restype = c_ushort |
| liblouis.lou_getTypeformForEmphClass.argtypes = (c_char_p, c_char_p) |
| |
| liblouis.lou_dotsToChar.restype = c_int |
| liblouis.lou_dotsToChar.argtypes = ( |
| c_char_p, |
| POINTER(c_char), |
| POINTER(c_char), |
| c_int, |
| c_int, |
| ) |
| |
| liblouis.lou_charToDots.restype = c_int |
| liblouis.lou_charToDots.argtypes = ( |
| c_char_p, |
| POINTER(c_char), |
| POINTER(c_char), |
| c_int, |
| c_int, |
| ) |
| |
| LogCallback = _functype(None, c_int, c_char_p) |
| |
| liblouis.lou_registerLogCallback.restype = None |
| liblouis.lou_registerLogCallback.argtypes = (LogCallback,) |
| |
| liblouis.lou_setLogLevel.restype = None |
| liblouis.lou_setLogLevel.argtypes = (c_int,) |
| |
| liblouis.lou_findTable.restype = POINTER(c_char) |
| liblouis.lou_findTable.argtypes = (c_char_p,) |
| |
| liblouis.lou_freeTableFile.restype = None |
| liblouis.lou_freeTableFile.argtypes = (POINTER(c_char),) |
| |
| liblouis.lou_findTables.restype = POINTER(c_char_p) |
| liblouis.lou_findTables.argtypes = (c_char_p,) |
| |
| liblouis.lou_freeTableFiles.restype = None |
| liblouis.lou_freeTableFiles.argtypes = (POINTER(c_char_p),) |
| |
| liblouis.lou_getTableInfo.restype = POINTER(c_char) |
| liblouis.lou_getTableInfo.argtypes = (c_char_p, c_char_p) |
| |
| liblouis.lou_freeTableInfo.restype = None |
| liblouis.lou_freeTableInfo.argtypes = (liblouis.lou_getTableInfo.restype,) |
| |
| liblouis.lou_listTables.restype = POINTER(c_char_p) |
| liblouis.lou_listTables.argtypes = () |
| |
| liblouis.lou_free.restype = None |
| liblouis.lou_free.argtypes = () |
| |
| |
| def version() -> str: |
| """Obtain version information for liblouis. |
| :return: The version of liblouis, plus other information, such as |
| the release date and perhaps notable changes. |
| """ |
| return liblouis.lou_version().decode("ASCII") |
| |
| |
| def charSize() -> int: |
| """Obtain charSize information for liblouis. |
| :return: The size of the widechar with which liblouis was compiled. |
| """ |
| return liblouis.lou_charSize() |
| |
| |
| def translate( |
| tableList: TableListT, |
| inbuf: str, |
| typeform: list[int] | None = None, |
| cursorPos: int = 0, |
| mode: int = 0, |
| ) -> tuple[str, list[int], list[int], int]: |
| """Translate a string of characters, providing position information. |
| :param tableList: A list of translation tables. |
| :param inbuf: The string to translate. |
| :param typeform: A list of typeform constants indicating the typeform for each position in inbuf, |
| `None` for no typeform information. |
| :param cursorPos: The position of the cursor in inbuf. |
| :param mode: The translation mode; add multiple values for a combined mode. |
| :return: A tuple of: the translated string, |
| a list of input positions for each position in the output, |
| a list of output positions for each position in the input, and |
| the position of the cursor in the output. |
| :raise RuntimeError: If a complete translation could not be done. |
| :see: lou_translate in the liblouis documentation |
| """ |
| tableBuf: Array[c_char] = _createTableBuf(tableList) |
| _inbuf = _createEncodedBuf(inbuf) |
| inlen = c_int(len(_inbuf) // wideCharBytes) |
| outlen = c_int(inlen.value * outlenMultiplier) |
| outbuf = create_string_buffer(outlen.value * wideCharBytes) |
| typeformbuf = None |
| if typeform: |
| typeformbuf = _createTypeformbuf(outlen.value, typeform) |
| inPos = (c_int * outlen.value)() |
| outPos = (c_int * inlen.value)() |
| _cursorPos = c_int(cursorPos) |
| if not liblouis.lou_translate( |
| tableBuf, |
| _inbuf, |
| inlen, |
| outbuf, |
| outlen, |
| typeformbuf, |
| None, |
| outPos, |
| inPos, |
| _cursorPos, |
| mode, |
| ): |
| raise RuntimeError( |
| f"Can't translate: tables {tableList!r}, inbuf {inbuf!r}, typeform {typeform!r}, cursorPos {cursorPos!r}, mode {mode!r}" |
| ) |
| if isinstance(typeform, list) and typeformbuf is not None: |
| typeform[:] = list(typeformbuf) |
| return ( |
| outbuf.raw[: outlen.value * wideCharBytes].decode( |
| conversionEncoding, |
| errors=ENCODING_ERROR_HANDLER, |
| ), |
| inPos[: outlen.value], |
| outPos[: inlen.value], |
| _cursorPos.value, |
| ) |
| |
| |
| def translateString( |
| tableList: TableListT, |
| inbuf: str, |
| typeform: list[int] | None = None, |
| mode: int = 0, |
| ) -> str: |
| """Translate a string of characters. |
| :param tableList: A list of translation tables. |
| :param inbuf: The string to translate. |
| :param typeform: A list of typeform constants indicating the typeform for each position in inbuf, |
| `None` for no typeform information. |
| :param mode: The translation mode; add multiple values for a combined mode. |
| :return: The translated string. |
| :raise RuntimeError: If a complete translation could not be done. |
| :see: lou_translateString in the liblouis documentation |
| """ |
| tableBuf = _createTableBuf(tableList) |
| _inbuf = _createEncodedBuf(inbuf) |
| inlen = c_int(len(_inbuf) // wideCharBytes) |
| outlen = c_int(inlen.value * outlenMultiplier) |
| outbuf = create_string_buffer(outlen.value * wideCharBytes) |
| typeformbuf = None |
| if typeform: |
| typeformbuf = _createTypeformbuf(outlen.value, typeform) |
| if not liblouis.lou_translateString( |
| tableBuf, |
| _inbuf, |
| inlen, |
| outbuf, |
| outlen, |
| typeformbuf, |
| None, |
| mode, |
| ): |
| raise RuntimeError( |
| f"Can't translate: tables {tableList}, inbuf {inbuf}, typeform {typeform}, mode {mode}" |
| ) |
| if isinstance(typeform, list) and typeformbuf is not None: |
| typeform[:] = list(typeformbuf) |
| return outbuf.raw[: outlen.value * wideCharBytes].decode( |
| conversionEncoding, |
| errors=ENCODING_ERROR_HANDLER, |
| ) |
| |
| |
| def backTranslate( |
| tableList: TableListT, |
| inbuf: str, |
| typeform: list[int] | None = None, |
| cursorPos: int = 0, |
| mode: int = 0, |
| ) -> tuple[str, list[int], list[int], int]: |
| """Back translates a string of characters, providing position information. |
| :param tableList: A list of translation tables. |
| :param inbuf: Braille to back translate. |
| :param typeform: List where typeform constants will be placed. |
| :param cursorPos: Position of cursor. |
| :param mode: Translation mode. |
| :return: A tuple: A string of the back translation, |
| a list of input positions for each position in the output, |
| a list of the output positions for each position in the input and |
| the position of the cursor in the output. |
| :raise RuntimeError: If a complete back translation could not be done. |
| :see: lou_backTranslate in the liblouis documentation. |
| """ |
| tableBuf = _createTableBuf(tableList) |
| _inbuf = _createEncodedBuf(inbuf) |
| inlen = c_int(len(_inbuf) // wideCharBytes) |
| outlen = c_int(inlen.value * outlenMultiplier) |
| outbuf = create_string_buffer(outlen.value * wideCharBytes) |
| typeformbuf = None |
| if isinstance(typeform, list): |
| typeformbuf = _createTypeformbuf(outlen.value) |
| inPos = (c_int * outlen.value)() |
| outPos = (c_int * inlen.value)() |
| _cursorPos = c_int(cursorPos) |
| if not liblouis.lou_backTranslate( |
| tableBuf, |
| _inbuf, |
| inlen, |
| outbuf, |
| outlen, |
| typeformbuf, |
| None, |
| outPos, |
| inPos, |
| _cursorPos, |
| mode, |
| ): |
| raise RuntimeError( |
| f"Can't back translate: tables {tableList!r}, inbuf {inbuf!r}, typeform {typeform!r}, cursorPos {cursorPos!r}, mode {mode!r}" |
| ) |
| if isinstance(typeform, list) and typeformbuf is not None: |
| typeform[:] = list(typeformbuf) |
| return ( |
| outbuf.raw[: outlen.value * wideCharBytes].decode( |
| conversionEncoding, |
| errors=ENCODING_ERROR_HANDLER, |
| ), |
| inPos[: outlen.value], |
| outPos[: inlen.value], |
| _cursorPos.value, |
| ) |
| |
| |
| def backTranslateString( |
| tableList: TableListT, |
| inbuf: str, |
| typeform: list[int] | None = None, |
| mode: int = 0, |
| ) -> str: |
| """Back translate from Braille. |
| :param tableList: A list of translation tables. |
| :param inbuf: The Braille to back translate. |
| :param typeform: List for typeform constants to be put in. |
| If you don't want typeform data then give `None` |
| :param mode: The translation mode |
| :return: The back translation of inbuf. |
| :raise RuntimeError: If a complete back translation could not be done. |
| :see: lou_backTranslateString in the liblouis documentation. |
| """ |
| tableBuf = _createTableBuf(tableList) |
| _inbuf = _createEncodedBuf(inbuf) |
| inlen = c_int(len(_inbuf) // wideCharBytes) |
| outlen = c_int(inlen.value * outlenMultiplier) |
| outbuf = create_string_buffer(outlen.value * wideCharBytes) |
| typeformbuf = None |
| if isinstance(typeform, list): |
| typeformbuf = _createTypeformbuf(outlen.value) |
| if not liblouis.lou_backTranslateString( |
| tableBuf, |
| _inbuf, |
| inlen, |
| outbuf, |
| outlen, |
| typeformbuf, |
| None, |
| mode, |
| ): |
| raise RuntimeError( |
| f"Can't back translate: tables {tableList!r}, inbuf {inbuf!r}, mode {mode!r}" |
| ) |
| if isinstance(typeform, list) and typeformbuf is not None: |
| typeform[:] = list(typeformbuf) |
| return outbuf.raw[: outlen.value * wideCharBytes].decode( |
| conversionEncoding, |
| errors=ENCODING_ERROR_HANDLER, |
| ) |
| |
| |
| def hyphenate(tableList: TableListT, inbuf: str, mode: int = 0) -> str: |
| """Get information for hyphenation. |
| :param tableList: A list of translation tables and hyphenation |
| dictionaries. |
| :param inbuf: The text to get hyphenation information about. |
| This should be a single word and leading/trailing whitespace |
| and punctuation is ignored. |
| :param mode: Lets liblouis know if inbuf is plain text or Braille. |
| Set to 0 for text and anyother value for Braille. |
| :return: A string with '1' at the beginning of every syllable |
| and '0' elsewhere. |
| :raise RuntimeError: If hyphenation data could not be produced. |
| :see: lou_hyphenate in the liblouis documentation. |
| """ |
| tableBuf = _createTableBuf(tableList) |
| _inbuf = _createEncodedBuf(inbuf) |
| inlen = c_int(len(_inbuf) // wideCharBytes) |
| hyphen_string = create_string_buffer(inlen.value + 1) |
| if not liblouis.lou_hyphenate( |
| tableBuf, |
| _inbuf, |
| inlen, |
| hyphen_string, |
| mode, |
| ): |
| raise RuntimeError( |
| f"Can't hyphenate: tables {tableList!r}, inbuf {inbuf!r}, mode {mode!r}" |
| ) |
| return hyphen_string.value.decode("ASCII") |
| |
| |
| def checkTable(tableList: TableListT) -> None: |
| """Check if the specified tables can be found and compiled. |
| This can be used to check if a list of tables contains errors |
| before sending it to other liblouis functions |
| that accept a list of tables. |
| :param tableList: A list of translation tables. |
| :raise RuntimeError: If compilation failed. |
| :see: lou_checkTable in the liblouis documentation |
| """ |
| tableBuf = _createTableBuf(tableList) |
| if not liblouis.lou_checkTable(tableBuf): |
| raise RuntimeError(f"Can't compile: tables {tableList}") |
| |
| |
| def compileString(tableList: TableListT, inString: str) -> None: |
| """Compile a table entry on the fly at run-time. |
| :param tableList: A list of translation tables. |
| :param inString: The table entry to be added. |
| :raise RuntimeError: If compilation of the entry failed. |
| :see: lou_compileString in the liblouis documentation |
| """ |
| tableBuf = _createTableBuf(tableList) |
| inbuf = create_string_buffer( |
| inString.encode("ASCII") if isinstance(inString, str) else bytes(inString) |
| ) |
| if not liblouis.lou_compileString(tableBuf, inbuf): |
| raise RuntimeError( |
| f"Can't compile entry: tables {tableList}, inString {inString}" |
| ) |
| |
| |
| def getTypeformForEmphClass(tableList: TableListT, emphClass: str) -> int: |
| """Get the typeform bit for the named emphasis class. |
| :param tableList: A list of translation tables. |
| :param emphClass: An emphasis class name. |
| :see: lou_getTypeformForEmphClass in the liblouis documentation |
| """ |
| tableBuf = _createTableBuf(tableList) |
| bEmphClass = emphClass.encode("ASCII") |
| return liblouis.lou_getTypeformForEmphClass(tableBuf, bEmphClass) |
| |
| |
| def dotsToChar(tableList: TableListT, inbuf: str) -> str: |
| """Convert a string of dot patterns to a string of characters according to the specifications in tableList. |
| :param tableList: A list of translation tables. |
| :param inbuf: a string of dot patterns, either in liblouis format or Unicode braille. |
| :raise RuntimeError: If a complete conversion could not be done. |
| :see: lou_dotsToChar in the liblouis documentation |
| """ |
| tableBuf = _createTableBuf(tableList) |
| _inbuf = _createEncodedBuf(inbuf) |
| length = c_int(len(inbuf) // wideCharBytes) |
| outbuf = create_string_buffer(length.value * wideCharBytes) |
| if not liblouis.lou_dotsToChar(tableBuf, _inbuf, outbuf, length, 0): |
| raise RuntimeError( |
| f"Can't convert dots to char: tables {tableList}, inbuf {inbuf!r}" |
| ) |
| return outbuf.raw[: length.value * wideCharBytes].decode( |
| conversionEncoding, |
| errors=ENCODING_ERROR_HANDLER, |
| ) |
| |
| |
| def charToDots(tableList: TableListT, inbuf: str, mode: int = 0) -> str: |
| """Convert a string of characterss to a string of dot patterns according to the specifications in tableList. |
| :param tableList: A list of translation tables. |
| :param inbuf: a string of characters. |
| :param mode: The translation mode; add multiple values for a combined mode. |
| :raise RuntimeError: If a complete conversion could not be done. |
| :see: lou_charToDots in the liblouis documentation |
| """ |
| tableBuf = _createTableBuf(tableList) |
| _inbuf = _createEncodedBuf(inbuf) |
| length = c_int(len(inbuf) // wideCharBytes) |
| outbuf = create_string_buffer(length.value * wideCharBytes) |
| if not liblouis.lou_charToDots(tableBuf, _inbuf, outbuf, length, mode): |
| raise RuntimeError( |
| f"Can't convert char to dots: tables {tableList!r}, inbuf {inbuf!r}, mode {mode!r}" |
| ) |
| return outbuf.raw[: length.value * wideCharBytes].decode( |
| conversionEncoding, |
| errors=ENCODING_ERROR_HANDLER, |
| ) |
| |
| |
| def registerLogCallback(logCallback) -> None: |
| """Register logging callbacks. |
| Set to `None` for default callback. |
| :param logCallback: The callback to use. |
| The callback must take two arguments: |
| :param level: The log level on which a message is logged. |
| :type level: int |
| :param message: The logged message. |
| Note that the callback should provide its own UTF-8 decoding routine. |
| :type message: bytes |
| |
| Example callback: |
| |
| @louis.LogCallback |
| def incomingLouisLog(level, message): |
| print("Message %s logged at level %d" % (message.decode("ASCII"), level)) |
| |
| @type logCallback: `LogCallback` |
| """ |
| if logCallback is None: |
| logCallback = LogCallback(0) |
| elif not isinstance(logCallback, LogCallback): |
| raise TypeError( |
| f"logCallback should be of type {LogCallback.__name__} or NoneType" |
| ) |
| return liblouis.lou_registerLogCallback(logCallback) |
| |
| |
| def setLogLevel(level: int) -> None: |
| """Set the level for logging callback to be called at. |
| :param level: one of the C{LOG_*} constants. |
| :raise ValueError: If an invalid log level is provided. |
| """ |
| if level not in logLevels: |
| raise ValueError("Level %d is an invalid log level" % level) |
| return liblouis.lou_setLogLevel(level) |
| |
| |
| def findTable(query: dict[str, str]) -> str | None: |
| """Find the best match for a query |
| |
| Returns the name of the table, or None when no match can be |
| found. An error message is given when the query is invalid. Freeing. |
| :param query: The query to lookup. |
| """ |
| queryStr = _createQueryStringBuf(query) |
| result = liblouis.lou_findTable(queryStr) |
| if not result: |
| return None |
| string = string_at(result).decode(fileSystemEncoding, errors=ENCODING_ERROR_HANDLER) |
| liblouis.lou_freeTableFile(result) |
| return string |
| |
| |
| def findTables(query: dict[str, str]) -> list[str]: |
| """Find all matches for a query, best match first. |
| |
| Returns the names of the matched tables. |
| An error message is given when the query is invalid. |
| :param query: The query to lookup. |
| """ |
| queryStr = _createQueryStringBuf(query) |
| result = liblouis.lou_findTables(queryStr) |
| return list(_processTableFiles(result)) |
| |
| |
| def getTableInfo(tableName: str, key: str) -> str | None: |
| """Read metadata from a file. |
| |
| Returns the value of the first occurring metadata field specified by |
| `key' in `table', or None when the field does not exist. |
| """ |
| bTableName = _createEncodedBuf(tableName, fileSystemEncoding) |
| bKey = _createEncodedBuf(key, getdefaultencoding()) |
| result = liblouis.lou_getTableInfo(bTableName, bKey) |
| if not result: |
| return None |
| string = string_at(result).decode(errors=ENCODING_ERROR_HANDLER) |
| liblouis.lou_freeTableInfo(result) |
| return string |
| |
| |
| def listTables() -> list[str]: |
| """List available tables. |
| |
| Returns the names of available tables as list of strings. |
| Only tables that are discoverable, i.e. the have active metadata, are listed. |
| """ |
| result = liblouis.lou_listTables() |
| return list(_processTableFiles(result)) |
| |
| |
| # { Typeforms |
| plain_text = 0x0000 |
| emph_1 = comp_emph_1 = italic = 0x0001 |
| emph_2 = comp_emph_2 = underline = 0x0002 |
| emph_3 = comp_emph_3 = bold = 0x0004 |
| emph_4 = 0x0008 |
| emph_5 = 0x0010 |
| emph_6 = 0x0020 |
| emph_7 = 0x0040 |
| emph_8 = 0x0080 |
| emph_9 = 0x0100 |
| emph_10 = 0x0200 |
| computer_braille = 0x0400 |
| no_translate = 0x0800 |
| no_contract = 0x1000 |
| # } |
| |
| # { Translation modes |
| noContractions = 1 |
| compbrlAtCursor = 2 |
| dotsIO = 4 |
| compbrlLeftCursor = 32 |
| ucBrl = 64 |
| noUndefined = 128 |
| noUndefinedDots = noUndefined # alias for backward compatiblity |
| partialTrans = 256 |
| # } |
| |
| # { logLevels |
| LOG_ALL = 0 |
| LOG_DEBUG = 10000 |
| LOG_INFO = 20000 |
| LOG_WARN = 30000 |
| LOG_ERROR = 40000 |
| LOG_FATAL = 50000 |
| LOG_OFF = 60000 |
| # } |
| |
| logLevels = (LOG_ALL, LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR, LOG_FATAL, LOG_OFF) |
| |
| if __name__ == "__main__": |
| # Just some common tests. |
| print(version()) |
| print(translate([b"../tables/en-us-g2.ctb"], "Hello world!", cursorPos=5)) |