Skip to content

Commit 4abd070

Browse files
authored
ENH Clean-up code by early initialization of sphinx_gallery_conf (#1120)
1 parent 795e11b commit 4abd070

File tree

10 files changed

+127
-111
lines changed

10 files changed

+127
-111
lines changed

sphinx_gallery/backreferences.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -350,8 +350,7 @@ def _finalize_backreferences(seen_backrefs, gallery_conf):
350350
ex_file.write(THUMBNAIL_PARENT_DIV_CLOSE)
351351
_replace_md5(path, mode='t')
352352
else:
353-
level = gallery_conf['log_level'].get('backreference_missing',
354-
'warning')
353+
level = gallery_conf['log_level']['backreference_missing']
355354
func = getattr(logger, level)
356355
func(f'Could not find backreferences file: {path}')
357356
func('The backreferences are likely to be erroneous '

sphinx_gallery/gen_gallery.py

Lines changed: 47 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -122,24 +122,6 @@ def _bool_eval(x):
122122
return bool(x)
123123

124124

125-
def parse_config(app, check_keys=True):
126-
"""Process the Sphinx Gallery configuration."""
127-
plot_gallery = _bool_eval(app.builder.config.plot_gallery)
128-
src_dir = app.builder.srcdir
129-
abort_on_example_error = _bool_eval(
130-
app.builder.config.abort_on_example_error)
131-
lang = app.builder.config.highlight_language
132-
gallery_conf = _complete_gallery_conf(
133-
app.config.sphinx_gallery_conf, src_dir, plot_gallery,
134-
abort_on_example_error, lang, app.builder.name, app,
135-
check_keys)
136-
137-
# this assures I can call the config in other places
138-
app.config.sphinx_gallery_conf = gallery_conf
139-
app.config.html_static_path.append(glr_path_static())
140-
return gallery_conf
141-
142-
143125
def _update_gallery_conf(gallery_conf):
144126
"""Update gallery config.
145127
@@ -151,19 +133,24 @@ def _update_gallery_conf(gallery_conf):
151133
gallery_conf['exclude_implicit_doc_regex'] = exclude_regex
152134

153135

154-
def _complete_gallery_conf(sphinx_gallery_conf, src_dir, plot_gallery,
155-
abort_on_example_error, lang='python',
156-
builder_name='html', app=None, check_keys=True):
136+
def _complete_gallery_conf_builder_inited(
137+
sphinx_gallery_conf, src_dir, plot_gallery=True,
138+
abort_on_example_error=False, lang='python',
139+
builder_name='html'):
140+
sphinx_gallery_conf.update(plot_gallery=plot_gallery)
141+
sphinx_gallery_conf.update(abort_on_example_error=abort_on_example_error)
142+
sphinx_gallery_conf['src_dir'] = src_dir
143+
lang = lang if lang in ('python', 'python3', 'default') else 'python'
144+
sphinx_gallery_conf['lang'] = lang
145+
# Make it easy to know which builder we're in
146+
sphinx_gallery_conf['builder_name'] = builder_name
147+
148+
149+
def _complete_gallery_conf_config_inited(sphinx_gallery_conf, app=None,
150+
check_keys=True):
157151
gallery_conf = copy.deepcopy(DEFAULT_GALLERY_CONF)
158152
options = sorted(gallery_conf)
159-
# sphinx-autoapi can run before our config filling can occur, which
160-
# when used with show_api_usage=True can cause us to add this early.
161-
# In theory we could bump our priority above theirs, but this could have
162-
# unintented consequences.
163-
ignore_keys = ('_sg_api_entries',)
164-
extra_keys = sorted(
165-
(set(sphinx_gallery_conf) - set(options)) - set(ignore_keys)
166-
)
153+
extra_keys = sorted(set(sphinx_gallery_conf) - set(options))
167154
if extra_keys and check_keys:
168155
msg = 'Unknown key(s) in sphinx_gallery_conf:\n'
169156
for key in extra_keys:
@@ -176,13 +163,10 @@ def _complete_gallery_conf(sphinx_gallery_conf, src_dir, plot_gallery,
176163
msg += '\n'
177164
raise ConfigError(msg.strip())
178165
gallery_conf.update(sphinx_gallery_conf)
179-
gallery_conf.update(plot_gallery=plot_gallery)
180-
gallery_conf.update(abort_on_example_error=abort_on_example_error)
181166
# XXX anything that can only be a bool (rather than str) should probably be
182167
# evaluated this way as it allows setting via -D on the command line
183168
for key in ('promote_jupyter_magic', 'run_stale_examples',):
184169
gallery_conf[key] = _bool_eval(gallery_conf[key])
185-
gallery_conf['src_dir'] = src_dir
186170
gallery_conf['app'] = app
187171

188172
# Check capture_repr
@@ -318,8 +302,6 @@ def call_memory(func):
318302
"['before', 'after', 'both'], "
319303
'got %r' % gallery_conf['reset_modules_order'])
320304

321-
lang = lang if lang in ('python', 'python3', 'default') else 'python'
322-
gallery_conf['lang'] = lang
323305
del resetters
324306

325307
# Ensure the first cell text is a string if we have it
@@ -357,8 +339,6 @@ def call_memory(func):
357339
"values: %s, got: %s."
358340
% (accepted_keys, key))
359341

360-
# Make it easy to know which builder we're in
361-
gallery_conf['builder_name'] = builder_name
362342
gallery_conf['titles'] = {}
363343
# Ensure 'backreferences_dir' is str, pathlib.Path or None
364344
backref = gallery_conf['backreferences_dir']
@@ -376,7 +356,6 @@ def call_memory(func):
376356
gallery_conf['binder'] = check_binder_conf(gallery_conf['binder'])
377357

378358
# jupyterlite
379-
print('_complete_gallery_conf', gallery_conf.get('jupyterlite'))
380359
gallery_conf['jupyterlite'] = check_jupyterlite_conf(
381360
gallery_conf.get('jupyterlite', {}), app)
382361

@@ -503,7 +482,7 @@ def generate_gallery_rst(app):
503482
"""
504483

505484
logger.info('generating gallery...', color='white')
506-
gallery_conf = parse_config(app)
485+
gallery_conf = app.config.sphinx_gallery_conf
507486

508487
seen_backrefs = set()
509488

@@ -737,9 +716,6 @@ def write_computation_times(gallery_conf, target_dir, costs):
737716

738717

739718
def write_api_entries(app, what, name, obj, options, lines):
740-
# sphinx-autoapi can do this before we manage to complete our config
741-
if 'show_api_usage' not in app.config.sphinx_gallery_conf:
742-
app.config.sphinx_gallery_conf['show_api_usage'] = False
743719
if app.config.sphinx_gallery_conf['show_api_usage'] is False:
744720
return
745721
if '_sg_api_entries' not in app.config.sphinx_gallery_conf:
@@ -1065,7 +1041,7 @@ def _parse_failures(gallery_conf):
10651041
# filter from examples actually run
10661042
passing_unexpectedly = [
10671043
src_file for src_file in passing_unexpectedly
1068-
if re.search(gallery_conf.get('filename_pattern'), src_file)]
1044+
if re.search(gallery_conf['filename_pattern'], src_file)]
10691045
return failing_as_expected, failing_unexpectedly, passing_unexpectedly
10701046

10711047

@@ -1187,12 +1163,38 @@ def default_getter(conf):
11871163
return default_getter
11881164

11891165

1166+
def normalize_gallery_conf_config_inited(app, config, check_keys=True):
1167+
new_sphinx_gallery_conf = _complete_gallery_conf_config_inited(
1168+
config.sphinx_gallery_conf, app=app, check_keys=check_keys)
1169+
config.sphinx_gallery_conf = new_sphinx_gallery_conf
1170+
config.html_static_path.append(glr_path_static())
1171+
1172+
1173+
def normalize_gallery_conf_builder_inited(app):
1174+
plot_gallery = _bool_eval(app.builder.config.plot_gallery)
1175+
src_dir = app.builder.srcdir
1176+
abort_on_example_error = _bool_eval(
1177+
app.builder.config.abort_on_example_error)
1178+
lang = app.builder.config.highlight_language
1179+
_complete_gallery_conf_builder_inited(
1180+
app.config.sphinx_gallery_conf,
1181+
src_dir,
1182+
plot_gallery=plot_gallery,
1183+
abort_on_example_error=abort_on_example_error,
1184+
lang=lang,
1185+
builder_name=app.builder.name
1186+
)
1187+
1188+
11901189
def setup(app):
11911190
"""Setup Sphinx-Gallery sphinx extension"""
11921191
app.add_config_value('sphinx_gallery_conf', DEFAULT_GALLERY_CONF, 'html')
11931192
for key in ['plot_gallery', 'abort_on_example_error']:
11941193
app.add_config_value(key, get_default_config_value(key), 'html')
11951194

1195+
# Early normalization of sphinx_gallery_conf at config-inited
1196+
app.connect('config-inited', normalize_gallery_conf_config_inited,
1197+
priority=10)
11961198
# set small priority value, so that pre_configure_jupyterlite_sphinx is
11971199
# called before jupyterlite_sphinx config-inited
11981200
app.connect(
@@ -1213,6 +1215,9 @@ def setup(app):
12131215

12141216
imagesg_addnode(app)
12151217

1218+
# Early normalization of sphinx_gallery_conf at builder-inited
1219+
app.connect('builder-inited', normalize_gallery_conf_builder_inited,
1220+
priority=10)
12161221
app.connect('builder-inited', generate_gallery_rst)
12171222
app.connect('build-finished', copy_binder_files)
12181223
app.connect('build-finished', create_jupyterlite_contents)

sphinx_gallery/gen_rst.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@
4848
remove_ignore_blocks)
4949

5050
from .notebook import jupyter_notebook, save_notebook
51-
from .interactive_example import check_binder_conf, gen_binder_rst
52-
from .interactive_example import check_jupyterlite_conf, gen_jupyterlite_rst
51+
from .interactive_example import gen_binder_rst
52+
from .interactive_example import gen_jupyterlite_rst
5353

5454

5555
logger = sphinx.util.logging.getLogger('sphinx-gallery')
@@ -331,7 +331,7 @@ def save_thumbnail(image_path_template, src_file, script_vars, file_conf,
331331
img = thumbnail_image_path
332332
elif not os.path.exists(thumb_file):
333333
# create something to replace the thumbnail
334-
default_thumb_path = gallery_conf.get("default_thumb_file")
334+
default_thumb_path = gallery_conf["default_thumb_file"]
335335
if default_thumb_path is None:
336336
default_thumb_path = os.path.join(
337337
glr_path_static(),
@@ -510,7 +510,7 @@ def generate_dir_rst(
510510
subsection_index_content = None
511511

512512
# Copy over any other files.
513-
copyregex = gallery_conf.get('copyfile_regex')
513+
copyregex = gallery_conf['copyfile_regex']
514514
if copyregex:
515515
listdir = [fname for fname in os.listdir(src_dir) if
516516
re.match(copyregex, fname)]
@@ -911,7 +911,7 @@ def executable_script(src_file, gallery_conf):
911911
True if script has to be executed
912912
"""
913913

914-
filename_pattern = gallery_conf.get('filename_pattern')
914+
filename_pattern = gallery_conf['filename_pattern']
915915
execute = re.search(filename_pattern, src_file) and gallery_conf[
916916
'plot_gallery']
917917
return execute
@@ -1230,7 +1230,7 @@ def rst_blocks(script_blocks, output_blocks, file_conf, gallery_conf):
12301230
if blabel == 'code':
12311231

12321232
if not file_conf.get('line_numbers',
1233-
gallery_conf.get('line_numbers', False)):
1233+
gallery_conf['line_numbers']):
12341234
lineno = None
12351235

12361236
code_rst = codestr2rst(bcontent, lang=gallery_conf['lang'],
@@ -1272,12 +1272,10 @@ def save_rst_example(example_rst, example_file, time_elapsed,
12721272
example_fname = os.path.relpath(example_file, gallery_conf['src_dir'])
12731273
ref_fname = example_fname.replace(os.path.sep, "_")
12741274

1275-
binder_conf = check_binder_conf(gallery_conf.get('binder'))
1275+
binder_conf = gallery_conf['binder']
12761276
is_binder_enabled = len(binder_conf) > 0
12771277

1278-
jupyterlite_conf = check_jupyterlite_conf(
1279-
gallery_conf.get('jupyterlite', {}),
1280-
gallery_conf['app'])
1278+
jupyterlite_conf = gallery_conf['jupyterlite']
12811279
is_jupyterlite_enabled = jupyterlite_conf is not None
12821280

12831281
interactive_example_text = ""

sphinx_gallery/interactive_example.py

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ def gen_binder_url(fpath, binder_conf, gallery_conf):
4747
environment.
4848
"""
4949
# Build the URL
50-
fpath_prefix = binder_conf.get('filepath_prefix')
51-
link_base = binder_conf.get('notebooks_dir')
50+
fpath_prefix = binder_conf['filepath_prefix']
51+
link_base = binder_conf['notebooks_dir']
5252

5353
# We want to keep the relative path to sub-folders
5454
relative_link = os.path.relpath(fpath, gallery_conf['src_dir'])
@@ -69,7 +69,7 @@ def gen_binder_url(fpath, binder_conf, gallery_conf):
6969
binder_conf['repo'],
7070
quote(binder_conf['branch'])])
7171

72-
if binder_conf.get('use_jupyter_lab', False) is True:
72+
if binder_conf['use_jupyter_lab'] is True:
7373
binder_url += f'?urlpath=lab/tree/{quote(path_link)}'
7474
else:
7575
binder_url += f'?filepath={quote(path_link)}'
@@ -154,7 +154,7 @@ def copy_binder_files(app, exception):
154154

155155
def _copy_binder_reqs(app, binder_conf):
156156
"""Copy Binder requirements files to a "binder" folder in the docs."""
157-
path_reqs = binder_conf.get('dependencies')
157+
path_reqs = binder_conf['dependencies']
158158
for path in path_reqs:
159159
if not os.path.exists(os.path.join(app.srcdir, path)):
160160
raise ConfigError(
@@ -197,9 +197,9 @@ def _copy_binder_notebooks(app):
197197
Jupyter notebook files."""
198198

199199
gallery_conf = app.config.sphinx_gallery_conf
200-
gallery_dirs = gallery_conf.get('gallery_dirs')
201-
binder_conf = gallery_conf.get('binder')
202-
notebooks_dir = os.path.join(app.outdir, binder_conf.get('notebooks_dir'))
200+
gallery_dirs = gallery_conf['gallery_dirs']
201+
binder_conf = gallery_conf['binder']
202+
notebooks_dir = os.path.join(app.outdir, binder_conf['notebooks_dir'])
203203
shutil.rmtree(notebooks_dir, ignore_errors=True)
204204
os.makedirs(notebooks_dir)
205205

@@ -218,7 +218,7 @@ def _copy_binder_notebooks(app):
218218
def check_binder_conf(binder_conf):
219219
"""Check to make sure that the Binder configuration is correct."""
220220
# Grab the configuration and return None if it's not configured
221-
binder_conf = {} if binder_conf is None else binder_conf
221+
binder_conf = {} if binder_conf is None else binder_conf.copy()
222222
if not isinstance(binder_conf, dict):
223223
raise ConfigError('`binder_conf` must be a dictionary or None.')
224224
if len(binder_conf) == 0:
@@ -258,8 +258,9 @@ def check_binder_conf(binder_conf):
258258
raise ConfigError("`dependencies` value should be a list of strings. "
259259
"Got type {}.".format(type(path_reqs)))
260260

261-
binder_conf['notebooks_dir'] = binder_conf.get('notebooks_dir',
262-
'notebooks')
261+
binder_conf.setdefault('filepath_prefix')
262+
binder_conf.setdefault('notebooks_dir', 'notebooks')
263+
binder_conf.setdefault('use_jupyter_lab', False)
263264
path_reqs_filenames = [os.path.basename(ii) for ii in path_reqs]
264265
if not any(ii in path_reqs_filenames for ii in required_reqs_files):
265266
raise ConfigError(
@@ -273,7 +274,7 @@ def check_binder_conf(binder_conf):
273274
def pre_configure_jupyterlite_sphinx(app, config):
274275
is_jupyterlite_enabled = (
275276
'jupyterlite_sphinx' in app.extensions
276-
and config.sphinx_gallery_conf.get('jupyterlite', {}) is not None
277+
and config.sphinx_gallery_conf['jupyterlite'] is not None
277278
)
278279
if not is_jupyterlite_enabled:
279280
return
@@ -286,7 +287,7 @@ def pre_configure_jupyterlite_sphinx(app, config):
286287

287288
def post_configure_jupyterlite_sphinx(app, config):
288289
config.sphinx_gallery_conf['jupyterlite'] = check_jupyterlite_conf(
289-
config.sphinx_gallery_conf.get('jupyterlite', {}), app)
290+
config.sphinx_gallery_conf['jupyterlite'], app)
290291

291292
if config.sphinx_gallery_conf['jupyterlite'] is None:
292293
return
@@ -315,7 +316,7 @@ def create_jupyterlite_contents(app, exception):
315316
return
316317

317318
logger.info('copying Jupyterlite contents ...', color='white')
318-
gallery_dirs = gallery_conf.get('gallery_dirs')
319+
gallery_dirs = gallery_conf['gallery_dirs']
319320
contents_dir = gallery_conf['jupyterlite']['jupyterlite_contents']
320321

321322
shutil.rmtree(contents_dir, ignore_errors=True)
@@ -383,7 +384,7 @@ def gen_jupyterlite_rst(fpath, gallery_conf):
383384
# Make sure we have the right slashes (in case we're on Windows)
384385
lite_root_url = lite_root_url.replace(os.path.sep, '/')
385386

386-
if gallery_conf["jupyterlite"].get("use_jupyter_lab", True):
387+
if gallery_conf["jupyterlite"]["use_jupyter_lab"]:
387388
lite_root_url += "/lab"
388389
else:
389390
lite_root_url += "/retro/notebooks"

sphinx_gallery/scrapers.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ def matplotlib_scraper(block, block_vars, gallery_conf, **kwargs):
117117
image_path_iterator = block_vars['image_path_iterator']
118118
image_rsts = []
119119
# Check for srcset hidpi images
120-
srcset = gallery_conf.get('image_srcset', [])
120+
srcset = gallery_conf['image_srcset']
121121
srcset_mult_facs = [1] # one is always supplied...
122122
for st in srcset:
123123
if (len(st) > 0) and (st[-1] == 'x'):
@@ -133,7 +133,7 @@ def matplotlib_scraper(block, block_vars, gallery_conf, **kwargs):
133133

134134
# Check for animations
135135
anims = list()
136-
if gallery_conf.get('matplotlib_animations', False):
136+
if gallery_conf['matplotlib_animations']:
137137
for ani in block_vars['example_globals'].values():
138138
if isinstance(ani, Animation):
139139
anims.append(ani)

sphinx_gallery/tests/conftest.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,10 @@ def gallery_conf(tmpdir):
2929
"""Set up a test sphinx-gallery configuration."""
3030
app = Mock(spec=Sphinx, config=dict(source_suffix={'.rst': None}),
3131
extensions=[])
32-
gallery_conf = gen_gallery._complete_gallery_conf(
33-
{}, str(tmpdir), True, False, app=app)
32+
gallery_conf = gen_gallery._complete_gallery_conf_config_inited(
33+
{}, app=app)
34+
gen_gallery._complete_gallery_conf_builder_inited(
35+
gallery_conf, str(tmpdir))
3436
gallery_conf.update(examples_dir=str(tmpdir), gallery_dir=str(tmpdir))
3537
return gallery_conf
3638

0 commit comments

Comments
 (0)