Skip to content

Commit

Permalink
Merge branch 'main' into ignore-0-width-rect
Browse files Browse the repository at this point in the history
  • Loading branch information
julian-smith-artifex-com authored Jun 17, 2024
2 parents 0a23d19 + a86fa11 commit 97c19e7
Show file tree
Hide file tree
Showing 10 changed files with 119 additions and 45 deletions.
Binary file modified docs/_static/PyMuPDF.ico
Binary file not shown.
Binary file modified docs/_static/pymupdf-sidebar-logo-dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/_static/pymupdf-sidebar-logo-light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
42 changes: 28 additions & 14 deletions pipcl.py
Original file line number Diff line number Diff line change
Expand Up @@ -2075,49 +2075,63 @@ def run_if( command, out, *prerequisites):
>>> out = 'run_if_test_out'
>>> if os.path.exists( out):
... os.remove( out)
>>> if os.path.exists( f'{out}.cmd'):
... os.remove( f'{out}.cmd')
>>> run_if( f'touch {out}', out)
pipcl.py: run_if(): Running command because: File does not exist: 'run_if_test_out'
pipcl.py: run(): Running: touch run_if_test_out
True
If we repeat, the output file will be up to date so the command is not run:
>>> run_if( f'touch {out}', out)
pipcl.py: run_if(): Not running command because up to date: 'run_if_test_out'
If we change the command, the command is run:
>>> run_if( f'touch {out}', out)
pipcl.py: run_if(): Running command because: Command has changed
pipcl.py: run(): Running: touch run_if_test_out
True
If we add a prerequisite that is newer than the output, the command is run:
>>> time.sleep(1)
>>> prerequisite = 'run_if_test_prerequisite'
>>> run( f'touch {prerequisite}')
>>> run_if( f'touch {out}', out, prerequisite)
pipcl.py: run(): Running: touch run_if_test_prerequisite
>>> run_if( f'touch {out}', out, prerequisite)
pipcl.py: run_if(): Running command because: Prerequisite is new: 'run_if_test_prerequisite'
pipcl.py: run(): Running: touch run_if_test_out
True
If we repeat, the output will be newer than the prerequisite, so the
command is not run:
>>> run_if( f'touch {out}', out, prerequisite)
>>> run_if( f'touch {out}', out, prerequisite)
pipcl.py: run_if(): Not running command because up to date: 'run_if_test_out'
'''
doit = False
cmd_path = f'{out}.cmd'

if not doit:
out_mtime = _fs_mtime( out)
if out_mtime == 0:
doit = f'File does not exist: {out!r}'

cmd_path = f'{out}.cmd'
if os.path.isfile( cmd_path):
with open( cmd_path) as f:
cmd = f.read()
else:
cmd = None
if command != cmd:
if cmd is None:
doit = 'No previous command stored'
if not doit:
if os.path.isfile( cmd_path):
with open( cmd_path) as f:
cmd = f.read()
else:
doit = f'Command has changed'
if 0:
doit += f': {cmd!r} => {command!r}'
cmd = None
if command != cmd:
if cmd is None:
doit = 'No previous command stored'
else:
doit = f'Command has changed'
if 0:
doit += f': {cmd!r} => {command!r}'

if not doit:
# See whether any prerequisites are newer than target.
Expand Down
4 changes: 3 additions & 1 deletion scripts/gh_release.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,9 @@ def set_if_unset(name, value):
set_if_unset( 'CIBW_BUILD_VERBOSITY', '3')
# We exclude pp* because of `fitz_wrap.obj : error LNK2001: unresolved
# external symbol PyUnicode_DecodeRawUnicodeEscape`.
set_if_unset( 'CIBW_SKIP', '"pp* *i686 cp36* cp37*"')
# 2024-06-05: musllinux on aarch64 fails because libclang cannot find
# libclang.so.
set_if_unset( 'CIBW_SKIP', '"pp* *i686 cp36* cp37* *musllinux*aarch64*"')

def make_string(*items):
ret = list()
Expand Down
82 changes: 59 additions & 23 deletions scripts/sysinstall.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
'''
Test for Linux system install of MuPDF and PyMuPDF.
We build and install MuPDF and PyMuPDF into a root directory, then run
PyMuPDF's pytest tests with LD_PRELOAD_PATH and PYTHONPATH set.
We build and install MuPDF and PyMuPDF into a root directory, then use
scripts/test.py to run PyMuPDF's pytest tests with LD_PRELOAD_PATH and
PYTHONPATH set.
PyMuPDF itself is installed using `python -m install` with a wheel created with
`pip wheel`.
Expand All @@ -21,6 +22,8 @@
--mupdf-dir <mupdf_dir>
Path of MuPDF checkout; default is 'mupdf'.
--mupdf-do 0|1
Whether to build and install mupdf.
--mupdf-git <git_args>
Get or update `mupdf_dir` using git. If `mupdf_dir` already
exists we run `git pull` in it; otherwise we run `git
Expand All @@ -43,6 +46,8 @@
Directory within `root`; default is `/usr/local`. Must start with `/`.
--pymupdf-dir <pymupdf_dir>
Path of PyMuPDF checkout; default is 'PyMuPDF'.
--pymupdf-do 0|1
Whether to build and install pymupdf.
--root <root>
Root of install directory; default is `/`.
--tesseract5 0|1
Expand All @@ -57,15 +62,14 @@
If 1 (the default), we use `python -m installer` to install PyMuPDF
from a generated wheel. [Otherwise we use `pip install`, which refuses
to do a system install with `--root /`, referencing PEP-668.]
-m 0|1
If 1 (the default) we build and install MuPDF, otherwise we just show
what command we would have run.
-p 0|1
If 1 (the default) we build and install PyMuPDF, otherwise we just show
what command we would have run.
-t 0|1
If 1 (the default) we run PyMuPDF's pytest tests, otherwise we just
show what command we would have run.
-i <implementations>
Passed through to scripts/test.py.
-f <test-fitz>
Passed through to scripts/test.py.
-p <pytest-options>
Passed through to scripts/test.py.
-t <names>
Passed through to scripts/test.py.
To only show what commands would be run, but not actually run them, specify `-m
0 -p 0 -t 0`.
Expand All @@ -75,6 +79,7 @@
import multiprocessing
import os
import platform
import shlex
import subprocess
import sys
import sysconfig
Expand Down Expand Up @@ -117,19 +122,23 @@ def main():
# Set default behaviour.
#
use_installer = True
mupdf = True
mupdf_do = True
mupdf_dir = 'mupdf'
mupdf_git = None
mupdf_so_mode = None
packages = True
prefix = '/usr/local'
pymupdf = True
pymupdf_do = True
pymupdf_dir = os.path.abspath( f'{__file__}/../..')
root = 'sysinstall_test'
tesseract5 = True
test = True
pytest_args = None
pytest_do = True
pytest_name = None
test_venv = 'venv-pymupdf-sysinstall-test'
pip = 'venv'
test_fitz = None
test_implementations = None

# Parse command-line.
#
Expand All @@ -142,20 +151,24 @@ def main():
if arg in ('-h', '--help'):
print(__doc__)
return
elif arg == '--mupdf-do': mupdf_do = int(next(args))
elif arg == '--mupdf-dir': mupdf_dir = next(args)
elif arg == '--mupdf-git': mupdf_git = next(args)
elif arg == '--mupdf-so-mode': mupdf_so_mode = next(args)
elif arg == '--packages': packages = int(next(args))
elif arg == '--prefix': prefix = next(args)
elif arg == '--pymupdf-do': pymupdf_do = int(next(args))
elif arg == '--pymupdf-dir': pymupdf_dir = next(args)
elif arg == '--root': root = next(args)
elif arg == '--tesseract5': tesseract5 = int(next(args))
elif arg == '--pytest-do': pytest_do = int(next(args))
elif arg == '--test-venv': test_venv = next(args)
elif arg == '--use-installer': use_installer = int(next(args))
elif arg == '--pip': pip = next(args)
elif arg == '-m': mupdf = int(next(args))
elif arg == '-p': pymupdf = int(next(args))
elif arg == '-t': test = int(next(args))
elif arg == '-f': test_fitz = next(args)
elif arg == '-i': test_implementations = next(args)
elif arg == '-p': pytest_args = next(args)
elif arg == '-t': pytest_name = next(args)
else:
assert 0, f'Unrecognised arg: {arg!r}'

Expand All @@ -169,7 +182,7 @@ def main():
if root == '/':
sudo = f'sudo PATH={os.environ["PATH"]} '
def run(command):
return run_command(command, doit=mupdf)
return run_command(command, doit=mupdf_do)
# Get MuPDF from git if specified.
#
if mupdf_git:
Expand Down Expand Up @@ -232,7 +245,7 @@ def run(command):
#
print('## Build and install PyMuPDF.')
def run(command):
return run_command(command, doit=pymupdf)
return run_command(command, doit=pymupdf_do)
flags_freetype2 = run_command('pkg-config --cflags freetype2', capture_output=1).stdout.strip()
compile_flags = f'-I {root_prefix}/include {flags_freetype2}'
link_flags = f'-L {root_prefix}/lib'
Expand Down Expand Up @@ -316,7 +329,7 @@ def run(command):
#
print('## Run PyMuPDF pytest tests.')
def run(command):
return run_command(command, doit=test)
return run_command(command, doit=pytest_do)
import gh_release
if pip == 'venv':
# Create venv.
Expand All @@ -342,9 +355,32 @@ def run(command):
run(f'ls -l {root_prefix}/bin/')
# 2024-03-20: Not sure whether/where `pymupdf` binary is installed, so we
# disable the test_cli* tests.
excluded_tests = 'test_color_count test_3050 test_cli test_cli_out test_pylint test_textbox3'.split()
excluded_tests = ' and not '.join(excluded_tests)
command += f' {pymupdf_dir}/scripts/test.py -p "-k \'not {excluded_tests}\'" -v 0 test'
command += f' {pymupdf_dir}/scripts/test.py'
command += f' -v 0'
if pytest_name is None:
excluded_tests = (
'test_color_count',
'test_3050',
'test_cli',
'test_cli_out',
'test_pylint',
'test_textbox3',
'test_3493',
)
excluded_tests = ' and not '.join(excluded_tests)
if not pytest_args:
pytest_args = ''
pytest_args += f' -k \'not {excluded_tests}\''
else:
command += f' -t {pytest_name}'
if test_fitz:
command += f' -f {test_fitz}'
if test_implementations:
command += f' -i {test_implementations}'
if pytest_args:
command += f' -p {shlex.quote(pytest_args)}'
if pytest_do:
command += ' test'
run(command)


Expand Down
20 changes: 14 additions & 6 deletions src/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2803,12 +2803,20 @@ def __init__(self, filename=None, stream=None, filetype=None, rect=None, width=0
stream = mupdf.FzStream(filename)
accel = mupdf.FzStream()
archive = mupdf.FzArchive(None)
doc = mupdf.ll_fz_document_open_fn_call(
handler.open,
stream.m_internal,
accel.m_internal,
archive.m_internal,
)
if mupdf_version_tuple >= (1, 25):
doc = mupdf.ll_fz_document_handler_open(
handler,
stream.m_internal,
accel.m_internal,
archive.m_internal,
)
else:
doc = mupdf.ll_fz_document_open_fn_call(
handler.open,
stream.m_internal,
accel.m_internal,
archive.m_internal,
)
else:
doc = mupdf.ll_fz_document_open_fn_call( handler.open, filename)
except Exception as e:
Expand Down
Binary file modified tests/resources/test_1645_expected_1.25.pdf
Binary file not shown.
5 changes: 4 additions & 1 deletion tests/test_pixmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,9 @@ def test_3493():
If python3-gi is installed, we check fix for #3493, where importing gi
would load an older version of libjpeg than is used in MuPDF, and break
MuPDF.
This test is excluded by default in sysinstall tests, because running
commands in a new venv does not seem to pick up pymupdf as expected.
'''
if platform.system() != 'Linux':
print(f'Not running because not Linux: {platform.system()=}')
Expand Down Expand Up @@ -315,7 +318,7 @@ def run_code(code, code_path, *, check=True, venv=None, venv_args='', pythonpath
return
gi = r.stdout.strip()
gi_pythonpath = os.path.abspath(f'{gi}/../..')

def do(gi):
# Run code that will import gi and pymupdf in different orders, and
# return contents of generated .png file as a bytes.
Expand Down
11 changes: 11 additions & 0 deletions tests/test_textbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,3 +260,14 @@ def test_htmlbox3():
# lowlevel-extract inserted text to access opacity
span = page.get_texttrace()[0]
assert span["opacity"] == 0.5


def test_3559():
if pymupdf.mupdf_version_tuple < (1, 24, 4):
print(f'test_3559(): Not running because mupdf known to SEGV.')
return
doc = pymupdf.Document()
page = doc.new_page()
text_insert="""<body><h3></h3></body>"""
rect = pymupdf.Rect(100, 100, 200, 200)
page.insert_htmlbox(rect, text_insert)

0 comments on commit 97c19e7

Please sign in to comment.