Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Various changes #2936

Merged
merged 15 commits into from
Dec 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
fb82e6b
docs/page.rst: added links to 'Description of get_links() Entries' se…
julian-smith-artifex-com Dec 20, 2023
38a4a5d
tests/test_imagebbox.py: fix handling of test failure.
julian-smith-artifex-com Dec 16, 2023
08734a8
src/__init__.py: allow extra debug exceptions diagnostics.
julian-smith-artifex-com Dec 18, 2023
2d20d04
tests/: added test_2904(), handling of corrupt JPX header.
julian-smith-artifex-com Dec 18, 2023
9cf377a
tests/: added test_2907() for segfault bug in classic.
julian-smith-artifex-com Dec 18, 2023
24423b0
scripts/: minor change to comments.
julian-smith-artifex-com Dec 18, 2023
be4b275
src/__init__.py: fix pymupdf_version_tuple.
julian-smith-artifex-com Dec 19, 2023
f3873fb
scripts/test.py: fixed handling of no build isolation, e.g. OpenBSD.
julian-smith-artifex-com Dec 20, 2023
dd87c19
scripts/gh_release.py: minor changes to diagnostics, and improved ven…
julian-smith-artifex-com Dec 21, 2023
6c9b340
tests/run_compound.py: added option to select which implementations t…
julian-smith-artifex-com Dec 21, 2023
3388371
scripts/test.py: improved cli, added various new options.
julian-smith-artifex-com Dec 21, 2023
1caef6e
tests/test_2904.py: update to match fixed mupdf master.
julian-smith-artifex-com Dec 21, 2023
2189c26
.github/workflows/test-valgrind.yml: fixed to use mupdf master.
julian-smith-artifex-com Dec 22, 2023
8e26ecf
Renamed fitz_old -> src_classic.
julian-smith-artifex-com Dec 22, 2023
f3594f4
setup.py: update to match rename to src_classic.
julian-smith-artifex-com Dec 22, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/test-valgrind.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ jobs:

- name: test_mupdf-master-branch
run:
python scripts/test.py --valgrind 1 buildtest
python scripts/test.py -m 'git:--recursive --depth 1 --shallow-submodules --branch master https://github.com/ArtifexSoftware/mupdf.git' --valgrind 1 buildtest
16 changes: 10 additions & 6 deletions docs/page.rst
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ In a nutshell, this is what you can do with PyMuPDF:

.. method:: bound()

Determine the rectangle of the page. Same as property :attr:`Page.rect` below. For PDF documents this **usually** also coincides with :data:`mediabox` and :data:`cropbox`, but not always. For example, if the page is rotated, then this is reflected by this method -- the :attr:`Page.cropbox` however will not change.
Determine the rectangle of the page. Same as property :attr:`Page.rect`. For PDF documents this **usually** also coincides with :data:`mediabox` and :data:`cropbox`, but not always. For example, if the page is rotated, then this is reflected by this method -- the :attr:`Page.cropbox` however will not change.

:rtype: :ref:`Rect`

Expand Down Expand Up @@ -480,19 +480,19 @@ In a nutshell, this is what you can do with PyMuPDF:

.. method:: delete_link(linkdict)

PDF only: Delete the specified link from the page. The parameter must be an **original item** of :meth:`get_links()` (see below). The reason for this is the dictionary's *"xref"* key, which identifies the PDF object to be deleted.
PDF only: Delete the specified link from the page. The parameter must be an **original item** of :meth:`get_links()`, see :ref:`link_dict_description`. The reason for this is the dictionary's *"xref"* key, which identifies the PDF object to be deleted.

:arg dict linkdict: the link to be deleted.

.. method:: insert_link(linkdict)

PDF only: Insert a new link on this page. The parameter must be a dictionary of format as provided by :meth:`get_links()` (see below).
PDF only: Insert a new link on this page. The parameter must be a dictionary of format as provided by :meth:`get_links()`, see :ref:`link_dict_description`.

:arg dict linkdict: the link to be inserted.

.. method:: update_link(linkdict)

