From e2fb5c0d5e9d156c4e96d44501af6af88b658cec Mon Sep 17 00:00:00 2001 From: Steffen Rehberg Date: Mon, 24 Apr 2023 21:06:29 +0200 Subject: [PATCH] MNT: Change % formatting to f-strings - change remaining old-style % formatting to f-strings (cases like '%s' % var or 'str1' 'str2 %s' % (var,) which are not handled by pyupgrade due to their potential ambiguity) - change logging.debug("... %s ..." % x) to logging.debug("... %s ...", x) for uniformity - remove some u string prefixes --- sphinx_gallery/backreferences.py | 10 +-- sphinx_gallery/directives.py | 8 +-- sphinx_gallery/docs_resolv.py | 2 +- sphinx_gallery/gen_gallery.py | 87 ++++++++++++------------ sphinx_gallery/gen_rst.py | 24 +++---- sphinx_gallery/interactive_example.py | 5 +- sphinx_gallery/notebook.py | 5 +- sphinx_gallery/scrapers.py | 9 ++- sphinx_gallery/tests/conftest.py | 8 +-- sphinx_gallery/tests/test_full.py | 21 +++--- sphinx_gallery/tests/test_gen_gallery.py | 2 +- sphinx_gallery/tests/test_gen_rst.py | 4 +- sphinx_gallery/utils.py | 6 +- 13 files changed, 93 insertions(+), 98 deletions(-) diff --git a/sphinx_gallery/backreferences.py b/sphinx_gallery/backreferences.py index ed8316bd2..2d070f54b 100644 --- a/sphinx_gallery/backreferences.py +++ b/sphinx_gallery/backreferences.py @@ -293,11 +293,11 @@ def _thumbnail_div(target_dir, src_dir, fname, snippet, title, """Generate reST to place a thumbnail in a gallery.""" thumb, _ = _find_image_ext( os.path.join(target_dir, 'images', 'thumb', - 'sphx_glr_%s_thumb.png' % fname[:-3])) + f'sphx_glr_{fname[:-3]}_thumb.png')) if check and not os.path.isfile(thumb): # This means we have done something wrong in creating our thumbnail! raise ExtensionError('Could not find internal Sphinx-Gallery thumbnail' - ' file:\n%s' % (thumb,)) + f' file:\n{thumb}') thumb = os.path.relpath(thumb, src_dir) full_dir = os.path.relpath(target_dir, src_dir) @@ -320,14 +320,14 @@ def _write_backreferences(backrefs, seen_backrefs, gallery_conf, for backref in backrefs: include_path = os.path.join(gallery_conf['src_dir'], gallery_conf['backreferences_dir'], - '%s.examples.new' % backref) + f'{backref}.examples.new') seen = backref in seen_backrefs with codecs.open(include_path, 'a' if seen else 'w', encoding='utf-8') as ex_file: if not seen: # Be aware that if the number of lines of this heading changes, # the minigallery directive should be modified accordingly - heading = 'Examples using ``%s``' % backref + heading = f'Examples using ``{backref}``' ex_file.write('\n\n' + heading + '\n') ex_file.write('^' * len(heading) + '\n') ex_file.write('\n\n.. start-sphx-glr-thumbnails\n\n') @@ -349,7 +349,7 @@ def _finalize_backreferences(seen_backrefs, gallery_conf): for backref in seen_backrefs: path = os.path.join(gallery_conf['src_dir'], gallery_conf['backreferences_dir'], - '%s.examples.new' % backref) + f'{backref}.examples.new') if os.path.isfile(path): # Close div containing all thumbnails # (it was open in _write_backreferences) diff --git a/sphinx_gallery/directives.py b/sphinx_gallery/directives.py index 440a50d42..f12f12385 100644 --- a/sphinx_gallery/directives.py +++ b/sphinx_gallery/directives.py @@ -40,7 +40,7 @@ def run(self): # Respect the same disabling options as the `raw` directive if (not self.state.document.settings.raw_enabled or not self.state.document.settings.file_insertion_enabled): - raise self.warning('"%s" directive disabled.' % self.name) + raise self.warning(f'"{self.name}" directive disabled.') # Retrieve the backreferences directory config = self.state.document.settings.env.config @@ -81,9 +81,9 @@ def has_backrefs(obj): f'{obj}.examples') # Always remove the heading from the file - lines.append("""\ -.. include:: {} - :start-after: start-sphx-glr-thumbnails""".format(path)) + lines.append(f"""\ +.. include:: {path} + :start-after: start-sphx-glr-thumbnails""") # Parse the assembly of `include` and `raw` directives text = '\n'.join(lines) diff --git a/sphinx_gallery/docs_resolv.py b/sphinx_gallery/docs_resolv.py index b6c92fa1a..07e129188 100644 --- a/sphinx_gallery/docs_resolv.py +++ b/sphinx_gallery/docs_resolv.py @@ -346,7 +346,7 @@ def _embed_code_links(app, gallery_conf, gallery_dir): for dirpath, _, filenames in os.walk(html_gallery_dir) for filename in filenames] iterator = status_iterator( - flat, 'embedding documentation hyperlinks for %s... ' % gallery_dir, + flat, f'embedding documentation hyperlinks for {gallery_dir}... ', color='fuchsia', length=len(flat), stringify_func=lambda x: os.path.basename(x[1])) intersphinx_inv = getattr(app.env, 'intersphinx_named_inventory', dict()) diff --git a/sphinx_gallery/gen_gallery.py b/sphinx_gallery/gen_gallery.py index 4fe1ea825..119b76e30 100644 --- a/sphinx_gallery/gen_gallery.py +++ b/sphinx_gallery/gen_gallery.py @@ -176,14 +176,15 @@ def _fill_gallery_conf_defaults(sphinx_gallery_conf, app=None, for rep in capture_repr: if rep not in supported_reprs: raise ConfigError("All entries in 'capture_repr' must be one " - "of %s, got: %s" % (supported_reprs, rep)) + f"of {supported_reprs}, got: {rep}") else: - raise ConfigError("'capture_repr' must be a tuple, got: %s" - % (type(capture_repr),)) + raise ConfigError( + f"'capture_repr' must be a tuple, got: {type(capture_repr)}" + ) # Check ignore_repr_types if not isinstance(gallery_conf['ignore_repr_types'], str): - raise ConfigError("'ignore_repr_types' must be a string, got: %s" - % (type(gallery_conf['ignore_repr_types']),)) + raise ConfigError("'ignore_repr_types' must be a string, got: " + + type(gallery_conf['ignore_repr_types'])) # deal with show_memory gallery_conf['memory_base'] = 0. @@ -230,8 +231,9 @@ def call_memory(func): scraper = getattr(scraper, '_get_sg_image_scraper') scraper = scraper() except Exception as exp: - raise ConfigError('Unknown image scraper %r, got:\n%s' - % (orig_scraper, exp)) + raise ConfigError( + f'Unknown image scraper {orig_scraper!r}, got:\n{exp}' + ) scrapers[si] = scraper if not callable(scraper): raise ConfigError(f'Scraper {scraper!r} was not callable') @@ -257,7 +259,7 @@ def call_memory(func): compress_images = [compress_images] elif not isinstance(compress_images, (tuple, list)): raise ConfigError('compress_images must be a tuple, list, or str, ' - 'got %s' % (type(compress_images),)) + f'got {type(compress_images)}') compress_images = list(compress_images) allowed_values = ('images', 'thumbnails') pops = list() @@ -267,13 +269,13 @@ def call_memory(func): pops.append(ki) continue raise ConfigError('All entries in compress_images must be one of ' - '%s or a command-line switch starting with "-", ' - 'got %r' % (allowed_values, kind)) + f'{allowed_values} or a command-line switch ' + f'starting with "-", got {kind!r}') compress_images_args = [compress_images.pop(p) for p in pops[::-1]] if len(compress_images) and not _has_optipng(): logger.warning( - 'optipng binaries not found, PNG %s will not be optimized' - % (' and '.join(compress_images),)) + 'optipng binaries not found, PNG %s will not be optimized', + ' and '.join(compress_images)) compress_images = () gallery_conf['compress_images'] = compress_images gallery_conf['compress_images_args'] = compress_images_args @@ -286,21 +288,21 @@ def call_memory(func): for ri, resetter in enumerate(resetters): if isinstance(resetter, str): if resetter not in _reset_dict: - raise ConfigError('Unknown module resetter named %r' - % (resetter,)) + raise ConfigError( + f'Unknown module resetter named {resetter!r}' + ) resetters[ri] = _reset_dict[resetter] elif not callable(resetter): - raise ConfigError('Module resetter %r was not callable' - % (resetter,)) + raise ConfigError(f'Module resetter {resetter!r} was not callable') gallery_conf['reset_modules'] = tuple(resetters) if not isinstance(gallery_conf['reset_modules_order'], str): raise ConfigError('reset_modules_order must be a str, ' - 'got %r' % gallery_conf['reset_modules_order']) + f'got {gallery_conf["reset_modules_order"]!r}') if gallery_conf['reset_modules_order'] not in ['before', 'after', 'both']: raise ConfigError("reset_modules_order must be in" "['before', 'after', 'both'], " - 'got %r' % gallery_conf['reset_modules_order']) + f"got {gallery_conf['reset_modules_order']!r}") del resetters @@ -308,17 +310,17 @@ def call_memory(func): first_cell = gallery_conf.get("first_notebook_cell") if (not isinstance(first_cell, str)) and (first_cell is not None): raise ConfigError("The 'first_notebook_cell' parameter must be type " - "str or None, found type %s" % type(first_cell)) + f"str or None, found type {type(first_cell)}") # Ensure the last cell text is a string if we have it last_cell = gallery_conf.get("last_notebook_cell") if (not isinstance(last_cell, str)) and (last_cell is not None): raise ConfigError("The 'last_notebook_cell' parameter must be type str" - " or None, found type %s" % type(last_cell)) + f" or None, found type {type(last_cell)}") # Check pypandoc pypandoc = gallery_conf['pypandoc'] if not isinstance(pypandoc, (dict, bool)): raise ConfigError("'pypandoc' parameter must be of type bool or dict," - "got: %s." % type(pypandoc)) + f"got: {type(pypandoc)}.") gallery_conf['pypandoc'] = dict() if pypandoc is True else pypandoc has_pypandoc, version = _has_pypandoc() if isinstance(gallery_conf['pypandoc'], dict) and has_pypandoc is None: @@ -327,7 +329,7 @@ def call_memory(func): gallery_conf['pypandoc'] = False elif isinstance(gallery_conf['pypandoc'], dict): logger.info("Using pandoc version: %s to convert rst text blocks to " - "markdown for .ipynb files" % (version,)) + "markdown for .ipynb files", version) else: logger.info("Using Sphinx-Gallery to convert rst text blocks to " "markdown for .ipynb files.") @@ -336,8 +338,7 @@ def call_memory(func): for key in pypandoc: if key not in accepted_keys: raise ConfigError("'pypandoc' only accepts the following key " - "values: %s, got: %s." - % (accepted_keys, key)) + f"values: {accepted_keys}, got: {key}.") gallery_conf['titles'] = {} # Ensure 'backreferences_dir' is str, pathlib.Path or None @@ -346,7 +347,7 @@ def call_memory(func): (backref is not None): raise ConfigError("The 'backreferences_dir' parameter must be of type " "str, pathlib.Path or None, " - "found type %s" % type(backref)) + f"found type {type(backref)}") # if 'backreferences_dir' is pathlib.Path, make str for Python <=3.5 # compatibility if isinstance(backref, pathlib.Path): @@ -360,25 +361,26 @@ def call_memory(func): gallery_conf.get('jupyterlite', {}), app) if not isinstance(gallery_conf['css'], (list, tuple)): - raise ConfigError('gallery_conf["css"] must be list or tuple, got %r' - % (gallery_conf['css'],)) + raise ConfigError('gallery_conf["css"] must be list or tuple, got ' + f'{gallery_conf["css"]!r}') for css in gallery_conf['css']: if css not in _KNOWN_CSS: - raise ConfigError('Unknown css %r, must be one of %r' - % (css, _KNOWN_CSS)) + raise ConfigError( + f'Unknown css {css!r}, must be one of {_KNOWN_CSS!r}' + ) if gallery_conf['app'] is not None: # can be None in testing gallery_conf['app'].add_css_file(css + '.css') # check API usage if not isinstance(gallery_conf['api_usage_ignore'], str): raise ConfigError('gallery_conf["api_usage_ignore"] must be str, ' - 'got %s' % type(gallery_conf['api_usage_ignore'])) + f'got {type(gallery_conf["api_usage_ignore"])}') if not isinstance(gallery_conf['show_api_usage'], bool) and \ gallery_conf['show_api_usage'] != 'unused': raise ConfigError( 'gallery_conf["show_api_usage"] must be True, False or "unused", ' - 'got %s' % gallery_conf['show_api_usage']) + f'got {gallery_conf["show_api_usage"]}') _update_gallery_conf_exclude_implicit_doc(gallery_conf) @@ -456,7 +458,7 @@ def _format_toctree(items, includehidden=False): """ st += """ - %s\n""" % "\n ".join(items) + {}\n""".format("\n ".join(items)) st += "\n" @@ -695,7 +697,7 @@ def write_computation_times(gallery_conf, target_dir, costs): return target_dir_clean = os.path.relpath( target_dir, gallery_conf['src_dir']).replace(os.path.sep, '_') - new_ref = 'sphx_glr_%s_sg_execution_times' % target_dir_clean + new_ref = f'sphx_glr_{target_dir_clean}_sg_execution_times' with codecs.open(os.path.join(target_dir, 'sg_execution_times.rst'), 'w', encoding='utf-8') as fid: fid.write(SPHX_GLR_COMP_TIMES.format(new_ref)) @@ -924,7 +926,7 @@ def get_entry_type(entry): ' :layout: neato\n\n') for module in used_modules: - logger.info(f'Making API usage graph for {module}') + logger.info('Making API usage graph for %s', module) # select and format entries for this module entries = dict() for entry, ref in used_api_entries.items(): @@ -1015,7 +1017,7 @@ def touch_empty_backreferences(app, what, name, obj, options, lines): examples_path = os.path.join(app.srcdir, app.config.sphinx_gallery_conf[ "backreferences_dir"], - "%s.examples" % name) + f"{name}.examples") if not os.path.exists(examples_path): # touch file @@ -1095,12 +1097,11 @@ def summarize_failing_examples(app, exception): ' gallery_conf["filename_pattern"] = %r\n' ' gallery_conf["ignore_pattern"] = %r\n' '\nafter excluding %d file%s that had previously been run ' - '(based on MD5).\n' - % (n_good, n_tot, 's' if n_tot != 1 else '', - gallery_conf['filename_pattern'], - gallery_conf['ignore_pattern'], - n_stale, 's' if n_stale != 1 else '', - ), + '(based on MD5).\n', + n_good, n_tot, 's' if n_tot != 1 else '', + gallery_conf['filename_pattern'], + gallery_conf['ignore_pattern'], + n_stale, 's' if n_stale != 1 else '', color='brown') if fail_msgs: @@ -1143,7 +1144,7 @@ def check_duplicate_filenames(files): logger.warning( 'Duplicate example file name(s) found. Having duplicate file ' 'names will break some links. ' - 'List of files: {}'.format(sorted(dup_names),)) + 'List of files: %s', sorted(dup_names)) def check_spaces_in_filenames(files): @@ -1154,7 +1155,7 @@ def check_spaces_in_filenames(files): logger.warning( 'Example file name(s) with space(s) found. Having space(s) in ' 'file names will break some links. ' - 'List of files: {}'.format(sorted(files_with_space),)) + 'List of files: %s', sorted(files_with_space)) def get_default_config_value(key): diff --git a/sphinx_gallery/gen_rst.py b/sphinx_gallery/gen_rst.py index fbf6e9eb7..43f94c29a 100644 --- a/sphinx_gallery/gen_rst.py +++ b/sphinx_gallery/gen_rst.py @@ -246,8 +246,7 @@ def extract_intro_and_title(filename, docstring): if match is None: raise ExtensionError( - 'Could not find a title in first paragraph:\n{}'.format( - title_paragraph)) + f'Could not find a title in first paragraph:\n{title_paragraph}') title = match.group(0).strip() # Use the title if no other paragraphs are provided intro_paragraph = title if len(paragraphs) < 2 else paragraphs[1] @@ -313,7 +312,7 @@ def save_thumbnail(image_path_template, src_file, script_vars, file_conf, if not isinstance(thumbnail_number, int): raise ExtensionError( 'sphinx_gallery_thumbnail_number setting is not a number, ' - 'got %r' % (thumbnail_number,)) + f'got {thumbnail_number!r}') # negative index means counting from the last one if thumbnail_number < 0: thumbnail_number += len(script_vars["image_path_iterator"]) + 1 @@ -453,7 +452,7 @@ def generate_dir_rst( build_target_dir = os.path.relpath(target_dir, gallery_conf['src_dir']) iterator = status_iterator( sorted_listdir, - 'generating gallery for %s... ' % build_target_dir, + f'generating gallery for {build_target_dir}... ', length=len(sorted_listdir)) for fname in iterator: intro, title, cost = generate_file_rst( @@ -484,7 +483,7 @@ def generate_dir_rst( with codecs.open(subsection_index_path, 'w', encoding='utf-8') as ( findex ): - findex.write("""\n\n.. _sphx_glr_{}:\n\n""".format( + findex.write("\n\n.. _sphx_glr_{}:\n\n".format( head_ref.replace(os.path.sep, '_') )) findex.write(subsection_index_content) @@ -501,8 +500,8 @@ def generate_dir_rst( .. toctree:: :hidden: - %s\n -""" % "\n ".join(subsection_toctree_filenames) + {}\n +""".format("\n ".join(subsection_toctree_filenames)) findex.write(subsection_index_toctree) if have_index_rst: @@ -662,7 +661,7 @@ def _get_memory_base(gallery_conf): sleep, timeout = (0.5, 1) proc = subprocess.Popen( [sys.executable, '-c', - 'import time, sys; time.sleep(%s); sys.exit(0)' % sleep], + f'import time, sys; time.sleep({sleep}); sys.exit(0)'], close_fds=True) memories = memory_usage(proc, interval=1e-3, timeout=timeout) kwargs = dict(timeout=timeout) if sys.version_info >= (3, 5) else {} @@ -784,9 +783,7 @@ def _get_code_output(is_last_expr, example_globals, gallery_conf, logging_tee, else: captured_html = '' - code_output = "\n{}\n\n{}\n{}\n\n".format( - images_rst, captured_std, captured_html - ) + code_output = f"\n{images_rst}\n\n{captured_std}\n{captured_html}\n\n" return code_output @@ -1086,7 +1083,7 @@ def generate_file_rst(fname, target_dir, src_dir, gallery_conf, if type(dummy_image) is not int: raise ExtensionError( 'sphinx_gallery_dummy_images setting is not a number, ' - 'got %r' % (dummy_image,)) + 'got {dummy_image!r}') image_path_iterator = script_vars['image_path_iterator'] stock_img = os.path.join(glr_path_static(), 'no_image.png') @@ -1302,8 +1299,7 @@ def save_rst_example(example_rst, example_file, time_elapsed, fname = os.path.basename(example_file) if gallery_conf['show_memory']: - example_rst += ("**Estimated memory usage:** {: .0f} MB\n\n" - .format(memory_used)) + example_rst += f"**Estimated memory usage:** {memory_used: .0f} MB\n\n" # Generate a binder URL if specified binder_badge_rst = '' diff --git a/sphinx_gallery/interactive_example.py b/sphinx_gallery/interactive_example.py index 48b5d9d9b..99ec55e7a 100644 --- a/sphinx_gallery/interactive_example.py +++ b/sphinx_gallery/interactive_example.py @@ -233,8 +233,9 @@ def check_binder_conf(binder_conf): missing_values.append(val) if len(missing_values) > 0: - raise ConfigError('binder_conf is missing values for: {}'.format( - missing_values)) + raise ConfigError( + f'binder_conf is missing values for: {missing_values}' + ) for key in binder_conf.keys(): if key not in (req_values + optional_values): diff --git a/sphinx_gallery/notebook.py b/sphinx_gallery/notebook.py index bbe49ba7d..5ba71ca40 100644 --- a/sphinx_gallery/notebook.py +++ b/sphinx_gallery/notebook.py @@ -209,10 +209,9 @@ def generate_image_src(image_path, gallery_conf, target_dir): data = base64.b64encode(image_file.read()) except OSError: raise ExtensionError( - 'Unable to open {} to generate notebook data URI' - ''.format(full_path)) + f'Unable to open {full_path} to generate notebook data URI') mime_type = mimetypes.guess_type(full_path) - return 'data:{};base64,{}'.format(mime_type[0], data.decode('ascii')) + return f"data:{mime_type[0]};base64,{data.decode('ascii')}" def jupyter_notebook(script_blocks, gallery_conf, target_dir): diff --git a/sphinx_gallery/scrapers.py b/sphinx_gallery/scrapers.py index 0de09aa1f..8fa19d2d9 100644 --- a/sphinx_gallery/scrapers.py +++ b/sphinx_gallery/scrapers.py @@ -339,17 +339,16 @@ def save_figures(block, block_vars, gallery_conf): for scraper in gallery_conf['image_scrapers']: rst = scraper(block, block_vars, gallery_conf) if not isinstance(rst, str): - raise ExtensionError('rst from scraper %r was not a string, ' - 'got type %s:\n%r' - % (scraper, type(rst), rst)) + raise ExtensionError(f'rst from scraper {scraper!r} was not a ' + f'string, got type {type(rst)}:\n{rst!r}') n_new = len(image_path_iterator) - prev_count for ii in range(n_new): current_path, _ = _find_image_ext( image_path_iterator.paths[prev_count + ii]) if not os.path.isfile(current_path): raise ExtensionError( - 'Scraper %s did not produce expected image:' - '\n%s' % (scraper, current_path)) + f'Scraper {scraper} did not produce expected image:' + f'\n{current_path}') all_rst += rst return all_rst diff --git a/sphinx_gallery/tests/conftest.py b/sphinx_gallery/tests/conftest.py index 0e90e0b21..e2cb3ca3c 100644 --- a/sphinx_gallery/tests/conftest.py +++ b/sphinx_gallery/tests/conftest.py @@ -178,16 +178,16 @@ def sphinx_app_wrapper(tmpdir, conf_file, req_mpl, req_pil): shutil.copytree(os.path.join(_fixturedir, "src"), os.path.join(str(tmpdir), "examples")) - base_config = """ + base_config = f""" import os import sphinx_gallery -extensions = {!r} +extensions = {conf_file['extensions']!r} exclude_patterns = ['_build'] source_suffix = '.rst' master_doc = 'index' # General information about the project. -project = u'Sphinx-Gallery '\n\n -""".format(conf_file['extensions']) +project = 'Sphinx-Gallery '\n\n +""" with open(os.path.join(srcdir, "conf.py"), "w") as conffile: conffile.write(base_config + conf_file['content']) diff --git a/sphinx_gallery/tests/test_full.py b/sphinx_gallery/tests/test_full.py index 4cc65cf8e..12f54fc22 100644 --- a/sphinx_gallery/tests/test_full.py +++ b/sphinx_gallery/tests/test_full.py @@ -96,7 +96,7 @@ def test_timings(sphinx_app): with codecs.open(timings_rst, 'r', 'utf-8') as fid: content = fid.read() assert ':ref:`sphx_glr_auto_examples_plot_numpy_matplotlib.py`' in content - parenthetical = '(``{}``)'.format('plot_numpy_matplotlib.py') + parenthetical = "(``plot_numpy_matplotlib.py``)" assert parenthetical in content # HTML output timings_html = op.join(out_dir, 'auto_examples', @@ -108,7 +108,7 @@ def test_timings(sphinx_app): # printed status = sphinx_app._status.getvalue() fname = op.join('..', 'examples', 'plot_numpy_matplotlib.py') - assert ('- %s: ' % fname) in status + assert f'- {fname}: ' in status def test_api_usage(sphinx_app): @@ -142,7 +142,7 @@ def test_api_usage(sphinx_app): # printed status = sphinx_app._status.getvalue() fname = op.join('..', 'examples', 'plot_numpy_matplotlib.py') - assert ('- %s: ' % fname) in status + assert f'- {fname}: ' in status def test_optipng(sphinx_app): @@ -165,7 +165,7 @@ def test_junit(sphinx_app, tmpdir): contents = fid.read() assert contents.startswith('