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

Use napari_scraper instead of qtgallery #207

Merged
merged 1 commit into from
Jul 24, 2023
Merged

Conversation

aganders3
Copy link
Contributor

@aganders3 aganders3 commented Jul 24, 2023

Description

This is a CI change that removes qtgallery in favor of a napari-specific scraper. It's not that different but gives us a little more control and is not much code.

This seems to fix the error seen in "Build PR Docs" for napari/napari#4865 and also speeds up the docs build quite a bit (~11 min instead of ~25 min).

I'm no Qt expert but suspect the main improvements here are related to adding napari.Viewer.close_all() (which maybe belongs in the reset fn) and calling processEvents() one more time after this.

The main drawback right now is that this doesn't capture non-Viewer windows, but this could probably be added if needed.

Type of change

  • Fixes or improves workflow, documentation build or deployment

References

closes #174 (maybe?)
fixes errors in docs build for napari/napari#4865

Final checklist:

  • My PR is the minimum possible work for the desired functionality
  • I have commented my code, particularly in hard-to-understand areas

@github-actions github-actions bot added the documentation Improvements or additions to documentation label Jul 24, 2023
@psobolewskiPhD
Copy link
Member

OMG! The CircleCI preview has the full gallery!
image

@melissawm
Copy link
Member

On mac I'm getting the following warnings:

Traceback (most recent call last):
  File "/Users/melissa/mambaforge/envs/napari-dev/lib/python3.11/site-packages/sphinx_gallery/scrapers.py", line 340, in save_figures
    rst = scraper(block, block_vars, gallery_conf)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/melissa/projects/napari-docs/docs/conf.py", line 236, in napari_scraper
    napari.Viewer.close_all()
    ^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: module 'napari.Viewer' has no attribute 'close_all'

This also breaks the corresponding example outputs.

Using time, I have the following on main:

      599.48 real       621.78 user       101.36 sys

And for this PR

      410.45 real       566.28 user       125.58 sys

CircleCI output looks good though - so this is probably mac specific

@psobolewskiPhD
Copy link
Member

Weird, I'm not building docs, but doing:

import napari
viewer = napari.Viewer()
viewer.close_all()

works on my macOS.

@aganders3
Copy link
Contributor Author

aganders3 commented Jul 24, 2023

Weird - this actually fixed building the docs locally on my Mac but I thought maybe it was a side-effect or something else I did. I'll try to start with a fresh env. I've been using pyqt6 but will try with other backends.

@melissawm
Copy link
Member

melissawm commented Jul 24, 2023

Here's my conda env if that's helpful: (note that I'm using pyqt5 as I'm doing python -m pip install -e ".[dev, pyqt]")

EDIT: PyQT6 doesn't solve it unfortunately