PDF only: Modify the specified link. The parameter must be a (modified) **original item** of :meth:`get_links()` (see below). The reason for this is the dictionary's *"xref"* key, which identifies the PDF object to be changed.
PDF only: Modify the specified link. The parameter must be a (modified) **original item** of :meth:`get_links()`, see :ref:`link_dict_description`. The reason for this is the dictionary's *"xref"* key, which identifies the PDF object to be changed.

:arg dict linkdict: the link to be modified.

Expand All @@ -516,7 +516,7 @@ In a nutshell, this is what you can do with PyMuPDF:
Retrieves **all** links of a page.

:rtype: list
:returns: A list of dictionaries. For a description of the dictionary entries see below. Always use this or the :meth:`Page.links` method if you intend to make changes to the links of a page.
:returns: A list of dictionaries. For a description of the dictionary entries, see :ref:`link_dict_description`. Always use this or the :meth:`Page.links` method if you intend to make changes to the links of a page.

.. method:: links(kinds=None)

Expand Down Expand Up @@ -1952,6 +1952,8 @@ In a nutshell, this is what you can do with PyMuPDF:

-----

.. _link_dict_description:

Description of *get_links()* Entries
----------------------------------------
Each entry of the :meth:`Page.get_links` list is a dictionary with the following keys:
Expand All @@ -1968,7 +1970,9 @@ Each entry of the :meth:`Page.get_links` list is a dictionary with the following

* *uri*: a string specifying the destination internet resource. Required for *LINK_URI*, else ignored. You should make sure to start this string with an unambiguous substring, that classifies the subtype of the URL, like `"http://"`, `"https://"`, `"file://"`, `"ftp://"`, `"mailto:"`, etc. Otherwise your browser will try to interpret the text and come to unwanted / unexpected conclusions about the intended URL type.

* *xref*: an integer specifying the PDF :data:`xref` of the link object. Do not change this entry in any way. Required for link deletion and update, otherwise ignored. For non-PDF documents, this entry contains *-1*. It is also *-1* for **all** entries in the *get_links()* list, if **any** of the links is not supported by MuPDF - see the note below.
* *xref*: an integer specifying the PDF :data:`xref` of the link object. Do not change this entry in any way. Required for link deletion and update, otherwise ignored. For non-PDF documents, this entry contains *-1*. It is also *-1* for **all** entries in the *get_links()* list, if **any** of the links is not supported by MuPDF - see :ref:`notes_on_supporting_links`.

.. _notes_on_supporting_links:

Notes on Supporting Links
---------------------------
Expand Down
102 changes: 63 additions & 39 deletions scripts/gh_release.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#! /usr/bin/env python3

'''
Build+test script for PyMuPDF, mostly for use with github builds but can also
be used to build Pyodide wheels.
Build+test script for PyMuPDF using cibuildwheel. Mostly for use with github
builds but can also be used to build Pyodide wheels.

We run cibuild manually, in order to build and test the two wheel
flavours that make up PyMuPDF:
Expand Down Expand Up @@ -68,14 +68,17 @@
'''

import glob
import inspect
import os
import platform
import shlex
import sys
import subprocess
import sys
import textwrap


pymupdf_dir = os.path.abspath( f'{__file__}/../..')

def main():

log( '### main():')
Expand Down Expand Up @@ -284,7 +287,6 @@ def set_cibuild_test():
valgrind_text = ' --valgrind 1'
env_set('CIBW_TEST_COMMAND', f'python {{project}}/scripts/gh_release.py{valgrind_text} test {{project}} {{package}}')

pymupdf_dir = os.path.abspath( f'{__file__}/../..')
if pymupdf_dir != os.path.abspath( os.getcwd()):
log( f'Changing dir to {pymupdf_dir=}')
os.chdir( pymupdf_dir)
Expand Down Expand Up @@ -392,7 +394,15 @@ def build_pyodide_wheel( implementations):
run('ls -l wheelhouse/')


def venv( command=None, packages=None):
def cpu_bits():
return 32 if sys.maxsize == 2**31 - 1 else 64


# Name of venv used by `venv()`.
#
venv_name = f'venv-pymupdf-{platform.python_version()}-{cpu_bits()}'

