Skip to content

Commit 7f928a3

Browse files
authored
Update pre-commit config to add some python checkers (#788)
This PR adds some additional pre-commit checkers for our `.py` files. jaimergp I know you are working through automation stuff so adding you here as well.
1 parent 640705d commit 7f928a3

File tree

2 files changed

+112
-68
lines changed

2 files changed

+112
-68
lines changed

.pre-commit-config.yaml

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,34 @@
11
repos:
2-
- repo: https://github.com/pre-commit/pre-commit-hooks
3-
rev: v4.4.0
4-
hooks:
5-
- id: trailing-whitespace
2+
- repo: https://github.com/pre-commit/pre-commit-hooks
3+
rev: "v5.0.0"
4+
hooks:
5+
- id: check-added-large-files
6+
- id: check-case-conflict
7+
- id: check-merge-conflict
8+
- id: check-symlinks
9+
- id: check-yaml
10+
- id: debug-statements
11+
- id: end-of-file-fixer
12+
- id: mixed-line-ending
13+
- id: trailing-whitespace
14+
exclude: .*\.md
615

716
- repo: https://github.com/codespell-project/codespell
817
# Configuration for codespell is in .codespellrc
918
rev: v2.4.0
1019
hooks:
1120
- id: codespell
21+
22+
- repo: https://github.com/astral-sh/ruff-pre-commit
23+
rev: v0.12.3
24+
hooks:
25+
# Run the linter.
26+
- id: ruff-check
27+
types_or: [ python, pyi ]
28+
args: [--fix]
29+
# Run the formatter.
30+
- id: ruff-format
31+
types_or: [ python, pyi ]
32+
33+
default_language_version:
34+
python: python3.13

docs/conf.py

Lines changed: 85 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@
1818
from pathlib import Path
1919
from urllib.parse import urlparse, urlunparse
2020

21-
2221
from jinja2.filters import FILTERS
2322
from packaging.version import parse as parse_version
2423
from pygments.lexers import TOMLLexer
24+
from sphinx_gallery import gen_rst
2525
from sphinx_gallery import scrapers
2626
from sphinx_gallery.sorting import ExampleTitleSortKey
2727
from sphinx.highlighting import lexers
@@ -41,9 +41,9 @@
4141

4242
# -- Project information ---------------------------------------------------
4343

44-
project = 'napari'
45-
copyright = f'{datetime.now().year}, The napari team'
46-
author = 'The napari team'
44+
project = "napari"
45+
copyright = f"{datetime.now().year}, The napari team"
46+
author = "The napari team"
4747

4848
# -- Sphinx extensions -------------------------------------------------------
4949

@@ -68,7 +68,7 @@
6868
# -- HTML Theme ------------------------------------------------------------
6969

7070
# See https://github.com/napari/napari-sphinx-theme for more information.
71-
html_theme = 'napari_sphinx_theme'
71+
html_theme = "napari_sphinx_theme"
7272
html_title = "napari"
7373
html_sourcelink_suffix = ""
7474

@@ -142,48 +142,48 @@
142142
# sidebar content
143143
html_sidebars = {
144144
"**": ["search-field.html", "sidebar-nav-bs"],
145-
"index": ["search-field.html" , "sidebar-link-items.html"],
145+
"index": ["search-field.html", "sidebar-link-items.html"],
146146
}
147147

148148
# html context is passed into the template engine’s context for all pages.
149149
html_context = {
150-
# use Light theme only, don't auto switch (default)
151-
"default_mode": "light",
152-
# add release version to context
153-
"release": release,
154-
"version": version,
150+
# use Light theme only, don't auto switch (default)
151+
"default_mode": "light",
152+
# add release version to context
153+
"release": release,
154+
"version": version,
155155
}
156156

157157
# intersphinx configuration for frequently used links to other projects
158158
intersphinx_mapping = {
159-
'python': ['https://docs.python.org/3', None],
160-
'numpy': ['https://numpy.org/doc/stable/', None],
161-
'napari_plugin_engine': [
162-
'https://napari-plugin-engine.readthedocs.io/en/latest/',
163-
'https://napari-plugin-engine.readthedocs.io/en/latest/objects.inv',
159+
"python": ["https://docs.python.org/3", None],
160+
"numpy": ["https://numpy.org/doc/stable/", None],
161+
"napari_plugin_engine": [
162+
"https://napari-plugin-engine.readthedocs.io/en/latest/",
163+
"https://napari-plugin-engine.readthedocs.io/en/latest/objects.inv",
164164
],
165-
'magicgui': [
166-
'https://pyapp-kit.github.io/magicgui/',
167-
'https://pyapp-kit.github.io/magicgui/objects.inv',
165+
"magicgui": [
166+
"https://pyapp-kit.github.io/magicgui/",
167+
"https://pyapp-kit.github.io/magicgui/objects.inv",
168168
],
169-
'app-model': [
170-
'http://app-model.readthedocs.io/en/latest/',
171-
'http://app-model.readthedocs.io/en/latest/objects.inv',
169+
"app-model": [
170+
"http://app-model.readthedocs.io/en/latest/",
171+
"http://app-model.readthedocs.io/en/latest/objects.inv",
172172
],
173-
'vispy': [
174-
'https://vispy.org/',
175-
'https://vispy.org/objects.inv',
173+
"vispy": [
174+
"https://vispy.org/",
175+
"https://vispy.org/objects.inv",
176176
],
177177
}
178178

179179
# myst markdown extensions for additional markdown features
180180
myst_enable_extensions = [
181-
'colon_fence',
182-
'dollarmath',
183-
'substitution',
184-
'tasklist',
185-
'attrs_inline',
186-
'linkify',
181+
"colon_fence",
182+
"dollarmath",
183+
"substitution",
184+
"tasklist",
185+
"attrs_inline",
186+
"linkify",
187187
]
188188
myst_footnote_transition = False
189189
myst_heading_anchors = 4
@@ -195,7 +195,7 @@
195195
lexers["toml"] = TOMLLexer(startinline=True)
196196
napoleon_custom_sections = [("Events", "params_style")]
197197
# use an env var to control whether noteboos are executed
198-
nb_execution_mode = os.environ.get('NB_EXECUTION_MODE', 'auto')
198+
nb_execution_mode = os.environ.get("NB_EXECUTION_MODE", "auto")
199199
nb_output_stderr = "show"
200200
mermaid_d3_zoom = True
201201
mermaid_version = "11.4.1"
@@ -211,14 +211,14 @@
211211
# OpenGraph configuration for link previews
212212

213213
ogp_site_url = "https://napari.org/"
214-
ogp_image = "dev/_static/opengraph_image.png"
214+
ogp_image = "dev/_static/opengraph_image.png"
215215
ogp_use_first_image = False
216216
ogp_description_length = 300
217217
ogp_type = "website"
218218
ogp_site_name = "napari"
219219
ogp_canonical_url = "https://napari.org/stable"
220220
ogp_social_cards = {
221-
'image': '_static/logo.png',
221+
"image": "_static/logo.png",
222222
}
223223

224224
# glob-style patterns to exclude from docs build source files
@@ -235,23 +235,33 @@
235235

236236
# -- Versions and switcher -------------------------------------------------
237237

238+
238239
def get_supported_python_versions(project_name):
239240
"""
240241
Get the supported Python versions for a given project
241242
based on the classifiers in its distribution metadata.
242243
"""
243244
dist = distribution(project_name)
244-
classifiers = [value for key, value in dist.metadata.items() if key == 'Classifier' and value.startswith('Programming Language :: Python ::')]
245-
return [parse_version(c.split(' :: ')[-1]) for c in classifiers if not c.endswith('Only')]
245+
classifiers = [
246+
value
247+
for key, value in dist.metadata.items()
248+
if key == "Classifier" and value.startswith("Programming Language :: Python ::")
249+
]
250+
return [
251+
parse_version(c.split(" :: ")[-1])
252+
for c in classifiers
253+
if not c.endswith("Only")
254+
]
246255

247-
napari_supported_python_versions = get_supported_python_versions('napari')
256+
257+
napari_supported_python_versions = get_supported_python_versions("napari")
248258

249259
min_python_version = min(napari_supported_python_versions)
250260
max_python_version = max(napari_supported_python_versions)
251261

252-
version_string = '.'.join(str(x) for x in __version_tuple__[:3])
262+
version_string = ".".join(str(x) for x in __version_tuple__[:3])
253263
# when updating the version below, ensure to also update napari/napari README
254-
python_version = '3.11'
264+
python_version = "3.11"
255265
python_version_range = f"{min_python_version}-{max_python_version}"
256266

257267
myst_substitutions = {
@@ -288,6 +298,7 @@ def get_attributes(item, obj, modulename):
288298

289299
FILTERS["get_attributes"] = get_attributes
290300

301+
291302
class FilterSphinxWarnings(logging.Filter):
292303
"""Filter autosummary 'duplicate object description' warnings.
293304
@@ -311,14 +322,16 @@ def filter(self, record: logging.LogRecord) -> bool:
311322
return False
312323
return True
313324

325+
314326
# -- Examples gallery -------------------------------------------------------
315327

328+
316329
def reset_napari(gallery_conf, fname):
317330
from napari.settings import get_settings
318331
from qtpy.QtWidgets import QApplication
319332

320333
settings = get_settings()
321-
settings.appearance.theme = 'dark'
334+
settings.appearance.theme = "dark"
322335

323336
# Disabling `QApplication.exec_` means example scripts can call `exec_`
324337
# (scripts work when run normally) without blocking example execution by
@@ -333,7 +346,7 @@ def napari_scraper(block, block_vars, gallery_conf):
333346
334347
`app.processEvents()` allows Qt events to propagateo and prevents hanging.
335348
"""
336-
imgpath_iter = block_vars['image_path_iterator']
349+
imgpath_iter = block_vars["image_path_iterator"]
337350

338351
if app := napari.qt.get_qapp():
339352
app.processEvents()
@@ -351,9 +364,8 @@ def napari_scraper(block, block_vars, gallery_conf):
351364
napari.Viewer.close_all()
352365
app.processEvents()
353366

354-
return scrapers.figure_rst(img_paths, gallery_conf['src_dir'])
367+
return scrapers.figure_rst(img_paths, gallery_conf["src_dir"])
355368

356-
from sphinx_gallery import gen_rst
357369

358370
gen_rst.EXAMPLE_HEADER = """
359371
.. DO NOT EDIT.
@@ -380,26 +392,30 @@ def napari_scraper(block, block_vars, gallery_conf):
380392
sphinx_gallery_conf = {
381393
# path to your example scripts (this value is set in the Makefile)
382394
# 'examples_dirs': '../../napari/examples',
383-
'gallery_dirs': 'gallery', # path to where to save gallery generated output
384-
'filename_pattern': '/*.py',
385-
'ignore_pattern': 'README.rst|/*_.py',
386-
'default_thumb_file': Path(__file__).parent / '_static' / 'images' / 'logo.png',
387-
'plot_gallery': "'True'", # https://github.com/sphinx-gallery/sphinx-gallery/pull/304/files
388-
'download_all_examples': False,
389-
'min_reported_time': 10,
390-
'only_warn_on_example_error': False,
391-
'abort_on_example_error': True,
392-
'image_scrapers': ("matplotlib", napari_scraper,),
393-
'reset_modules': (reset_napari,),
394-
'reference_url': {'napari': None},
395-
'within_subsection_order': ExampleTitleSortKey,
395+
"gallery_dirs": "gallery", # path to where to save gallery generated output
396+
"filename_pattern": "/*.py",
397+
"ignore_pattern": "README.rst|/*_.py",
398+
"default_thumb_file": Path(__file__).parent / "_static" / "images" / "logo.png",
399+
"plot_gallery": "'True'", # https://github.com/sphinx-gallery/sphinx-gallery/pull/304/files
400+
"download_all_examples": False,
401+
"min_reported_time": 10,
402+
"only_warn_on_example_error": False,
403+
"abort_on_example_error": True,
404+
"image_scrapers": (
405+
"matplotlib",
406+
napari_scraper,
407+
),
408+
"reset_modules": (reset_napari,),
409+
"reference_url": {"napari": None},
410+
"within_subsection_order": ExampleTitleSortKey,
396411
}
397412

398413
# -- Calendar ---------------------------------------------------------------
399414

400415
# We host a google calendar on the docs website. To keep it up to date, we
401416
# need an api key to make requests to the Google API for updating calendar events.
402-
GOOGLE_CALENDAR_API_KEY = os.environ.get('GOOGLE_CALENDAR_API_KEY', '')
417+
GOOGLE_CALENDAR_API_KEY = os.environ.get("GOOGLE_CALENDAR_API_KEY", "")
418+
403419

404420
def add_google_calendar_secrets(app, docname, source):
405421
"""Add google calendar api key to meeting schedule page.
@@ -408,8 +424,9 @@ def add_google_calendar_secrets(app, docname, source):
408424
source file. You can process the contents and replace this item to implement
409425
source-level transformations.
410426
"""
411-
if docname == 'community/meeting_schedule':
412-
source[0] = source[0].replace('{API_KEY}', GOOGLE_CALENDAR_API_KEY)
427+
if docname == "community/meeting_schedule":
428+
source[0] = source[0].replace("{API_KEY}", GOOGLE_CALENDAR_API_KEY)
429+
413430

414431
# -- Links and checks ------------------------------------------------------
415432

@@ -432,6 +449,7 @@ def add_google_calendar_secrets(app, docname, source):
432449
"https://onlinelibrary.wiley.com/doi/10.1002/col.20327",
433450
]
434451

452+
435453
def rewrite_github_anchor(app, uri: str):
436454
"""Rewrite anchor name of the hyperlink to github.com
437455
@@ -457,8 +475,10 @@ def rewrite_github_anchor(app, uri: str):
457475
return urlunparse(parsed._replace(fragment=fragment))
458476
return None
459477

478+
460479
# -- Qt threading docstrings ------------------------------------------------
461480

481+
462482
def qt_docstrings(app, what, name, obj, options, lines):
463483
"""Only show first line of Qt threading docstrings.
464484
@@ -470,8 +490,10 @@ def qt_docstrings(app, what, name, obj, options, lines):
470490
if len(lines) > 0:
471491
del lines[1:]
472492

493+
473494
# -- Docs build setup ------------------------------------------------------
474495

496+
475497
def setup(app):
476498
"""Set up docs build.
477499
@@ -484,13 +506,12 @@ def setup(app):
484506
485507
"""
486508
app.registry.source_suffix.pop(".ipynb", None)
487-
app.connect('source-read', add_google_calendar_secrets)
488-
app.connect('linkcheck-process-uri', rewrite_github_anchor)
489-
app.connect('autodoc-process-docstring', qt_docstrings)
509+
app.connect("source-read", add_google_calendar_secrets)
510+
app.connect("linkcheck-process-uri", rewrite_github_anchor)
511+
app.connect("autodoc-process-docstring", qt_docstrings)
490512

491513
logger = logging.getLogger("sphinx")
492514
warning_handler, *_ = [
493-
h for h in logger.handlers
494-
if isinstance(h, sphinx_logging.WarningStreamHandler)
515+
h for h in logger.handlers if isinstance(h, sphinx_logging.WarningStreamHandler)
495516
]
496517
warning_handler.filters.insert(0, FilterSphinxWarnings(app))

0 commit comments

Comments
 (0)