(napari-dev) ➜  napari-docs git:(napari-scraper) conda list
# packages in environment at /Users/melissa/mambaforge/envs/napari-dev:
#
# Name                    Version                   Build  Channel
alabaster                 0.7.13                   pypi_0    pypi
app-model                 0.2.0                    pypi_0    pypi
appdirs                   1.4.4                    pypi_0    pypi
appnope                   0.1.3                    pypi_0    pypi
asciitree                 0.3.3                    pypi_0    pypi
asttokens                 2.2.1                    pypi_0    pypi
attrs                     23.1.0                   pypi_0    pypi
babel                     2.12.1                   pypi_0    pypi
backcall                  0.2.0                    pypi_0    pypi
beautifulsoup4            4.12.2                   pypi_0    pypi
black                     23.7.0                   pypi_0    pypi
build                     0.10.0                   pypi_0    pypi
bzip2                     1.0.8                h0d85af4_4    conda-forge
ca-certificates           2023.7.22            h8857fd0_0    conda-forge
cachey                    0.2.1                    pypi_0    pypi
certifi                   2023.7.22                pypi_0    pypi
cfgv                      3.3.1                    pypi_0    pypi
charset-normalizer        3.2.0                    pypi_0    pypi
check-manifest            0.49                     pypi_0    pypi
click                     8.1.6                    pypi_0    pypi
cloudpickle               2.2.1                    pypi_0    pypi
colorama                  0.4.6                    pypi_0    pypi
comm                      0.1.3                    pypi_0    pypi
contourpy                 1.1.0                    pypi_0    pypi
coverage                  7.2.7                    pypi_0    pypi
cycler                    0.11.0                   pypi_0    pypi
dask                      2023.7.1                 pypi_0    pypi
debugpy                   1.6.7                    pypi_0    pypi
decorator                 5.1.1                    pypi_0    pypi
distlib                   0.3.7                    pypi_0    pypi
docstring-parser          0.15                     pypi_0    pypi
docutils                  0.17.1                   pypi_0    pypi
entrypoints               0.4                      pypi_0    pypi
executing                 1.2.0                    pypi_0    pypi
fasteners                 0.18                     pypi_0    pypi
fastjsonschema            2.18.0                   pypi_0    pypi
filelock                  3.12.2                   pypi_0    pypi
fonttools                 4.41.1                   pypi_0    pypi
freetype-py               2.4.0                    pypi_0    pypi
fsspec                    2023.6.0                 pypi_0    pypi
greenlet                  2.0.2                    pypi_0    pypi
heapdict                  1.0.1                    pypi_0    pypi
hsluv                     5.0.3                    pypi_0    pypi
hypothesis                6.82.0                   pypi_0    pypi
identify                  2.5.26                   pypi_0    pypi
idna                      3.4                      pypi_0    pypi
imageio                   2.31.1                   pypi_0    pypi
imageio-ffmpeg            0.4.8                    pypi_0    pypi
imagesize                 1.4.1                    pypi_0    pypi
importlib-metadata        6.8.0                    pypi_0    pypi
in-n-out                  0.1.8                    pypi_0    pypi
iniconfig                 2.0.0                    pypi_0    pypi
ipykernel                 6.24.0                   pypi_0    pypi
ipython                   8.14.0                   pypi_0    pypi
ipython-genutils          0.2.0                    pypi_0    pypi
jedi                      0.18.2                   pypi_0    pypi
jinja2                    3.0.3                    pypi_0    pypi
jsonschema                4.18.4                   pypi_0    pypi
jsonschema-specifications 2023.7.1                 pypi_0    pypi
jupyter-cache             0.6.1                    pypi_0    pypi
jupyter-client            8.3.0                    pypi_0    pypi
jupyter-core              5.3.1                    pypi_0    pypi
kiwisolver                1.4.4                    pypi_0    pypi
lazy-loader               0.3                      pypi_0    pypi
libexpat                  2.5.0                hf0c8a7f_1    conda-forge
libffi                    3.4.2                h0d85af4_5    conda-forge
libsqlite                 3.42.0               h58db7d2_0    conda-forge
libzlib                   1.2.13               h8a1eda9_5    conda-forge
livereload                2.6.3                    pypi_0    pypi
locket                    1.0.0                    pypi_0    pypi
lxml                      4.9.3                    pypi_0    pypi
magicgui                  0.7.2                    pypi_0    pypi
markdown-it-py            2.2.0                    pypi_0    pypi
markupsafe                2.1.3                    pypi_0    pypi
matplotlib                3.7.2                    pypi_0    pypi
matplotlib-inline         0.1.6                    pypi_0    pypi
mdit-py-plugins           0.3.5                    pypi_0    pypi
mdurl                     0.1.2                    pypi_0    pypi
mpmath                    1.3.0                    pypi_0    pypi
mypy-extensions           1.0.0                    pypi_0    pypi
myst-nb                   0.17.2                   pypi_0    pypi
myst-parser               0.18.1                   pypi_0    pypi
napari                    0.4.11rc2.dev1308+g007712f0.d20230724          pypi_0    pypi
napari-console            0.0.8                    pypi_0    pypi
napari-plugin-engine      0.2.0                    pypi_0    pypi
napari-plugin-manager     0.1.0a2                  pypi_0    pypi
napari-sphinx-theme       0.2.1                    pypi_0    pypi
napari-svg                0.1.10                   pypi_0    pypi
nbclient                  0.7.4                    pypi_0    pypi
nbformat                  5.9.1                    pypi_0    pypi
ncurses                   6.4                  hf0c8a7f_0    conda-forge
nest-asyncio              1.5.6                    pypi_0    pypi
networkx                  3.1                      pypi_0    pypi
nodeenv                   1.8.0                    pypi_0    pypi
npe2                      0.7.2                    pypi_0    pypi
numcodecs                 0.11.0                   pypi_0    pypi
numpy                     1.25.1                   pypi_0    pypi
numpydoc                  1.5.0                    pypi_0    pypi
openssl                   3.1.1                h8a1eda9_1    conda-forge
packaging                 23.1                     pypi_0    pypi
pandas                    2.0.3                    pypi_0    pypi
parso                     0.8.3                    pypi_0    pypi
partd                     1.4.0                    pypi_0    pypi
pathspec                  0.11.1                   pypi_0    pypi
pexpect                   4.8.0                    pypi_0    pypi
pickleshare               0.7.5                    pypi_0    pypi
pillow                    10.0.0                   pypi_0    pypi
pint                      0.22                     pypi_0    pypi
pip                       23.2.1             pyhd8ed1ab_0    conda-forge
platformdirs              3.9.1                    pypi_0    pypi
pluggy                    1.2.0                    pypi_0    pypi
pooch                     1.7.0                    pypi_0    pypi
pre-commit                3.3.3                    pypi_0    pypi
prompt-toolkit            3.0.39                   pypi_0    pypi
psutil                    5.9.5                    pypi_0    pypi
psygnal                   0.9.1                    pypi_0    pypi
ptyprocess                0.7.0                    pypi_0    pypi
pure-eval                 0.2.2                    pypi_0    pypi
pydantic                  1.10.11                  pypi_0    pypi
pygments                  2.15.1                   pypi_0    pypi
pyopengl                  3.1.7                    pypi_0    pypi
pyparsing                 3.0.9                    pypi_0    pypi
pyproject-hooks           1.0.0                    pypi_0    pypi
pyqt5                     5.15.9                   pypi_0    pypi
pyqt5-qt5                 5.15.2                   pypi_0    pypi
pyqt5-sip                 12.12.2                  pypi_0    pypi
pytest                    7.4.0                    pypi_0    pypi
pytest-cov                4.1.0                    pypi_0    pypi
pytest-pretty             1.2.0                    pypi_0    pypi
pytest-qt                 4.2.0                    pypi_0    pypi
python                    3.11.4          h30d4d87_0_cpython    conda-forge
python-dateutil           2.8.2                    pypi_0    pypi
python-dotenv             1.0.0                    pypi_0    pypi
pytz                      2023.3                   pypi_0    pypi
pyvirtualdisplay          3.0                      pypi_0    pypi
pywavelets                1.4.1                    pypi_0    pypi
pyyaml                    6.0.1                    pypi_0    pypi
pyzmq                     25.1.0                   pypi_0    pypi
qtconsole                 5.4.3                    pypi_0    pypi
qtgallery                 0.0.2                    pypi_0    pypi
qtpy                      2.3.1                    pypi_0    pypi
readline                  8.2                  h9e318b2_1    conda-forge
referencing               0.30.0                   pypi_0    pypi
requests                  2.31.0                   pypi_0    pypi
rich                      13.4.2                   pypi_0    pypi
rpds-py                   0.9.2                    pypi_0    pypi
scikit-image              0.21.0                   pypi_0    pypi
scipy                     1.11.1                   pypi_0    pypi
setuptools                68.0.0             pyhd8ed1ab_0    conda-forge
six                       1.16.0                   pypi_0    pypi
snowballstemmer           2.2.0                    pypi_0    pypi
sortedcontainers          2.4.0                    pypi_0    pypi
soupsieve                 2.4.1                    pypi_0    pypi
sphinx                    4.5.0                    pypi_0    pypi
sphinx-autobuild          2021.3.14                pypi_0    pypi
sphinx-autodoc-typehints  1.12.0                   pypi_0    pypi
sphinx-copybutton         0.5.2                    pypi_0    pypi
sphinx-design             0.4.1                    pypi_0    pypi
sphinx-external-toc       0.3.1                    pypi_0    pypi
sphinx-favicon            1.0.1                    pypi_0    pypi
sphinx-gallery            0.13.0                   pypi_0    pypi
sphinx-rtd-theme          1.2.2                    pypi_0    pypi
sphinx-tabs               3.4.0                    pypi_0    pypi
sphinx-tags               0.2.1                    pypi_0    pypi
sphinxcontrib-applehelp   1.0.4                    pypi_0    pypi
sphinxcontrib-devhelp     1.0.2                    pypi_0    pypi
sphinxcontrib-htmlhelp    2.0.1                    pypi_0    pypi
sphinxcontrib-jquery      4.1                      pypi_0    pypi
sphinxcontrib-jsmath      1.0.1                    pypi_0    pypi
sphinxcontrib-qthelp      1.0.3                    pypi_0    pypi
sphinxcontrib-serializinghtml 1.1.5                    pypi_0    pypi
sqlalchemy                2.0.19                   pypi_0    pypi
stack-data                0.6.2                    pypi_0    pypi
superqt                   0.4.1                    pypi_0    pypi
sympy                     1.12                     pypi_0    pypi
tabulate                  0.9.0                    pypi_0    pypi
tensorstore               0.1.40                   pypi_0    pypi
tifffile                  2023.7.18                pypi_0    pypi
tk                        8.6.12               h5dbffcc_0    conda-forge
tomli-w                   1.0.0                    pypi_0    pypi
toolz                     0.12.0                   pypi_0    pypi
torch                     2.0.1                    pypi_0    pypi
tornado                   6.3.2                    pypi_0    pypi
tqdm                      4.65.0                   pypi_0    pypi
traitlets                 5.9.0                    pypi_0    pypi
typer                     0.9.0                    pypi_0    pypi
typing-extensions         4.7.1                    pypi_0    pypi
tzdata                    2023.3                   pypi_0    pypi
urllib3                   2.0.4                    pypi_0    pypi
virtualenv                20.24.2                  pypi_0    pypi
vispy                     0.13.0                   pypi_0    pypi
wcwidth                   0.2.6                    pypi_0    pypi
wheel                     0.41.0             pyhd8ed1ab_0    conda-forge
wrapt                     1.15.0                   pypi_0    pypi
xarray                    2023.7.0                 pypi_0    pypi
xz                        5.2.6                h775f41a_0    conda-forge
zarr                      2.16.0                   pypi_0    pypi
zipp                      3.16.2                   pypi_0    pypi
(napari-dev) ➜  napari-docs git:(napari-scraper) 

