Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 10 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@ jobs:
pip install flake8
flake8 .

- name: Type check with mypy
run: |
# Pin mypy to <1.19 due to librt dependency in 1.19+
# which is not available on PyPy 3.9
pip install "mypy<1.19"
mypy pyvips/__init__.pyi --no-error-summary
mypy examples/affine.py examples/convolve.py examples/try5.py examples/watermark.py \
examples/annotate-animation.py examples/join-animation.py examples/progress.py \
--no-error-summary

- name: Install tox and any other packages
run: pip install tox

Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## Version 3.2.0 (released TBA)

- add comprehensive type hints for all pyvips operations via generated stubs [JoshCLWren]
- add operator overload type hints with array support (int, float, list[int], list[float]) [JoshCLWren]
- add hand-written binding type hints for common methods [JoshCLWren]
- add test coverage for type stubs [JoshCLWren]

## Version 3.1.1 (released 9 December 2025)

- fix get_gainmap arguments [jcupitt]
Expand Down
34 changes: 34 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,30 @@ Stylecheck:

$ flake8

Stylecheck:

.. code-block:: shell

$ flake8

Type checking:

pyvips includes type hints via PEP 561 type stub files (``pyvips/__init__.pyi``).
To enable type checking in your project, install a type checker like mypy:

.. code-block:: shell

$ pip install mypy pyvips

Then run mypy on your code:

.. code-block:: shell

$ mypy your_script.py

Note: ``pyvips`` methods accept arbitrary keyword arguments for libvips options,
which may not be fully covered by type hints.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this correct? We seem to have them all covered, I think.


Generate HTML docs in ``doc/build/html``:

.. code-block:: shell
Expand All @@ -246,6 +270,16 @@ then

Then check and move `enums.py` into `pyvips/`.

Regenerate type stubs:

After adding new libvips operations or updating libvips itself, regenerate type stubs:

.. code-block:: shell

$ python examples/generate_type_stubs.py

This updates ``pyvips/__init__.pyi`` with the latest operations.

Regenerate autodocs:

Make sure you have installed a libvips with all optional packages enabled,
Expand Down
70 changes: 38 additions & 32 deletions doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import os
import sys
import sphinx_rtd_theme

sys.path.insert(0, os.path.abspath('..'))


Expand Down Expand Up @@ -55,24 +56,24 @@
master_doc = 'index'

# General information about the project.
project = u'pyvips'
copyright = u'2019, John Cupitt'
author = u'John Cupitt'
project = 'pyvips'
copyright = '2019, John Cupitt'
author = 'John Cupitt'

# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = u'3.1'
version = u'3.2'
# The full version, including alpha/beta/rc tags.
release = u'3.1.1'
release = u'3.2.0'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
# Usually you set 'language' from the command line for these cases.
language = None

# List of patterns, relative to source directory, that match files and
Expand Down Expand Up @@ -103,7 +104,7 @@

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
# so a file named 'default.css' will overwrite the builtin 'default.css'.
html_static_path = ['_static']

# Custom sidebar templates, must be a dictionary that maps document names
Expand All @@ -126,7 +127,7 @@
# each page.
'github_user': 'libvips',
'github_repo': 'pyvips',
'github_version': 'master/doc/'
'github_version': 'master/doc/',
}

# -- Options for HTMLHelp output ------------------------------------------
Expand All @@ -141,15 +142,12 @@
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',

# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',

# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',

# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
Expand All @@ -159,19 +157,15 @@
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'pyvips.tex', u'pyvips Documentation',
u'john', 'manual'),
(master_doc, 'pyvips.tex', 'pyvips Documentation', 'john', 'manual'),
]


# -- Options for manual page output ---------------------------------------

# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'pyvips', u'pyvips Documentation',
[author], 1)
]
man_pages = [(master_doc, 'pyvips', 'pyvips Documentation', [author], 1)]


# -- Options for Texinfo output -------------------------------------------
Expand All @@ -180,19 +174,26 @@
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'pyvips', u'pyvips Documentation',
author, 'pyvips', 'One line description of project.',
'Miscellaneous'),
(
master_doc,
'pyvips',
'pyvips Documentation',
author,
'pyvips',
'One line description of project.',
'Miscellaneous',
),
]


# see https://stackoverflow.com/questions/20569011
# adds autoautosummary directive, see vimage.rst


# try to exclude deprecated
def skip_deprecated(app, what, name, obj, skip, options):
if hasattr(obj, "func_dict") and "__deprecated__" in obj.func_dict:
print("skipping " + name)
print('skipping ' + name)
return True
return skip or False

Expand All @@ -206,10 +207,9 @@ def setup(app):
from sphinx.util.inspect import safe_getattr

class AutoAutoSummary(Autosummary):

option_spec = {
'methods': directives.unchanged,
'attributes': directives.unchanged
'attributes': directives.unchanged,
}

required_arguments = 1
Expand All @@ -227,8 +227,10 @@ def get_members(obj, typ, include_public=None):
continue
if documenter.objtype == typ:
items.append(name)
public = [x for x in items
if x in include_public or not x.startswith('_')]
public = [
x for x in items
if x in include_public or not x.startswith('_')
]
return public, items

def run(self):
Expand All @@ -242,17 +244,21 @@ def run(self):
_, methods = self.get_members(c,
'method', ['__init__'])

self.content = ["~%s.%s" % (clazz, method)
for method in methods
if not method.startswith('_')]
self.content = [
'~%s.%s' % (clazz, method)
for method in methods
if not method.startswith('_')
]
if 'attributes' in self.options:
_, attribs = self.get_members(c, 'attribute')
self.content = ["~%s.%s" % (clazz, attrib)
for attrib in attribs
if not attrib.startswith('_')]
self.content = [
'~%s.%s' % (clazz, attrib)
for attrib in attribs
if not attrib.startswith('_')
]
finally:
return super(AutoAutoSummary, self).run()

app.add_directive('autoautosummary', AutoAutoSummary)
app.add_directive("autoautosummary", AutoAutoSummary)
except BaseException as e:
raise e
Loading