Compare commits

...
8 Commits
10 changed files with 51 additions and 39 deletions
+3 -3
View File
@@ -19,16 +19,16 @@ repos:
language_version: python language_version: python
exclude: ^src/ocrmypdf/lib/_leptonica.py exclude: ^src/ocrmypdf/lib/_leptonica.py
- repo: https://github.com/asottile/setup-cfg-fmt - repo: https://github.com/asottile/setup-cfg-fmt
rev: v1.17.0 rev: v1.19.0
hooks: hooks:
- id: setup-cfg-fmt - id: setup-cfg-fmt
- repo: https://github.com/asottile/pyupgrade - repo: https://github.com/asottile/pyupgrade
rev: v2.26.0 rev: v2.29.0
hooks: hooks:
- id: pyupgrade - id: pyupgrade
args: ["--py36-plus"] args: ["--py36-plus"]
- repo: https://github.com/pre-commit/mirrors-mypy - repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.910 rev: v0.910-1
hooks: hooks:
- id: mypy - id: mypy
additional_dependencies: additional_dependencies:
+10
View File
@@ -18,6 +18,16 @@ wish to use some of its features for working with PDFs.
for Python 3.6 around that time. The change will be marked with a major for Python 3.6 around that time. The change will be marked with a major
release. release.
v12.7.2
=======
- Fixed "invalid version number" error for Tesseract packaging with nonstandard
version "5.0.0-rc1.20211030".
- Fixed use of deprecated ``importlib.resources.read_binary``.
- Replace some uses of string paths with ``pathlib.Path``.
- Fixed a leaked file handle when using ``--output-type none``.
- Removed shims to support versions of pikepdf that are no longer supported.
v12.7.1 v12.7.1
======= =======
+6 -5
View File
@@ -28,6 +28,7 @@ classifiers =
Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
Topic :: Scientific/Engineering :: Image Recognition Topic :: Scientific/Engineering :: Image Recognition
Topic :: Text Processing :: Indexing Topic :: Text Processing :: Indexing
Topic :: Text Processing :: Linguistic Topic :: Text Processing :: Linguistic
@@ -49,14 +50,14 @@ install_requires =
cffi>=1.9.1 # must be a setup and install requirement cffi>=1.9.1 # must be a setup and install requirement
coloredlogs>=14.0 # strictly optional coloredlogs>=14.0 # strictly optional
img2pdf>=0.3.0,<0.5 # pure Python img2pdf>=0.3.0,<0.5 # pure Python
importlib-metadata>=4;python_version<'3.8' # until Python 3.8
importlib-resources>=5;python_version<'3.9' # until Python 3.9
pdfminer.six!=20200720,>=20191110,<=20211012 pdfminer.six!=20200720,>=20191110,<=20211012
pikepdf>=2.10.0 pikepdf>=2.10.0
pikepdf<3;implementation_name=="pypy" and python_version=='3.6'
pluggy>=0.13.0,<2 pluggy>=0.13.0,<2
reportlab>=3.5.66 reportlab>=3.5.66
tqdm>=4 tqdm>=4
importlib-metadata>=4;python_version<'3.8' # until Python 3.8
importlib-resources>=5;python_version<'3.9' # until Python 3.9
pikepdf<3;implementation_name=="pypy" and python_version=='3.6'
python_requires = >=3.6 python_requires = >=3.6
include_package_data = True include_package_data = True
package_dir = package_dir =
@@ -64,8 +65,8 @@ package_dir =
platforms = any platforms = any
setup_requires = setup_requires =
cffi>=1.9.1 # to build the leptonica module cffi>=1.9.1 # to build the leptonica module
setuptools_scm setuptools-scm
setuptools_scm_git_archive setuptools-scm-git-archive
zip_safe = False zip_safe = False
[options.packages.find] [options.packages.find]
+9 -11
View File
@@ -8,9 +8,7 @@
"""Interface to Tesseract executable""" """Interface to Tesseract executable"""
import logging import logging
import os
import re import re
import shutil
from collections import namedtuple from collections import namedtuple
from distutils.version import StrictVersion from distutils.version import StrictVersion
from os import fspath from os import fspath
@@ -61,8 +59,8 @@ class TesseractVersion(StrictVersion):
r''' r'''
^(\d+) \. (\d+) (\. (\d+))? # groups: 1/major, 2/minor, 3/[skip], 4/patch ^(\d+) \. (\d+) (\. (\d+))? # groups: 1/major, 2/minor, 3/[skip], 4/patch
[-]? # optional hyphen separator [-]? # optional hyphen separator
(?:(alpha|beta|rc|dev)?[.\-\ ]?(\d+)?)? # 5/prerelease, 6/prerelease_num (?: ((?:alpha|beta|rc|dev)\d*)? [.\-\ ]? (\d+)? )? # 5/prerelease, 6/prerelease_num
(?:-(\d+)-g[0-9a-f]+)? # untagged git version (?:(?:-\d+)?-g[0-9a-f]+)? # untagged git version
$ $
''', ''',
re.VERBOSE | re.ASCII, re.VERBOSE | re.ASCII,
@@ -73,7 +71,7 @@ class TesseractVersion(StrictVersion):
super().parse(vstring) super().parse(vstring)
except TypeError as e: except TypeError as e:
if 'int() argument must be a string' in str(e): if 'int() argument must be a string' in str(e):
super().parse(vstring + '0') super().parse(vstring + '-0')
def version(): def version():
@@ -250,7 +248,7 @@ def generate_hocr(
# Reminder: test suite tesseract test plugins will break after any changes # Reminder: test suite tesseract test plugins will break after any changes
# to the number of order parameters here # to the number of order parameters here
args_tesseract.extend([os.fspath(input_file), os.fspath(prefix), 'hocr', 'txt']) args_tesseract.extend([fspath(input_file), fspath(prefix), 'hocr', 'txt'])
args_tesseract.extend(tessconfig) args_tesseract.extend(tessconfig)
try: try:
p = run(args_tesseract, stdout=PIPE, stderr=STDOUT, timeout=timeout, check=True) p = run(args_tesseract, stdout=PIPE, stderr=STDOUT, timeout=timeout, check=True)
@@ -273,7 +271,7 @@ def generate_hocr(
# The sidecar text file will get the suffix .txt; rename it to # The sidecar text file will get the suffix .txt; rename it to
# whatever caller wants it named # whatever caller wants it named
if prefix.with_suffix('.txt').exists(): if prefix.with_suffix('.txt').exists():
shutil.move(prefix.with_suffix('.txt'), output_text) prefix.with_suffix('.txt').replace(output_text)
def use_skip_page(output_pdf, output_text): def use_skip_page(output_pdf, output_text):
@@ -320,18 +318,18 @@ def generate_pdf(
if user_patterns: if user_patterns:
args_tesseract.extend(['--user-patterns', user_patterns]) args_tesseract.extend(['--user-patterns', user_patterns])
prefix = os.path.splitext(output_pdf)[0] # Tesseract appends suffixes prefix = output_pdf.parent / Path(output_pdf.stem)
# Reminder: test suite tesseract test plugins might break after any changes # Reminder: test suite tesseract test plugins might break after any changes
# to the number of order parameters here # to the number of order parameters here
args_tesseract.extend([os.fspath(input_file), os.fspath(prefix), 'pdf', 'txt']) args_tesseract.extend([fspath(input_file), fspath(prefix), 'pdf', 'txt'])
args_tesseract.extend(tessconfig) args_tesseract.extend(tessconfig)
try: try:
p = run(args_tesseract, stdout=PIPE, stderr=STDOUT, timeout=timeout, check=True) p = run(args_tesseract, stdout=PIPE, stderr=STDOUT, timeout=timeout, check=True)
stdout = p.stdout stdout = p.stdout
if os.path.exists(prefix + '.txt'): if prefix.with_suffix('.txt').exists():
shutil.move(prefix + '.txt', output_text) prefix.with_suffix('.txt').replace(output_text)
except TimeoutExpired: except TimeoutExpired:
page_timedout(timeout) page_timedout(timeout)
use_skip_page(output_pdf, output_text) use_skip_page(output_pdf, output_text)
+3 -3
View File
@@ -290,10 +290,10 @@ def exec_concurrent(context: PdfContext, executor: Executor):
# Copy text file to destination # Copy text file to destination
copy_final(text, options.sidecar, context) copy_final(text, options.sidecar, context)
if options.output_type != 'none': # Merge layers to one single pdf
# Merge layers to one single pdf pdf = ocrgraft.finalize()
pdf = ocrgraft.finalize()
if options.output_type != 'none':
# PDF/A and metadata # PDF/A and metadata
log.info("Postprocessing...") log.info("Postprocessing...")
pdf = post_process(pdf, context, executor) pdf = post_process(pdf, context, executor)
+4 -2
View File
@@ -160,10 +160,12 @@ def _pages_from_ranges(ranges: str) -> Set[int]:
try: try:
new_pages = list(range(int(start) - 1, int(end))) new_pages = list(range(int(start) - 1, int(end)))
if not new_pages: if not new_pages:
raise BadArgsError(f"invalid page subrange '{start}-{end}'") raise BadArgsError(
f"invalid page subrange '{start}-{end}'"
) from None
pages.extend(new_pages) pages.extend(new_pages)
except ValueError: except ValueError:
raise BadArgsError("invalid page range") from None raise BadArgsError(f"invalid page subrange '{g}'") from None
if not pages: if not pages:
raise BadArgsError( raise BadArgsError(
+1 -9
View File
@@ -221,15 +221,7 @@ def check_pdf(input_file: Path) -> bool:
# If linearization is missing entirely, we do not complain. We do # If linearization is missing entirely, we do not complain. We do
# complain if linearization is present but incorrect. # complain if linearization is present but incorrect.
pdf.check_linearization(sio) pdf.check_linearization(sio)
except RuntimeError: except (RuntimeError, pikepdf.ForeignObjectError):
pass
except (
# Workaround for a problematic pikepdf version
# pragma: no cover
pikepdf.ForeignObjectError
if pikepdf.__version__ == '2.1.0'
else NeverRaise
):
pass pass
else: else:
linearize_msgs = sio.getvalue() linearize_msgs = sio.getvalue()
+4 -1
View File
@@ -585,7 +585,10 @@ def optimize(
log.info(f"Optimize ratio: {ratio:.2f} savings: {(savings):.1%}") log.info(f"Optimize ratio: {ratio:.2f} savings: {(savings):.1%}")
if savings < 0: if savings < 0:
log.info("Image optimization did not improve the file - discarded") log.info(
"Image optimization did not improve the file - "
"optimizations will not be used"
)
# We still need to save the file # We still need to save the file
with Pdf.open(input_file) as pike: with Pdf.open(input_file) as pike:
pike.remove_unreferenced_resources() pike.remove_unreferenced_resources()
+4 -5
View File
@@ -14,9 +14,10 @@ from pathlib import Path
from typing import Dict, Iterator, Union from typing import Dict, Iterator, Union
try: try:
from importlib_resources import read_binary from importlib_resources import files as package_files
except ImportError: except ImportError:
from importlib.resources import read_binary from importlib.resources import files as package_files
import pikepdf import pikepdf
import pkg_resources # deprecated import pkg_resources # deprecated
@@ -107,9 +108,7 @@ def generate_pdfa_ps(target_filename: Path, icc: str = 'sRGB'):
if icc != 'sRGB': if icc != 'sRGB':
raise NotImplementedError("Only supporting sRGB") raise NotImplementedError("Only supporting sRGB")
bytes_icc_profile = read_binary( bytes_icc_profile = (package_files('ocrmypdf.data') / SRGB_ICC_PROFILE).read_bytes()
'ocrmypdf.data', SRGB_ICC_PROFILE_NAME
)
ps = '\n'.join(_make_postscript(icc, bytes_icc_profile, 3)) ps = '\n'.join(_make_postscript(icc, bytes_icc_profile, 3))
# We should have encoded everything to pure ASCII by this point, and # We should have encoded everything to pure ASCII by this point, and
+7
View File
@@ -238,6 +238,13 @@ def test_version_comparison():
need_version='4.0.0', need_version='4.0.0',
version_parser=TesseractVersion, version_parser=TesseractVersion,
) )
vd.check_external_program(
program="tesseract",
package="tesseract",
version_checker=lambda: '5.0.0-rc1.20211030',
need_version='4.0.0',
version_parser=TesseractVersion,
)
vd.check_external_program( vd.check_external_program(
program="tesseract", program="tesseract",
package="tesseract", package="tesseract",