@aganders3
Copy link
Contributor Author

aganders3 commented Jul 24, 2023

Thanks - your env looks fine to me.

I just remembered though that I think I had this error before and made a change in my (local) napari to fix it. Are you able to build docs with napari/main without this PR? I thought they would be totally separate issues.

I was having a problem with how sphinx-gallery tries to do...something...with the imports and it was breaking when combined with the way napari does some lazy importing on the main module. The symptom was that every example in the gallery after custom_key_bindings.py would break.

This is how I worked around it:

❯ git diff main -- examples/custom_key_bindings.py 
diff --git a/examples/custom_key_bindings.py b/examples/custom_key_bindings.py
index f78ffe53b..90ece4add 100644
--- a/examples/custom_key_bindings.py
+++ b/examples/custom_key_bindings.py
@@ -11,6 +11,8 @@ from skimage import data
 
 import napari
 
+Viewer = napari.Viewer
+
 blobs = data.binary_blobs(
     length=128, blob_size_fraction=0.05, n_dim=2, volume_fraction=0.25
 ).astype(float)
@@ -41,7 +43,7 @@ def set_layer_data(viewer):
     viewer.layers[0].data = blobs
 
 
-@napari.Viewer.bind_key('w')
+@Viewer.bind_key('w')
 def hello(viewer):
     # on press
     viewer.status = 'hello world!'

