Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-tesserocr for
openSUSE:Factory checked in at 2026-09-23 14:34:39
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-tesserocr (Old)
and /work/SRC/openSUSE:Factory/.python-tesserocr.new.383539 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-tesserocr"
Wed Sep 23 14:34:39 2026 rev:28 rq:1379774 version:2.11.0
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-tesserocr/python-tesserocr.changes
2026-02-18 17:07:09.554042518 +0100
+++
/work/SRC/openSUSE:Factory/.python-tesserocr.new.383539/python-tesserocr.changes
2026-09-23 14:36:16.183618903 +0200
@@ -1,0 +2,9 @@
+Wed Sep 23 01:26:48 UTC 2026 - Steve Kowalik <[email protected]>
+
+- Update to 2.11.0:
+ * Catch exception in get_languages()
+ * fix _pix_to_image memory leak
+ * place long running API calls in cysignals blocks
+- Build with Cython 3.
+
+-------------------------------------------------------------------
Old:
----
tesserocr-2.9.2.tar.gz
New:
----
tesserocr-2.11.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-tesserocr.spec ++++++
--- /var/tmp/diff_new_pack.svV5Bt/_old 2026-09-23 14:36:17.005652893 +0200
+++ /var/tmp/diff_new_pack.svV5Bt/_new 2026-09-23 14:36:17.008653017 +0200
@@ -18,14 +18,15 @@
%{?sle15_python_module_pythons}
Name: python-tesserocr
-Version: 2.9.2
+Version: 2.11.0
Release: 0
Summary: A Python wrapper around tesseract-ocr
License: MIT
URL: https://github.com/sirfz/tesserocr
Source:
https://files.pythonhosted.org/packages/source/t/tesserocr/tesserocr-%{version}.tar.gz
-BuildRequires: %{python_module Cython0}
+BuildRequires: %{python_module Cython}
BuildRequires: %{python_module Pillow}
+BuildRequires: %{python_module cysignals}
BuildRequires: %{python_module devel}
BuildRequires: %{python_module pip}
BuildRequires: %{python_module pytest}
@@ -39,6 +40,7 @@
BuildRequires: tesseract-ocr-traineddata-orientation_and_script_detection
BuildRequires: pkgconfig(libcurl)
BuildRequires: pkgconfig(tesseract)
+Requires: python-cysignals
Requires: tesseract-ocr-traineddata-english
Requires: tesseract-ocr-traineddata-orientation_and_script_detection
Recommends: python-Pillow
++++++ tesserocr-2.9.2.tar.gz -> tesserocr-2.11.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/tesserocr-2.9.2/.eggs/cysignals-1.12.5-py3.9-linux-x86_64.egg/cysignals/macros.h
new/tesserocr-2.11.0/.eggs/cysignals-1.12.5-py3.9-linux-x86_64.egg/cysignals/macros.h
---
old/tesserocr-2.9.2/.eggs/cysignals-1.12.5-py3.9-linux-x86_64.egg/cysignals/macros.h
1970-01-01 01:00:00.000000000 +0100
+++
new/tesserocr-2.11.0/.eggs/cysignals-1.12.5-py3.9-linux-x86_64.egg/cysignals/macros.h
2026-08-04 13:59:53.000000000 +0200
@@ -0,0 +1,320 @@
+/*
+Interrupt and signal handling for Cython.
+
+This code distinguishes between two kinds of signals:
+
+(1) interrupt-like signals: SIGINT, SIGALRM, SIGHUP. The word
+"interrupt" refers to any of these signals. These need not be handled
+immediately, we might handle them at a suitable later time, outside of
+sig_block() and with the Python GIL acquired. SIGINT raises a
+KeyboardInterrupt (as usual in Python), SIGALRM raises AlarmInterrupt
+(a custom exception inheriting from KeyboardInterrupt), while SIGHUP
+raises SystemExit, causing Python to exit. The latter signal also
+redirects stdin from /dev/null, to cause interactive sessions to exit.
+
+(2) critical signals: SIGQUIT, SIGILL, SIGABRT, SIGFPE, SIGBUS, SIGSEGV.
+These are critical because they cannot be ignored. If they happen
+outside of sig_on(), we can only exit Python with the dreaded
+"unhandled SIG..." message. Inside of sig_on(), they can be handled
+and raise various exceptions (see cysignals/signals.pyx). SIGQUIT
+will never be handled and always causes Python to exit.
+
+*/
+
+/*****************************************************************************
+ * Copyright (C) 2006 William Stein <[email protected]>
+ * 2006 Martin Albrecht
<[email protected]>
+ * 2010-2016 Jeroen Demeyer <[email protected]>
+ *
+ * cysignals 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * cysignals 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 cysignals. If not, see <http://www.gnu.org/licenses/>.
+ *
+ ****************************************************************************/
+
+
+#ifndef CYSIGNALS_MACROS_H
+#define CYSIGNALS_MACROS_H
+
+#include <setjmp.h>
+#include <signal.h>
+#include "struct_signals.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**********************************************************************
+ * HELPER FUNCTIONS *
+ **********************************************************************/
+
+/* Send a signal to the calling process. The POSIX raise() function
+ * sends a signal to the calling thread, while kill() typically sends
+ * a signal to the main thread (although this is not guaranteed by the
+ * POSIX standard) */
+#if HAVE_KILL
+#define proc_raise(sig) kill(getpid(), sig)
+#else
+/* On Windows, raise() actually signals the process */
+#define proc_raise(sig) raise(sig)
+#endif
+
+/**********************************************************************
+ * IMPLEMENTATION OF SIG_ON/SIG_OFF *
+ **********************************************************************/
+
+/*
+ * Implementation of sig_on(). Applications should not use this
+ * directly, use sig_on() or sig_str() instead.
+ *
+ * _sig_on_(message) is a macro which pretends to be a function.
+ * Since this is declared as "cdef except 0", Cython will know that an
+ * exception occurred if the value of _sig_on_() is 0 (false).
+ *
+ * INPUT:
+ *
+ * - message -- a string to be displayed as error message when the code
+ * between sig_on() and sig_off() fails and raises an exception.
+ *
+ * OUTPUT: zero if an exception occurred, non-zero otherwise.
+ *
+ * The function cysetjmp() in the _sig_on_() macro can return:
+ * - zero: this happens in the actual sig_on() call. cysetjmp() sets
+ * up the address for the signal handler to jump to. The
+ * program continues normally.
+ * - a signal number (e.g. 2 for SIGINT), assumed to be strictly
+ * positive: the cysignals signal handler handled a signal. Since
+ * _sig_on_() will return 0 in this case, the Exception (raised by
+ * cysigs_signal_handler) will be detected by Cython.
+ * - a negative number: this is assumed to come from sig_retry(). In
+ * this case, the program continues as if nothing happened between
+ * sig_on() and sig_retry().
+ *
+ * We cannot simply put cysetjmp() in a function, because when that
+ * function returns, we would lose the stack frame to cylongjmp() to.
+ * That's why we need this hackish macro. We use the fact that || is
+ * a short-circuiting operator (the second argument is only evaluated
+ * if the first returns 0).
+ */
+
+#define _sig_on_(message) ( unlikely(_sig_on_prejmp(message, __FILE__,
__LINE__)) || _sig_on_postjmp(cysetjmp(cysigs.env)) )
+
+/*
+ * Set message, return 0 if we need to cysetjmp(), return 1 otherwise.
+ */
+static inline int _sig_on_prejmp(const char* message, CYTHON_UNUSED const
char* file, CYTHON_UNUSED int line)
+{
+ cysigs.s = message;
+#if ENABLE_DEBUG_CYSIGNALS
+ if (cysigs.debug_level >= 4)
+ {
+ fprintf(stderr, "sig_on (count = %i) at %s:%i\n",
+ (int)cysigs.sig_on_count+1, file, line);
+ fflush(stderr);
+ }
+ if (cysigs.block_sigint && cysigs.sig_on_count <= 0)
+ {
+ fprintf(stderr, "\n*** ERROR *** sig_on() with sig_on_count = %i,
block_sigint = %i\n",
+ (int)cysigs.sig_on_count, (int)cysigs.block_sigint);
+ print_backtrace();
+ }
+#endif
+ if (cysigs.sig_on_count > 0)
+ {
+ cysigs.sig_on_count++;
+ return 1;
+ }
+
+ /* At this point, cysigs.sig_on_count == 0 */
+ return 0;
+}
+
+
+/*
+ * Process the return value of cysetjmp().
+ * Return 0 if there was an exception, 1 otherwise.
+ */
+static inline int _sig_on_postjmp(int jmpret)
+{
+ if (unlikely(jmpret > 0))
+ {
+ /* An exception occurred */
+ _sig_on_recover();
+ return 0;
+ }
+
+ /* When we are here, it's either the original sig_on() call or we
+ * got here after sig_retry(). */
+ cysigs.sig_on_count = 1;
+
+ /* Check whether we received an interrupt before this point.
+ * cysigs.interrupt_received can only be set by the interrupt
+ * handler if cysigs.sig_on_count is zero. Because of that and
+ * because cysigs.sig_on_count and cysigs.interrupt_received are
+ * volatile, we can safely evaluate cysigs.interrupt_received here
+ * without race conditions. */
+ if (unlikely(cysigs.interrupt_received))
+ {
+ _sig_on_interrupt_received();
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/*
+ * Implementation of sig_off(). Applications should not use this
+ * directly, use sig_off() instead.
+ */
+static inline void _sig_off_(const char* file, int line)
+{
+#if ENABLE_DEBUG_CYSIGNALS
+ if (cysigs.debug_level >= 4)
+ {
+ fprintf(stderr, "sig_off (count = %i) at %s:%i\n",
+ (int)cysigs.sig_on_count, file, line);
+ fflush(stderr);
+ }
+#endif
+ if (unlikely(cysigs.sig_on_count <= 0))
+ {
+ _sig_off_warning(file, line);
+ }
+ else
+ {
+ --cysigs.sig_on_count;
+ }
+}
+
+
+/**********************************************************************
+ * USER MACROS/FUNCTIONS *
+ **********************************************************************/
+
+/* The actual macros which should be used in a program. */
+#define sig_on() _sig_on_(NULL)
+#define sig_str(message) _sig_on_(message)
+#define sig_off() _sig_off_(__FILE__, __LINE__)
+
+/* sig_check() should be functionally equivalent to sig_on(); sig_off();
+ * but much faster. Essentially, it checks whether we missed any
+ * interrupts.
+ *
+ * OUTPUT: zero if an interrupt occurred, non-zero otherwise.
+ */
+static inline int sig_check(void)
+{
+ if (unlikely(cysigs.interrupt_received) && cysigs.sig_on_count == 0)
+ {
+ _sig_on_interrupt_received();
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/*
+ * Temporarily block interrupts from happening inside sig_on(). This
+ * is meant to wrap malloc() for example. sig_unblock() checks whether
+ * an interrupt happened in the mean time. If yes, the interrupt is
+ * re-raised.
+ *
+ * NOTES:
+ * - This only works inside sig_on()/sig_off(). Outside of sig_on(),
+ * interrupts behave as usual. This is because we can't propagate
+ * Python exceptions from low-level C code.
+ * - Despite the above note, it is still legal to use sig_block()
+ * outside of sig_on().
+ * - Other signals still go through, because we can't really ignore
+ * SIGSEGV for example.
+ * - It is NOT allowed to have an outer call of sig_on() inside
+ * sig_block().
+ * A deeper nesting (sig_on(); sig_block(); sig_on();) is OK.
+ */
+static inline void sig_block(void)
+{
+ /* This increment may not be atomic. However, that's not an issue
+ * because our signal handlers do not change this value. The value
+ * of block_sigint is set to 0 in _sig_on_recover, but that only
+ * happens after a longjmp(). */
+ ++cysigs.block_sigint;
+}
+
+static inline void sig_unblock(void)
+{
+#if ENABLE_DEBUG_CYSIGNALS
+ if (cysigs.block_sigint < 1)
+ {
+ fprintf(stderr, "\n*** ERROR *** sig_unblock() with sig_on_count = %i,
block_sigint = %i\n",
+ (int)cysigs.sig_on_count, (int)cysigs.block_sigint);
+ print_backtrace();
+ }
+#endif
+ --cysigs.block_sigint;
+
+ if (unlikely(cysigs.interrupt_received))
+ /* Re-raise the signal if we can handle it now */
+ if (cysigs.sig_on_count > 0 && cysigs.block_sigint == 0)
+ proc_raise(cysigs.interrupt_received);
+}
+
+
+/*
+ * Retry a failed computation starting from sig_on().
+ */
+static inline void sig_retry(void)
+{
+ /* If we're outside of sig_on(), we can't jump, so we can only bail
+ * out */
+ if (unlikely(cysigs.sig_on_count <= 0))
+ {
+ fprintf(stderr, "sig_retry() without sig_on()\n");
+ proc_raise(SIGABRT);
+ }
+ cylongjmp(cysigs.env, -1);
+}
+
+/* Used in error callbacks from C code (in particular NTL and PARI).
+ * This should be used after an exception has been raised to jump back
+ * to sig_on() where the exception will be seen. */
+static inline void sig_error(void)
+{
+ if (unlikely(cysigs.sig_on_count <= 0))
+ {
+ fprintf(stderr, "sig_error() without sig_on()\n");
+ }
+ proc_raise(SIGABRT);
+}
+
+
+static inline int _set_debug_level(int level)
+{
+#if ENABLE_DEBUG_CYSIGNALS
+ int old = cysigs.debug_level;
+ cysigs.debug_level = level;
+ return old;
+#else
+ if (level == 0)
+ return 0; /* 0 is the only valid debug level */
+ else
+ return -1; /* Error */
+#endif
+}
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* ifndef CYSIGNALS_MACROS_H */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/tesserocr-2.9.2/.eggs/cysignals-1.12.5-py3.9-linux-x86_64.egg/cysignals/struct_signals.h
new/tesserocr-2.11.0/.eggs/cysignals-1.12.5-py3.9-linux-x86_64.egg/cysignals/struct_signals.h
---
old/tesserocr-2.9.2/.eggs/cysignals-1.12.5-py3.9-linux-x86_64.egg/cysignals/struct_signals.h
1970-01-01 01:00:00.000000000 +0100
+++
new/tesserocr-2.11.0/.eggs/cysignals-1.12.5-py3.9-linux-x86_64.egg/cysignals/struct_signals.h
2026-08-04 13:59:53.000000000 +0200
@@ -0,0 +1,109 @@
+/*****************************************************************************
+ * Copyright (C) 2006 William Stein <[email protected]>
+ * 2006 Martin Albrecht
<[email protected]>
+ * 2010-2016 Jeroen Demeyer <[email protected]>
+ *
+ * cysignals 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * cysignals 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 cysignals. If not, see <http://www.gnu.org/licenses/>.
+ *
+ ****************************************************************************/
+
+#ifndef CYSIGNALS_STRUCT_SIGNALS_H
+#define CYSIGNALS_STRUCT_SIGNALS_H
+
+
+#include "cysignals_config.h"
+#include <setjmp.h>
+#include <signal.h>
+#include <Python.h>
+
+
+/* Choose sigjmp/longjmp variant */
+#if CYSIGNALS_USE_SIGSETJMP
+#define cyjmp_buf sigjmp_buf
+#define cysetjmp(env) sigsetjmp(env, 0)
+#define cylongjmp(env, val) siglongjmp(env, val)
+#else
+#define cyjmp_buf jmp_buf
+#define cysetjmp(env) setjmp(env)
+#define cylongjmp(env, val) longjmp(env, val)
+#endif
+
+
+/* Define a cy_atomic_int type for atomic operations */
+#if __cplusplus
+#if CYSIGNALS_STD_ATOMIC
+#include <atomic>
+typedef volatile std::atomic<int> cy_atomic_int;
+#elif CYSIGNALS_CXX_ATOMIC
+typedef volatile _Atomic int cy_atomic_int;
+#else
+/* The type sig_atomic_t is not really atomic, but it's the best we have */
+typedef volatile sig_atomic_t cy_atomic_int;
+#endif
+#else
+#if CYSIGNALS_C_ATOMIC
+typedef volatile _Atomic int cy_atomic_int;
+#else
+/* The type sig_atomic_t is not really atomic, but it's the best we have */
+typedef volatile sig_atomic_t cy_atomic_int;
+#endif
+#endif
+
+
+/* All the state of the signal handler is in this struct. */
+typedef struct
+{
+ /* Reference counter for sig_on().
+ * If this is strictly positive, we are inside a sig_on(). */
+ cy_atomic_int sig_on_count;
+
+ /* If this is nonzero, it is a signal number of a non-critical
+ * signal (e.g. SIGINT) which happened during a time when it could
+ * not be handled. This may be set when an interrupt occurs either
+ * outside of sig_on() or inside sig_block(). To avoid race
+ * conditions, this value may only be changed when all
+ * interrupt-like signals are masked. */
+ cy_atomic_int interrupt_received;
+
+ /* Are we currently handling a signal inside cysigs_signal_handler()?
+ * This is set to 1 on entry in cysigs_signal_handler (not in
+ * cysigs_interrupt_handler) and 0 in _sig_on_postjmp. This is
+ * needed to check for signals raised within the signal handler. */
+ cy_atomic_int inside_signal_handler;
+
+ /* Non-zero if we currently are in a function such as malloc()
+ * which blocks interrupts, zero normally.
+ * See sig_block(), sig_unblock(). */
+ cy_atomic_int block_sigint;
+
+ /* A jump buffer holding where to cylongjmp() after a signal has
+ * been received. This is set by sig_on(). */
+ cyjmp_buf env;
+
+ /* An optional string (in UTF-8 encoding) to be used as text for
+ * the exception raised by sig_raise_exception(). If this is NULL,
+ * use some default string depending on the type of signal. This can
+ * be set using sig_str() instead of sig_on(). */
+ const char* s;
+
+ /* Reference to the exception object that we raised (NULL if none).
+ * This is used by the sig_occurred function. */
+ PyObject* exc_value;
+
+#if ENABLE_DEBUG_CYSIGNALS
+ int debug_level;
+#endif
+} cysigs_t;
+
+#endif /* ifndef CYSIGNALS_STRUCT_SIGNALS_H */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tesserocr-2.9.2/MANIFEST.in
new/tesserocr-2.11.0/MANIFEST.in
--- old/tesserocr-2.9.2/MANIFEST.in 2025-12-18 09:51:29.000000000 +0100
+++ new/tesserocr-2.11.0/MANIFEST.in 2026-08-04 13:59:43.000000000 +0200
@@ -3,7 +3,7 @@
include tesserocr/*.pyx
include tesserocr/*.pxd
include tesserocr/*.pyi
-include tests/*.py tests/*.png
+include tests/*.py tests/*.png tests/*.train
exclude tesserocr/*.cpp
exclude tesserocr/*.so
exclude *.so
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tesserocr-2.9.2/PKG-INFO
new/tesserocr-2.11.0/PKG-INFO
--- old/tesserocr-2.9.2/PKG-INFO 2025-12-18 09:51:35.032224200 +0100
+++ new/tesserocr-2.11.0/PKG-INFO 2026-08-04 13:59:55.400774200 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.4
Name: tesserocr
-Version: 2.9.2
+Version: 2.11.0
Summary: A simple, Pillow-friendly, Python wrapper around tesseract-ocr API
using Cython
Home-page: https://github.com/sirfz/tesserocr
Author: Fayez Zouheiry
@@ -12,7 +12,6 @@
Classifier: Topic :: Multimedia :: Graphics :: Capture :: Scanners
Classifier: Topic :: Multimedia :: Graphics :: Graphics Conversion
Classifier: Topic :: Scientific/Engineering :: Image Recognition
-Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: POSIX
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
@@ -27,6 +26,7 @@
Requires-Python: >=3.9
Description-Content-Type: text/x-rst
License-File: LICENSE
+Requires-Dist: cysignals
Dynamic: author
Dynamic: author-email
Dynamic: classifier
@@ -36,6 +36,7 @@
Dynamic: keywords
Dynamic: license
Dynamic: license-file
+Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tesserocr-2.9.2/setup.py
new/tesserocr-2.11.0/setup.py
--- old/tesserocr-2.9.2/setup.py 2025-12-18 09:51:29.000000000 +0100
+++ new/tesserocr-2.11.0/setup.py 2026-08-04 13:59:43.000000000 +0200
@@ -1,4 +1,3 @@
-import codecs
import errno
import glob
import itertools
@@ -39,7 +38,7 @@
def read(*parts):
- with codecs.open(pjoin(here, *parts), "r", encoding="utf-8") as f:
+ with open(pjoin(here, *parts), "r", encoding="utf-8") as f:
return f.read()
@@ -301,7 +300,6 @@
"Topic :: Multimedia :: Graphics :: Capture :: Scanners",
"Topic :: Multimedia :: Graphics :: Graphics Conversion",
"Topic :: Scientific/Engineering :: Image Recognition",
- "License :: OSI Approved :: MIT License",
"Operating System :: POSIX",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.9",
@@ -318,7 +316,8 @@
cmdclass={"build_ext": my_build_ext},
ext_modules=[make_extension()],
test_suite="tests",
- setup_requires=["Cython>=3.0.0,<3.2.0"],
+ setup_requires=["Cython>=3.0.0,<3.2.0", "cysignals"],
+ install_requires=["cysignals"],
packages=["tesserocr"],
package_dir={"tesserocr": "tesserocr"},
)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tesserocr-2.9.2/tesserocr/tesseract5.pxd
new/tesserocr-2.11.0/tesserocr/tesseract5.pxd
--- old/tesserocr-2.9.2/tesserocr/tesseract5.pxd 2025-12-18
09:51:29.000000000 +0100
+++ new/tesserocr-2.11.0/tesserocr/tesseract5.pxd 2026-08-04
13:59:43.000000000 +0200
@@ -282,7 +282,7 @@
int Init(cchar_t *, cchar_t *)
cchar_t *GetInitLanguagesAsString() const
void GetLoadedLanguagesAsVector(vector[string] *) const
- void GetAvailableLanguagesAsVector(vector[string] *) const
+ void GetAvailableLanguagesAsVector(vector[string] *) except +
void InitForAnalysePage()
void ReadConfigFile(cchar_t *)
void SetPageSegMode(PageSegMode)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tesserocr-2.9.2/tesserocr/tesserocr.pyx
new/tesserocr-2.11.0/tesserocr/tesserocr.pyx
--- old/tesserocr-2.9.2/tesserocr/tesserocr.pyx 2025-12-18 09:51:29.000000000
+0100
+++ new/tesserocr-2.11.0/tesserocr/tesserocr.pyx 2026-08-04
13:59:43.000000000 +0200
@@ -18,7 +18,7 @@
['eng', 'osd', 'equ'])
"""
-__version__ = '2.9.2'
+__version__ = '2.11.0'
import os
import logging
@@ -39,6 +39,7 @@
from libcpp.vector cimport vector
from cython.operator cimport preincrement as inc, dereference as deref
from cpython.version cimport PY_MAJOR_VERSION
+from cysignals.signals cimport sig_on, sig_off
_LOGGER = logging.getLogger("tesserocr")
@@ -375,9 +376,11 @@
size_t size
int result
int fmt = pix.informat
+ Pix *converted_pix = NULL
if pix.d == 1:
# prevent catastrophic 8-bit conversion
- pix = pixConvertTo8(pix, 0)
+ converted_pix = pixConvertTo8(pix, 0)
+ pix = converted_pix
if fmt > 0:
result = pixWriteMem(&buff, &size, pix, fmt)
else:
@@ -392,6 +395,8 @@
image.load()
finally:
free(buff)
+ if converted_pix != NULL:
+ pixDestroy(&converted_pix)
return image
@@ -2073,8 +2078,11 @@
blockids_addr = NULL
if not paraids:
paraids_addr = NULL
- boxa = self._baseapi.GetComponentImages(level, text_only, raw_image,
raw_padding,
- &pixa, blockids_addr,
paraids_addr)
+ with nogil:
+ sig_on()
+ boxa = self._baseapi.GetComponentImages(level, text_only,
raw_image, raw_padding,
+ &pixa, blockids_addr,
paraids_addr)
+ sig_off()
if boxa == NULL:
# no components found
return []
@@ -2122,7 +2130,9 @@
"""
cdef PageIterator *piter
with nogil:
+ sig_on()
piter = self._baseapi.AnalyseLayout(merge_similar_words)
+ sig_off()
if piter == NULL:
return None
return PyPageIterator.createPageIterator(piter)
@@ -2145,6 +2155,7 @@
ETEXT_DESC monitor
int res
with nogil:
+ sig_on()
if timeout > 0:
monitor.cancel = NULL
monitor.cancel_this = NULL
@@ -2152,6 +2163,7 @@
res = self._baseapi.Recognize(&monitor)
else:
res = self._baseapi.Recognize(NULL)
+ sig_off()
return res == 0
"""Methods to retrieve information after :meth:`SetImage`,
@@ -2164,6 +2176,7 @@
ETEXT_DESC monitor
int res
with nogil:
+ sig_on()
if timeout > 0:
monitor.cancel = NULL
monitor.cancel_this = NULL
@@ -2171,6 +2184,7 @@
res = self._baseapi.RecognizeForChopTest(&monitor)
else:
res = self._baseapi.RecognizeForChopTest(NULL)
+ sig_off()
return res == 0
cdef TessResultRenderer *_get_renderer(self, cchar_t *outputbase):
@@ -2370,7 +2384,9 @@
"""Return the recognized text coded as UTF-8 from the image."""
cdef char *text
with nogil:
+ sig_on()
text = self._baseapi.GetUTF8Text()
+ sig_off()
self._destroy_pix()
if text == NULL:
with gil:
@@ -2710,7 +2726,9 @@
if pix == NULL:
with gil:
raise RuntimeError('Failed to read picture')
+ sig_on()
text = _image_to_text(pix, clang, psm, cpath, oem)
+ sig_off()
if text == NULL:
with gil:
raise RuntimeError(f'Failed to init API, possibly an invalid
tessdata path: {path}')
@@ -2755,7 +2773,9 @@
if pix == NULL:
with gil:
raise RuntimeError('Failed to read picture')
+ sig_on()
text = _image_to_text(pix, clang, psm, cpath, oem)
+ sig_off()
if text == NULL:
with gil:
raise RuntimeError(f'Failed to init API, possibly an invalid
tessdata path: {path}')
@@ -2799,7 +2819,11 @@
int i
baseapi.Init(py_path, NULL)
path = baseapi.GetDatapath()
- baseapi.GetAvailableLanguagesAsVector(&v)
+ try:
+ baseapi.GetAvailableLanguagesAsVector(&v)
+ except RuntimeError:
+ baseapi.End()
+ raise
langs = [v[i].c_str() for i in range(v.size())]
baseapi.End()
return path, langs
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tesserocr-2.9.2/tesserocr.egg-info/PKG-INFO
new/tesserocr-2.11.0/tesserocr.egg-info/PKG-INFO
--- old/tesserocr-2.9.2/tesserocr.egg-info/PKG-INFO 2025-12-18
09:51:33.000000000 +0100
+++ new/tesserocr-2.11.0/tesserocr.egg-info/PKG-INFO 2026-08-04
13:59:54.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.4
Name: tesserocr
-Version: 2.9.2
+Version: 2.11.0
Summary: A simple, Pillow-friendly, Python wrapper around tesseract-ocr API
using Cython
Home-page: https://github.com/sirfz/tesserocr
Author: Fayez Zouheiry
@@ -12,7 +12,6 @@
Classifier: Topic :: Multimedia :: Graphics :: Capture :: Scanners
Classifier: Topic :: Multimedia :: Graphics :: Graphics Conversion
Classifier: Topic :: Scientific/Engineering :: Image Recognition
-Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: POSIX
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
@@ -27,6 +26,7 @@
Requires-Python: >=3.9
Description-Content-Type: text/x-rst
License-File: LICENSE
+Requires-Dist: cysignals
Dynamic: author
Dynamic: author-email
Dynamic: classifier
@@ -36,6 +36,7 @@
Dynamic: keywords
Dynamic: license
Dynamic: license-file
+Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tesserocr-2.9.2/tesserocr.egg-info/SOURCES.txt
new/tesserocr-2.11.0/tesserocr.egg-info/SOURCES.txt
--- old/tesserocr-2.9.2/tesserocr.egg-info/SOURCES.txt 2025-12-18
09:51:35.000000000 +0100
+++ new/tesserocr-2.11.0/tesserocr.egg-info/SOURCES.txt 2026-08-04
13:59:55.000000000 +0200
@@ -3,6 +3,8 @@
README.rst
pyproject.toml
setup.py
+.eggs/cysignals-1.12.5-py3.9-linux-x86_64.egg/cysignals/macros.h
+.eggs/cysignals-1.12.5-py3.9-linux-x86_64.egg/cysignals/struct_signals.h
tesserocr/__init__.py
tesserocr/__init__.pyi
tesserocr/tesseract.pxd
@@ -11,7 +13,9 @@
tesserocr.egg-info/PKG-INFO
tesserocr.egg-info/SOURCES.txt
tesserocr.egg-info/dependency_links.txt
+tesserocr.egg-info/requires.txt
tesserocr.egg-info/top_level.txt
tests/__init__.py
+tests/box.train
tests/eurotext.png
tests/test_api.py
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tesserocr-2.9.2/tesserocr.egg-info/requires.txt
new/tesserocr-2.11.0/tesserocr.egg-info/requires.txt
--- old/tesserocr-2.9.2/tesserocr.egg-info/requires.txt 1970-01-01
01:00:00.000000000 +0100
+++ new/tesserocr-2.11.0/tesserocr.egg-info/requires.txt 2026-08-04
13:59:54.000000000 +0200
@@ -0,0 +1 @@
+cysignals
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tesserocr-2.9.2/tests/box.train
new/tesserocr-2.11.0/tests/box.train
--- old/tesserocr-2.9.2/tests/box.train 1970-01-01 01:00:00.000000000 +0100
+++ new/tesserocr-2.11.0/tests/box.train 2026-08-04 13:59:43.000000000
+0200
@@ -0,0 +1,12 @@
+disable_character_fragments T
+file_type .bl
+textord_fast_pitch_test T
+tessedit_zero_rejection T
+tessedit_minimal_rejection F
+tessedit_write_rep_codes F
+edges_children_fix F
+edges_childarea 0.65
+edges_boxarea 0.9
+tessedit_resegment_from_boxes T
+tessedit_train_from_boxes T
+textord_no_rejects T
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tesserocr-2.9.2/tests/test_api.py
new/tesserocr-2.11.0/tests/test_api.py
--- old/tesserocr-2.9.2/tests/test_api.py 2025-12-18 09:51:29.000000000
+0100
+++ new/tesserocr-2.11.0/tests/test_api.py 2026-08-04 13:59:43.000000000
+0200
@@ -48,6 +48,7 @@
class TestTessBaseApi(unittest.TestCase):
_test_dir = os.path.abspath(os.path.dirname(__file__))
+ _config_file = os.path.join(_test_dir, "box.train")
_image_file = os.path.join(_test_dir, "eurotext.png")
def setUp(self):
@@ -77,13 +78,13 @@
self.assertEqual(self._api.GetVariableAsString("file_type"), ".tif")
self.assertEqual(self._api.GetVariableAsString("edges_childarea"),
"0.5")
# use box.train config variables
- configs = ["box.train"]
+ configs = [self._config_file]
# change edges_childarea
vars_ = {"edges_childarea": "0.7"}
self._api.End()
self._api.InitFull(configs=configs, variables=vars_)
# assert file_type from box.train and custom edges_childarea
- self.assertEqual(self._api.GetVariableAsString("file_type"), ".tif")
+ self.assertEqual(self._api.GetVariableAsString("file_type"), ".bl")
self.assertEqual(self._api.GetVariableAsString("edges_childarea"),
"0.7")
# reset back to default
self._api.End()