8000 MRG: Only rebuild necessary parts by larsoner · Pull Request #448 · sphinx-gallery/sphinx-gallery · GitHub
[go: up one dir, main page]

Skip to content

MRG: Only rebuild necessary parts #448

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

Merged
merged 5 commits into from
Mar 4, 2019
Merged
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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
.coverage*

# C extensions
*.so
Expand Down Expand Up @@ -73,4 +74,4 @@ target/
.history

# Jupyter notebooks
.ipynb_checkpoints
.ipynb_checkpoints
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ Sphinx-Gallery will not manage its dependencies when installing, thus
you are required to install them manually. Our minimal dependencies
are:

* Sphinx
* Sphinx >= 1.5
* Matplotlib
* Pillow

Expand Down
4 changes: 2 additions & 2 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ environment:
global:
PYTHON: "C:\\conda"
MINICONDA_VERSION: "latest"
CONDA_DEPENDENCIES: "numpy seaborn matplotlib sphinx pillow pytest pytest-cov sphinx_rtd_theme memory_profiler ipython"
CONDA_DEPENDENCIES: "numpy seaborn matplotlib sphinx pillow pytest pytest-cov sphinx_rtd_theme vtk pyface traits traitsui ipython"

matrix:
- PYTHON_VERSION: "2.7"
PYTHON_ARCH: "64"
- PYTHON_VERSION: "3.5"
- PYTHON_VERSION: "3.6"
PYTHON_ARCH: "64"

platform:
Expand Down
63 changes: 58 additions & 5 deletions doc/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ file:
- ``binder`` (:ref:`binder_links`)
- ``first_notebook_cell`` (:ref:`first_notebook_cell`)
- ``junit`` (:ref:`junit_xml`)
- ``log_level`` (:ref:`log_level`)

Some options can also be set or overridden on a file-by-file basis:

Expand Down Expand Up @@ -75,7 +76,8 @@ Keep in mind that both lists have to be of the same length.

.. note:: If your examples take a long time to run, consider looking at the
:ref:`execution times <sphx_glr_auto_examples_sg_execution_times>`
file that is generated for each gallery dir.
file that is generated for each gallery dir (as long as any examples
were actually executed in that directory during the build).

.. _build_pattern:

Expand Down Expand Up @@ -122,6 +124,13 @@ you would do::
Here, one should escape the dot ``r'\.'`` as otherwise python `regular expressions`_ matches any character. Nevertheless, as
one is targeting a specific file, it would match the dot in the filename even without this escape character.

.. note::
Sphinx-gallery only re-runs examples that have changed (according to their
md5 hash). You can delete the associated MD5 files (e.g.,
``./auto_examples/plot_awesome_example.py.md5``) to force a rebuild if
you have not changed the example itself between subsequent ``sphinx``
calls.

Similarly, to build only examples in a specific directory, you can do::