(this also took me a really long time to debug/workaround)

edit: all that said I just created a new env and it is now working with napari/main so ¯_(ツ)_/¯

> mamba create -n docs-new python=3.10 pyqt=5
...
> mamba activate docs-new
> pip install ../napari -r docs/requirements.txt
> make docs

@aganders3
Copy link
Contributor Author

I am able to reproduce the AttributeError: module 'napari.Viewer' has no attribute 'close_all' error if I use an editable install of napari, but it goes away if I do a normal (still local) pip install (pip install ../napari for me). Does this make a difference for you, @melissawm?

@melissawm
Copy link
Member

That did fix it! Any ideas why? I've been building like this forever because I am often changing things in both napari and the docs at the same time, so understanding that would also be helpful...

Copy link
Member

@melissawm melissawm left a comment

Choose a reason for hiding this comment

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

🎉

@aganders3
Copy link
Contributor Author

That did fix it! Any ideas why? I've been building like this forever because I am often changing things in both napari and the docs at the same time, so understanding that would also be helpful...

Sorry, but not really :( - I don't know enough about the differences between editable and "normal" installs to say (and I think it's even changed a bit in the past couple years).

I chased it a bit and found sphinx-gallery was doing some interesting stuff to try to figure out where different imports in the examples come from, I think as part of looking for backreferences. In any case this caused napari.Viewer to end up in sys.modules which then shadowed the lazy import of the Viewer class. Once I had a workaround for this I stopped digging, but only just now noticed this discrepancy between editable/normal installs.

@melissawm
Copy link
Member