def venv( command=None, packages=None, quick=False):
'''
Runs remaining args, or the specified command if present, in a venv.

Expand All @@ -401,8 +411,10 @@ def venv( command=None, packages=None):
to run the venv's python.
packages:
List of packages (or comma-separated string) to install.
quick:
If true and venv directory already exists, we don't recreate venv or
install Python packages in it.
'''
venv_name = f'venv-pymupdf-{platform.python_version()}-{cpu_bits()}'
command2 = ''
ssp = ''
if platform.system() == 'OpenBSD':
Expand All @@ -414,16 +426,23 @@ def venv( command=None, packages=None):
log(f'OpenBSD: system package `py3-llvm` must be installed.')
log(f'OpenBSD: creating venv with --system-site-packages.')
log(f'OpenBSD: `pip install .../PyMuPDF` must be preceded by install of swig etc.')
command2 += f'{sys.executable} -m venv{ssp} {venv_name}'
if quick and os.path.isdir(venv_name):
log(f'{quick=}: Not creating venv because directory already exists: {venv_name}')
command2 += 'true'
else:
command2 += f'{sys.executable} -m venv{ssp} {venv_name}'
if platform.system() == 'Windows':
command2 += f' && {venv_name}\\Scripts\\activate'
else:
command2 += f' && . {venv_name}/bin/activate'
command2 += ' && python -m pip install --upgrade pip'
if packages:
if isinstance(packages, str):
packages = packages.split(',')
command2 += ' && pip install ' + ' '.join(packages)
if quick:
log(f'{quick=}: Not upgrading pip or installing packages.')
else:
command2 += ' && python -m pip install --upgrade pip'
if packages:
if isinstance(packages, str):
packages = packages.split(',')
command2 += ' && pip install ' + ' '.join(packages)
command2 += ' &&'
if isinstance( command, str):
command2 += ' ' + command
Expand Down Expand Up @@ -578,40 +597,49 @@ def write( text, path):


if platform.system() == 'Windows':
def relpath(path):
def relpath(path, start=None):
try:
return os.path.relpath(__file__)
return os.path.relpath(path, start)
except ValueError:
# os.path.relpath() fails if trying to change drives.
return os.path.abspath(__file__)
return os.path.abspath(path)
else:
def relpath(path):
return os.path.relpath(__file__)


def log(text):
print(f'{relpath(__file__)}: {text}')
sys.stdout.flush()
def relpath(path, start=None):
return os.path.relpath(path, start)


def run(command, env_extra=None, env=None, check=1):
if env is None:
env = add_env(env_extra)
else:
assert env_extra is None
log(f'Running: {command}')
def log(text, caller=0):
'''
Writes `text` to stdout with prefix showing caller path relative to
pymupdf_dir and fn name.
'''
frame_record = inspect.stack( context=0)[ caller+1]
filename = frame_record.filename
line = frame_record.lineno
function = frame_record.function
prefix = f'{relpath(filename, pymupdf_dir)}:{function}(): '
print(textwrap.indent(text, prefix))
sys.stdout.flush()
subprocess.run(command, check=check, shell=1, env=env)


def add_env(env_extra):
env = os.environ.copy()
def run(command, env_extra=None, check=1):
'''
Runs a command using subprocess.run().
Args:
command:
The command to run.
env_extra:
None or dict containing extra environment variable settings to add
to os.environ.
check:
Whether to raise exception if command fails.
'''
env = None
if env_extra:
env = os.environ.copy()
env.update(env_extra)
log(f'Adding environment:')
for n, v in env_extra.items():
log(f' {n}: {v!r}')
return env
log(f'Running: {command}')
return subprocess.run(command, check=check, shell=1, env=env)


def platform_tag():
Expand All @@ -626,10 +654,6 @@ def platform_tag():
assert 0, f'Unrecognised: {platform.system()=}'


def cpu_bits():
return 32 if sys.maxsize == 2**31 - 1 else 64


# If this has changed, need to update
# .github/workflows/*.yml.
#
Expand Down
Loading
Loading