sphinx_gallery_conf = {
Expand Down Expand Up @@ -182,6 +191,22 @@ the converse does not hold.
If you so desire you can implement your own sorting key. It will be
provided the relative paths to `conf.py` of each sub gallery folder.

.. warning:: If you create your own class for ``'subsection_order'``, ensure
that the ``__str__`` of your class is stable across runs.
Sphinx determines if the build environment has changed
(and thus if *all* documents should be rewritten)
by examining the config values using
``md5(str(obj).encode()).hexdigest()`` in
``sphinx/builders/html.py``. Default class instances
in Python have their memory address in their ``__repr__`` which
will in general change for each build. For ``ExplicitOrder``
for example, this is fixed via::

def __repr__(self):
return '<%s: %s>' % (self.__class__.__name__, self.ordered_list)

Thus the files are only all rebuilt if the specified ordered list
is changed.

.. _within_gallery_order:

Expand Down Expand Up @@ -429,9 +454,12 @@ displays a comment along-side each the code shown above.

Which is achieved by the following configuration::

'first_notebook_cell': ("# This cell is added by sphinx-gallery\n"
"# It can be customized to whatever you like\n"
"%matplotlib inline")
sphinx_gallery_conf = {
...
'first_notebook_cell': ("# This cell is added by sphinx-gallery\n"
"# It can be customized to whatever you like\n"
"%matplotlib inline")
}

If the value of ``first_notebook_cell`` is set to ``None``, then no extra first
cell will be added to the notebook.
Expand Down Expand Up @@ -470,6 +498,28 @@ For more information on CircleCI integration, peruse the related
`CircleCI doc <https://circleci.com/docs/2.0/collect-test-data/#metadata-collection-in-custom-test-steps>`__
and `blog post <https://circleci.com/blog/how-to-output-junit-tests-through-circleci-2-0-for-expanded-insights/>`__.


.. _log_level:

Setting log level
=================

Sphinx-Gallery logs output at several stages. Warnings can be generated for
code that requires case sensitivity (e.g., ``plt.subplot`` and ``plt.Subplot``)
when building docs on a filesystem that does not support case sensitive
naming (e.g., Windows). In this case, by default a ``logger.warning`` is
emitted, which will lead to a build failure when buidling with ``-W``.
The log level can be set with::

sphinx_gallery_conf = {
...
'log_level': {'backreference_missing': 'warning'},
}

The only valid key currently is ``backreference_missing``.
The valid values are ``'debug'``, ``'info'``, ``'warning'``, and ``'error'``.


.. _disable_all_scripts_download:

Disabling download button of all scripts
Expand Down Expand Up @@ -549,7 +599,7 @@ If a Sphinx-Gallery configuration for Binder is discovered, the following extra
1. The dependency files specified in ``dependencies`` will be copied to a ``binder/`` folder in your built documentation.
2. The built Jupyter Notebooks from the documentation will be copied to a folder called ``<notebooks_dir/>`` at the root of
your built documentation (they will follow the same folder hierarchy within the notebooks directory folder.
2. The rST output of each Sphinx-Gallery example will now have a ``launch binder`` button in it.
3. The rST output of each Sphinx-Gallery example will now have a ``launch binder`` button in it.
4. That button will point to a binder link with the following structure::

<binderhub_url>/v2/gh/<org>/<repo>/<ref>?filepath=<filepath_prefix>/<notebooks_dir>/path/to/notebook.ipynb
Expand Down Expand Up @@ -769,6 +819,9 @@ Here you list the examples you allow to fail during the build process,
keep in mind to specify the full relative path from your `conf.py` to
the example script.

.. note:: If an example is expected to fail, sphinx-gallery will error if
the example runs without error.


.. _setting_thumbnail_size:

Expand Down
3 changes: 3 additions & 0 deletions examples/local_module.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
"""
Local module
============

A trivial local module to provide a value for plot_exp.py.
"""

Expand Down
6 changes: 3 additions & 3 deletions examples/plot_function_identifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@

import os # noqa, analysis:ignore
import matplotlib.pyplot as plt
import sphinx_gallery.backreferences as spback
from sphinx_gallery.backreferences import identify_names

filename = spback.__file__.replace('.pyc', '.py')
names = spback.identify_names(filename)
filename = os.__file__.replace('.pyc', '.py')
names = identify_names(filename)
figheight = len(names) + .5

fontsize = 20
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[tool:pytest]
addopts = --cov-report= --cov=sphinx_gallery --durations=5 -ra
addopts = --cov-report= --cov=sphinx_gallery --durations=5 -ra --showlocals
python_files = tests/*.py
norecursedirs = build _build auto_examples gen_modules
sphinx_gallery/tests/tinybuild
Expand Down
32 changes: 29 additions & 3 deletions sphinx_gallery/backreferences.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,13 @@

import ast
import codecs
import collections
import os
import re

from . import sphinx_compatibility
from .utils import _replace_md5

# Try Python 2 first, otherwise load from Python 3
try:
import cPickle as pickle
Expand Down Expand Up @@ -129,7 +133,7 @@ def identify_names(filename):
names = list(finder.get_mapping())
names += extract_object_names_from_docs(filename)

example_code_obj = {}
example_code_obj = collections.OrderedDict()
for name, full_name in names:
if name in example_code_obj:
continue # if someone puts it in the docstring and code
Expand All @@ -154,9 +158,10 @@ def scan_used_functions(example_file, gallery_conf):
"""save variables so we can later add links to the documentation"""
example_code_obj = identify_names(example_file)
if example_code_obj:
codeobj_fname = example_file[:-3] + '_codeobj.pickle'
codeobj_fname = example_file[:-3] + '_codeobj.pickle.new'
with open(codeobj_fname, 'wb') as fid:
pickle.dump(example_code_obj, fid, pickle.HIGHEST_PROTOCOL)
_replace_md5(codeobj_fname)

backrefs = set('{module_short}.{name}'.format(**entry)
for entry in example_code_obj.values()
Expand Down Expand Up @@ -216,7 +221,7 @@ def write_backreferences(seen_backrefs, gallery_conf,
for backref in backrefs:
include_path = os.path.join(gallery_conf['src_dir'],
gallery_conf['backreferences_dir'],
'%s.examples' % backref)
'%s.examples.new' % backref)
seen = backref in seen_backrefs
with codecs.open(include_path, 'a' if seen else 'w',
encoding='utf-8') as ex_file:
Expand All @@ -227,3 +232,24 @@ def write_backreferences(seen_backrefs, gallery_conf,
ex_file.write(_thumbnail_div(build_target_dir, fname, snippet,
is_backref=True))
seen_backrefs.add(backref)


def finalize_backreferences(seen_backrefs, gallery_conf):
"""Replace backref files only if necessary."""
logger = sphinx_compatibility.getLogger('sphinx-gallery')
if gallery_conf['backreferences_dir'] is None:
return

for backref in seen_backrefs:
path = os.path.join(gallery_conf['src_dir'],
gallery_conf['backreferences_dir'],
'%s.examples.new' % backref)
if os.path.isfile(path):
_replace_md5(path)
else:
level = gallery_conf['log_level'].get('backreference_missing',
'warning')
func = getattr(logger, level)
func('Could not find backreferences file: %s' % (path,))
func('The backreferences are likely to be erroneous '
'due to file system case insensitivity.')
6 changes: 3 additions & 3 deletions sphinx_gallery/binder.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def gen_binder_url(fpath, binder_conf, gallery_conf):
----------
fpath: str
The path to the `.py` file for which a Binder badge will be generated.
binder_conf: dict | None
binder_conf: dict or None
The Binder configuration dictionary. See `gen_binder_rst` for details.

Returns
Expand Down Expand Up @@ -85,7 +85,7 @@ def gen_binder_rst(fpath, binder_conf, gallery_conf):
----------
fpath: str
The path to the `.py` file for which a Binder badge will be generated.
binder_conf: dict | None
binder_conf: dict or None
If a dictionary it must have the following keys:

'binderhub_url': The URL of the BinderHub instance that's running a Binder
Expand Down Expand Up @@ -204,7 +204,7 @@ def check_binder_conf(binder_conf):
raise ValueError('`binder_conf` must be a dictionary or None.')
if len(binder_conf) == 0:
return binder_conf

if binder_conf.get('url') and not binder_conf.get('binderhub_url'):
logger.warning(
'Found old BinderHub URL keyword ("url"). Please update your '
Expand Down
2 changes: 1 addition & 1 deletion sphinx_gallery/docs_resolv.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ def resolve(self, cobj, this_url):

Returns
-------
link : str | None
link : str or None
The link (URL) to the documentation.
"""
full_name = cobj['module_short'] + '.' + cobj['name']
Expand Down
17 changes: 9 additions & 8 deletions sphinx_gallery/downloads.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
import os
import zipfile

from .utils import _replace_md5

CODE_DOWNLOAD = """
.. _sphx_glr_download_{3}:

Expand Down Expand Up @@ -49,7 +51,7 @@ def python_zip(file_list, gallery_path, extension='.py'):

Parameters
----------
file_list : list of strings
file_list : list
Holds all the file names to be included in zip file
gallery_path : str
path to where the zipfile is stored
Expand All @@ -67,13 +69,12 @@ def python_zip(file_list, gallery_path, extension='.py'):
zipname = os.path.basename(os.path.normpath(gallery_path))
zipname += '_python' if extension == '.py' else '_jupyter'
zipname = os.path.join(gallery_path, zipname + '.zip')

zipf = zipfile.ZipFile(zipname, mode='w')
for fname in file_list:
file_src = os.path.splitext(fname)[0] + extension
zipf.write(file_src, os.path.relpath(file_src, gallery_path))
zipf.close()

zipname_new = zipname + '.new'
with zipfile.ZipFile(zipname_new, mode='w') as zipf:
for fname in file_list:
file_src = os.path.splitext(fname)[0] + extension
zipf.write(file_src, os.path.relpath(file_src, gallery_path))
_replace_md5(zipname_new)
return zipname


Expand Down
Loading
0