melissawm commented Jul 24, 2023

Thanks - that is helpful to know and maybe should be documented in our development docs so I'll open a PR for that. Cheers!

EDIT: here it is #209

@Czaki Czaki added this to the 0.5.0 milestone Jul 24, 2023
@jni jni merged commit 37ebe2d into napari:main Jul 24, 2023
@jni
Copy link
Member

jni commented Jul 24, 2023

I ❤️ 😍 this! Thank you!!! 🙏

@lucyleeow
Copy link
Collaborator

I chased it a bit and found sphinx-gallery was doing some interesting stuff to try to figure out where different imports in the examples come from, I think as part of looking for backreferences.

The backreferences code in Sphinx Gallery is very complex and confusing, but I really don't think it executes anything. It parses the code into AST but nothing more. And I just checked and we do not set even backreferences_dir config, which is None by default (see: https://sphinx-gallery.github.io/stable/configuration.html#references-to-examples) so backreferences would not be generated.

I am intrigued as to why napari.Viewer would only end up in sys.modules when installed in editable mode. Not sure if it makes a difference but was it 'napari.viewer' or 'napari.Viewer' because 'napari.Viewer' isn't a module is it?

@lucyleeow
Copy link
Collaborator

lucyleeow commented Jul 25, 2023

I am not sure if this will make a difference, but would directly importing napari in napari_scraper prevent the error? I'm actually a bit surprised that the current scraper works, since it is run at the end of executing a code block, without getting any global variables from executing the example (I guess at some point in doc building, napari is imported in the env, maybe here - though this is only in the github workflow ?) The example scraper and matplotlib scraper in sphinx gallery imports itself first too: https://sphinx-gallery.github.io/stable/advanced.html#example-1-a-matplotlib-style-scraper Edit: nevermind, I see sphinx evals the config file at the start, so imports get into the env then.

Edit2: Actually would doing from napari.viewer import Viewer in the scraper fix the error? No idea the cause but possibly a bandaid?

(Sorry I tried to test on the mac, but its updating and downloading and estimating to take hours)

@lucyleeow
Copy link
Collaborator

lucyleeow commented Jul 25, 2023

napari.Viewer.close_all() (which maybe belongs in the reset fn

I think it would be safer to add this to the reset function. Potentially it may remove references to things that will enable garbage collection and aid memory usage. Will open a PR for this.

Edit: Technically it is probably fine for it to be in the scraper as in our case the scraper is always run when executing examples, so will leave as is.

@aganders3 aganders3 deleted the napari-scraper branch July 25, 2023 12:50
@aganders3
Copy link
Contributor Author

I am not sure if this will make a difference, but would directly importing napari in napari_scraper prevent the error?

Yes I think doing some import tricks may prevent the error, but as you note it's more of a band-aid or workaround. I think it's ultimately caused by the way things are imported in one or more examples (custom_key_bindings.py), and may regardless cause issues in subsequent examples. At least that was the symptom I saw before.

I will continue digging into this because it's a sufficiently interesting (annoying) mystery.

I think it would be safer to add this to the reset function. Potentially it may remove references to things that will enable garbage collection and aid memory usage. Will open a PR for this.

It does feel more like reset-type functionality, so I'll also play with this. I'm glad this PR was merged quickly to get CI green but it's probably not the last time we'll have to touch it 😄.

melissawm pushed a commit to melissawm/napari-docs that referenced this pull request Sep 6, 2023
# Description
This is a CI change that removes `qtgallery` in favor of a
napari-specific scraper. It's not that different but gives us a little
more control and is not much code.

This seems to fix the error seen in "Build PR Docs" for
napari/napari#4865 and also speeds up the docs
build quite a bit (~11 min instead of ~25 min).

I'm no Qt expert but suspect the main improvements here are related to
adding `napari.Viewer.close_all()` (which maybe belongs in the reset fn)
and calling `processEvents()` one more time after this.

The main drawback right now is that this doesn't capture non-Viewer
windows, but this could probably be added if needed.

## Type of change
- [x] Fixes or improves workflow, documentation build or deployment

# References
closes napari#174 (maybe?)
fixes errors in docs build for
napari/napari#4865

## Final checklist:
- [x] My PR is the minimum possible work for the desired functionality
- [x] I have commented my code, particularly in hard-to-understand areas
@Czaki Czaki modified the milestones: 0.5.0, 0.4.19 Oct 25, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Maint] The Gallery is broken in CircleCI previews
6 participants