From ac473fab6ed3aa498b7ebeb88074e1a98ecfa326 Mon Sep 17 00:00:00 2001 From: James Knight Date: Sat, 2 Mar 2024 13:46:48 -0500 Subject: [PATCH] utilize f-strings Updating various implementation to take advantage of f-strings over the use of printf (UP031) and format (UP032). This includes also tweaks to original format calls to use variables for some complex values, as well as even dropping format calls for simple string concatenation. Signed-off-by: James Knight --- sphinxcontrib/confluencebuilder/builder.py | 9 ++- sphinxcontrib/confluencebuilder/cmd/report.py | 6 +- .../confluencebuilder/intersphinx.py | 18 +++--- sphinxcontrib/confluencebuilder/rest.py | 10 ++-- .../confluencebuilder/singlebuilder.py | 3 +- sphinxcontrib/confluencebuilder/state.py | 8 +-- .../confluencebuilder/storage/translator.py | 59 ++++++++++--------- .../confluencebuilder/transmute/__init__.py | 12 ++-- tests/__main__.py | 6 +- tests/lib/__init__.py | 8 +-- tests/test_validation.py | 8 +-- .../test_config_postfix_formatting.py | 3 +- .../unit-tests/test_sphinx_image_candidate.py | 3 +- 13 files changed, 75 insertions(+), 78 deletions(-) diff --git a/sphinxcontrib/confluencebuilder/builder.py b/sphinxcontrib/confluencebuilder/builder.py index 50e5f10c..157782d3 100644 --- a/sphinxcontrib/confluencebuilder/builder.py +++ b/sphinxcontrib/confluencebuilder/builder.py @@ -134,8 +134,7 @@ def init(self): old_url = self.config.confluence_server_url new_url = ConfluenceUtil.normalize_base_url(old_url) if old_url != new_url: - self.warn('normalizing confluence url from ' - '{} to {} '.format(old_url, new_url)) + self.warn(f'normalizing confluence url from {old_url} to {new_url}') self.config.confluence_server_url = new_url # detect if Confluence Cloud if using the Atlassian domain @@ -611,7 +610,7 @@ def publish_asset(self, key, docname, output, type_, hash_): self.state.register_upload_id(docname, page_id) else: self.warn('cannot publish asset since publishing ' - 'point cannot be found ({}): {}'.format(key, docname)) + f'point cannot be found ({key}): {docname}') return attachment_id = None @@ -1166,9 +1165,9 @@ def _parse_doctree_title(self, docname, doctree): doctitle = f'autogen-{docname}' if self.publish: self.warn('document will be published using an ' - 'generated title value: {}'.format(docname)) + f'generated title value: {docname}') elif self.publish: self.warn('document will not be published since it ' - 'has no title: {}'.format(docname)) + f'has no title: {docname}') return doctitle diff --git a/sphinxcontrib/confluencebuilder/cmd/report.py b/sphinxcontrib/confluencebuilder/cmd/report.py index a19a32d7..952c52ec 100644 --- a/sphinxcontrib/confluencebuilder/cmd/report.py +++ b/sphinxcontrib/confluencebuilder/cmd/report.py @@ -182,9 +182,9 @@ def report_main(args_parser): for o in root.findall('buildNumber'): info += ' build: ' + o.text + '\n' else: - logger.error('bad response from server ({})'.format( - rsp.status_code)) - info += f' fetched: error ({rsp.status_code})\n' + code = rsp.status_code + logger.error(f'bad response from server ({code})') + info += f' fetched: error ({code})\n' rv = 1 except Exception: # noqa: BLE001 sys.stdout.flush() diff --git a/sphinxcontrib/confluencebuilder/intersphinx.py b/sphinxcontrib/confluencebuilder/intersphinx.py index fc85a915..e5300b29 100644 --- a/sphinxcontrib/confluencebuilder/intersphinx.py +++ b/sphinxcontrib/confluencebuilder/intersphinx.py @@ -34,13 +34,14 @@ def escape(string): inventory_db = builder.out_dir / INVENTORY_FILENAME with inventory_db.open('wb') as f: # header - f.write(( - '# Sphinx inventory version 2\n' - '# Project: {}\n' - '# Version: {}\n' - '# The remainder of this file is compressed using zlib.\n'.format( - escape(builder.env.config.project), - escape(builder.env.config.version))).encode()) + f.write( + ( + '# Sphinx inventory version 2\n' + f'# Project: {escape(builder.env.config.project)}\n' + f'# Version: {escape(builder.env.config.version)}\n' + '# The remainder of this file is compressed using zlib.\n' + ).encode() + ) # contents compressor = zlib.compressobj(9) @@ -74,8 +75,7 @@ def escape(string): uri += '#' + anchor if dispname == name: dispname = '-' - entry = ('%s %s:%s %s %s %s\n' % - (name, domainname, typ, prio, uri, dispname)) + entry = f'{name} {domainname}:{typ} {prio} {uri} {dispname}\n' logger.verbose('(intersphinx) ' + entry.strip()) f.write(compressor.compress(entry.encode('utf-8'))) diff --git a/sphinxcontrib/confluencebuilder/rest.py b/sphinxcontrib/confluencebuilder/rest.py index 1b529299..9751c454 100644 --- a/sphinxcontrib/confluencebuilder/rest.py +++ b/sphinxcontrib/confluencebuilder/rest.py @@ -86,7 +86,7 @@ def _wrapper(self, *args, **kwargs): if self.config.confluence_publish_delay: delay = self.config.confluence_publish_delay logger.verbose('user-set api delay set; ' - 'waiting {} seconds...'.format(math.ceil(delay))) + f'waiting {math.ceil(delay)} seconds...') time.sleep(delay) # if confluence asked us to wait so many seconds before a next @@ -94,7 +94,7 @@ def _wrapper(self, *args, **kwargs): if self.next_delay: delay = self.next_delay logger.verbose('rate-limit header detected; ' - 'waiting {} seconds...'.format(math.ceil(delay))) + f'waiting {math.ceil(delay)} seconds...') time.sleep(delay) self.next_delay = None @@ -128,7 +128,7 @@ def _wrapper(self, *args, **kwargs): # wait the calculated delay before retrying again logger.warn('rate-limit response detected; ' - 'waiting {} seconds...'.format(math.ceil(delay))) + f'waiting {math.ceil(delay)} seconds...') time.sleep(delay) self.last_retry = delay attempt += 1 @@ -373,8 +373,8 @@ def _process_request(self, method, path, *args, **kwargs): # user once if delay >= 60 and not self._reported_large_delay: logger.warn('(warning) site has reported a long ' - 'rate-limit delay ({} seconds)'.format( - math.ceil(delay))) + 'rate-limit delay ' + f'({math.ceil(delay)} seconds)') self._reported_large_delay = True # check if Confluence reports a `Deprecation` header in the response; diff --git a/sphinxcontrib/confluencebuilder/singlebuilder.py b/sphinxcontrib/confluencebuilder/singlebuilder.py index b5b886d2..fa051537 100644 --- a/sphinxcontrib/confluencebuilder/singlebuilder.py +++ b/sphinxcontrib/confluencebuilder/singlebuilder.py @@ -59,8 +59,7 @@ def get_relative_uri(self, from_, to, typ=None): def get_target_uri(self, docname, typ=None): if docname in self.env.all_docs: - return '{}{}#{}'.format( - self.config.root_doc, self.link_suffix, docname) + return f'{self.config.root_doc}{self.link_suffix}#{docname}' else: return self.link_transform(docname) diff --git a/sphinxcontrib/confluencebuilder/state.py b/sphinxcontrib/confluencebuilder/state.py index 5532d1af..979180bb 100644 --- a/sphinxcontrib/confluencebuilder/state.py +++ b/sphinxcontrib/confluencebuilder/state.py @@ -105,9 +105,9 @@ def register_title(docname, title, config): offset = 2 while title.lower() in ConfluenceState.title2doc: if offset == 2: + docname2 = ConfluenceState.title2doc[title.lower()] logger.warn('title conflict detected with ' - "'{}' and '{}'".format( - ConfluenceState.title2doc[title.lower()], docname)) + f"'{docname2}' and '{docname}'") tail = f' ({offset}){base_tail}' if len(base_title) + len(tail) > try_max: @@ -227,8 +227,8 @@ def _format_postfix(postfix, docname, config): ) except KeyError: raise ConfluenceConfigError( - "Configured confluence_publish_prefix '{postfix}' has an " - "unknown template replacement.".format(postfix=postfix)) + f"Configured confluence_publish_prefix '{postfix}' has an " + "unknown template replacement.") return postfix @staticmethod diff --git a/sphinxcontrib/confluencebuilder/storage/translator.py b/sphinxcontrib/confluencebuilder/storage/translator.py index 7a42380f..50f2ddf0 100644 --- a/sphinxcontrib/confluencebuilder/storage/translator.py +++ b/sphinxcontrib/confluencebuilder/storage/translator.py @@ -101,9 +101,9 @@ def get_secnumber(self, node): if self.builder.name == 'singleconfluence': docname = self._docnames[-1] raw_anchor = node.parent['ids'][0] - anchorname = '{}/#{}'.format(docname, node.parent['ids'][0]) + anchorname = f'{docname}/#{raw_anchor}' if anchorname not in self.builder.secnumbers: - anchorname = '%s/' % raw_anchor + anchorname = f'{raw_anchor}/' else: anchorname = '#' + node.parent['ids'][0] if anchorname not in self.builder.secnumbers: @@ -171,7 +171,7 @@ def visit_start_of_file(self, node): # an anchor point with the name matching the title (which allows the # fallback link to jump to the desired point in a document). if self.builder.name == 'singleconfluence': - doc_anchorname = '%s/' % node['docname'] + doc_anchorname = node['docname'] + '/' doc_target = self.state.target(doc_anchorname) if not doc_target: doc_id = node['docname'] @@ -276,7 +276,8 @@ def visit_paragraph(self, node): # on the paragraph since the v2 editor does not permit nesting # block elements for indentation if self.v2 and self._indent_level > 0: - style += 'margin-left: {}px;'.format(INDENT * self._indent_level) + offset = INDENT * self._indent_level + style += f'margin-left: {offset}px;' # MyST-Parser will inject text-align hints in the node's classes # attribute; if set, attempt to apply the style @@ -430,14 +431,12 @@ def visit_enumerated_list(self, node): elif node['enumtype'] == 'arabic': list_style_type = 'decimal' else: - self.warn( - 'unknown enumerated list type: {}'.format(node['enumtype'])) + self.warn('unknown enumerated list type: ' + node['enumtype']) if list_style_type: if 'style' not in attribs: attribs['style'] = '' - attribs['style'] = '{}list-style-type: {};'.format( - attribs['style'], list_style_type) + attribs['style'] += f'list-style-type: {list_style_type};' self.body.append(self._start_tag(node, 'ol', suffix=self.nl, **attribs)) self.context.append(self._end_tag(node)) @@ -513,9 +512,9 @@ def visit_term(self, node): self.body.append(self.context.pop()) # dt/p if self.v2: + offset = INDENT * self._indent_level self.body.append(self._start_tag(node, 'p', - **{'style': 'margin-left: {}px;'.format( - INDENT * self._indent_level)})) + **{'style': f'margin-left: {offset}px;'})) self.context.append(self._end_tag(node)) if 'ids' in node: @@ -1133,8 +1132,9 @@ def visit_tgroup(self, node): # configuring it explicitly may break the editor's page # width configuration attribs = {} - if colspec['colwidth'] != 100 or not self.v2: - attribs['style'] = 'width: {}%'.format(colspec['colwidth']) + colwidth = colspec['colwidth'] + if colwidth != 100 or not self.v2: + attribs['style'] = f'width: {colwidth}%' self.body.append(self._start_tag( node, 'col', empty=True, **attribs)) @@ -1296,7 +1296,7 @@ def _visit_reference_intern_id(self, node): docname = self._docnames[-1] anchorname = f'{docname}/#{raw_anchor}' if anchorname not in self.builder.secnumbers: - anchorname = '%s/' % raw_anchor + anchorname = f'{raw_anchor}/' else: anchorname = f'{self.docname}#{raw_anchor}' @@ -1346,7 +1346,7 @@ def _visit_reference_intern_uri(self, node): doctitle = self.state.title(docname) if not doctitle: self.warn('unable to build link to document due to ' - 'missing title (in {}): {}'.format(self.docname, docname)) + f'missing title (in {self.docname}): {docname}') # build a broken link self.body.append(self._start_tag(node, 'a', **{'href': '#'})) @@ -1695,8 +1695,7 @@ def visit_caption(self, node): alignment = self._fetch_alignment(node) if alignment and alignment != 'left': - attribs['style'] = '{}text-align: {};'.format( - attribs['style'], alignment) + attribs['style'] += f'text-align: {alignment};' self.body.append(self._start_tag(node, 'p', **attribs)) self.add_fignumber(node.parent) @@ -1730,8 +1729,9 @@ def _visit_image(self, node, opts): # offset vertical image to align with paragraph if not self.v2 and node.get('from_math') and node.get('math_depth'): math_depth = node['math_depth'] + offset = -1 * math_depth self.body.append(self._start_tag(node, 'span', - **{'style': 'vertical-align: {}px'.format(-1 * math_depth)})) + **{'style': f'vertical-align: {offset}px'})) self.context.append(self._end_tag(node)) node.math_number = None @@ -1888,8 +1888,8 @@ def depart_legend(self, node): # ------------------ def visit_download_reference(self, node): - uri = node['reftarget'] - uri = self.encode(uri) + reftarget = node['reftarget'] + uri = self.encode(reftarget) if uri.find('://') != -1: self.body.append(self._start_tag(node, 'strong')) @@ -1915,8 +1915,7 @@ def visit_download_reference(self, node): node, asset_docname, standalone=True) if not file_key: - self.warn('unable to find download: ' '{}'.format( - node['reftarget'])) + self.warn(f'unable to find download: {reftarget}') raise nodes.SkipNode hosting_doctitle = self.state.title(hosting_docname) @@ -2065,7 +2064,8 @@ def visit_productionlist(self, node): self.body.append(f'{formatted_token} ::=') lastname = production['tokenname'] else: - self.body.append('{} '.format(' ' * len(lastname))) + prefix = ' ' * len(lastname) + self.body.append(f'{prefix} ') text = production.astext() text = self.encode(text) self.body.append(text + self.nl) @@ -2263,8 +2263,7 @@ def visit_versionmodified(self, node): elif node['type'] == 'versionadded': self._visit_info(node) else: - self.warn('unsupported version modification type: ' - '{}'.format(node['type'])) + self.warn('unsupported version modification type: ' + node['type']) self._visit_info(node) depart_versionmodified = _depart_admonition @@ -2297,7 +2296,7 @@ def visit_confluence_excerpt_include(self, node): if not doctitle: self.warn('unable to build excerpt include to document since ' 'document is missing or is missing title ' - '(in {}): {}'.format(self.docname, docname)) + f'(in {self.docname}): {docname}') raise nodes.SkipNode elif ':' in doclink: space_key, doctitle = doclink.split(':', 1) @@ -2542,7 +2541,7 @@ def visit_confluence_doc_card(self, node): self.body.append(self._end_tag(node, suffix='')) else: self.warn('unable to build link to document card due to ' - 'missing title (in {}): {}'.format(self.docname, docname)) + f'missing title (in {self.docname}): {docname}') self.body.append(node.astext()) if not self.v2: @@ -2567,7 +2566,7 @@ def visit_confluence_doc_card_inline(self, node): self.body.append(self._end_ac_link(node)) else: self.warn('unable to build link to document card due to ' - 'missing title (in {}): {}'.format(self.docname, docname)) + f'missing title (in {self.docname}): {docname}') self.body.append(node.astext()) raise nodes.SkipNode @@ -3038,7 +3037,8 @@ def visit_line_block(self, node): style += f'margin-left: {indent}px;' elif self.v2: # (see "visit_paragraph") - style += 'margin-left: {}px;'.format(INDENT * self._indent_level) + offset = INDENT * self._indent_level + style += f'margin-left: {offset}px;' if style: attribs['style'] = style @@ -3163,7 +3163,8 @@ def _start_tag(self, node, tag, suffix=None, empty=False, **kwargs): except AttributeError: node.__confluence_tag = [tag] - return '<{}{}'.format(' '.join(data), suffix) + prefix = ' '.join(data) + return f'<{prefix}{suffix}' def _end_tag(self, node, suffix=None): """ diff --git a/sphinxcontrib/confluencebuilder/transmute/__init__.py b/sphinxcontrib/confluencebuilder/transmute/__init__.py index 018d6c1c..eed60183 100644 --- a/sphinxcontrib/confluencebuilder/transmute/__init__.py +++ b/sphinxcontrib/confluencebuilder/transmute/__init__.py @@ -147,9 +147,8 @@ def __init__(self, builder): if 'ids' in new_node: math_image_ids.extend(new_node['ids']) - except imgmath.MathExtError as exc: - ConfluenceLogger.warn('inline latex {}: {}'.format( - node.astext(), exc)) + except imgmath.MathExtError as ex: + ConfluenceLogger.warn(f'inline latex {node.astext()}: {ex}') # v2 editor will manually inject anchors in an image-managed # section to avoid a newline spacing between the anchor and @@ -215,8 +214,9 @@ def __init__(self, builder): mock_translator = MockTranslator(builder) for node in findall(doctree, graphviz): + node_code = node['code'] try: - _, out_filename = render_dot(mock_translator, node['code'], + _, out_filename = render_dot(mock_translator, node_code, node['options'], builder.graphviz_output_format, 'graphviz') if not out_filename: node.parent.remove(node) @@ -226,8 +226,8 @@ def __init__(self, builder): if 'align' in node: new_node['align'] = node['align'] node.replace_self(new_node) - except GraphvizError as exc: - ConfluenceLogger.warn('dot code {}: {}'.format(node['code'], exc)) + except GraphvizError as ex: + ConfluenceLogger.warn(f'dot code {node_code}: {ex}') node.parent.remove(node) diff --git a/tests/__main__.py b/tests/__main__.py index f75136a4..591ffeab 100644 --- a/tests/__main__.py +++ b/tests/__main__.py @@ -71,14 +71,14 @@ def main(): target_unit_test_name_pattern) if not target_unit_tests: print('\nERROR: unable to find test with pattern: ' - '{}\n'.format(target_unit_test_name_pattern)) + f'{target_unit_test_name_pattern}\n') if issued: issued[0].debug() sys.exit(1) + total_tests = len(target_unit_tests) print('') - print('running specific test(s) (total: {})'.format( - len(target_unit_tests))) + print(f'running specific test(s) (total: {total_tests})') for target_unit_test in target_unit_tests: print(f' {target_unit_test.id()}') print('') diff --git a/tests/lib/__init__.py b/tests/lib/__init__.py index f6d75605..0d064e89 100644 --- a/tests/lib/__init__.py +++ b/tests/lib/__init__.py @@ -74,16 +74,16 @@ def check_unhandled_requests(self): with self.mtx: if self.del_req or self.get_req or self.put_req: - raise Exception('''unhandled requests detected + raise Exception(f'''unhandled requests detected (get requests) -{} +{self.get_req} (put requests) -{} +{self.put_req} (del requests) -{}'''.format(self.get_req, self.put_req, self.del_req)) +{self.del_req}''') def pop_delete_request(self): """ diff --git a/tests/test_validation.py b/tests/test_validation.py index bb562e3f..8655be60 100644 --- a/tests/test_validation.py +++ b/tests/test_validation.py @@ -88,10 +88,10 @@ def setUpClass(cls): cls.config['confluence_publish_postfix'] = '' cls.config['confluence_cleanup_archive'] = False cls.config['confluence_sourcelink']['version'] = cls.test_version - cls.config['rst_epilog'] = """ -.. |test_key| replace:: {} -.. |test_desc| replace:: {} -""".format(cls.test_key, cls.test_desc) + cls.config['rst_epilog'] = f''' +.. |test_key| replace:: {cls.test_key} +.. |test_desc| replace:: {cls.test_desc} +''' # find validate-sets base folder test_dir = Path(__file__).parent.resolve() diff --git a/tests/unit-tests/test_config_postfix_formatting.py b/tests/unit-tests/test_config_postfix_formatting.py index 997a489b..a83dbee7 100644 --- a/tests/unit-tests/test_config_postfix_formatting.py +++ b/tests/unit-tests/test_config_postfix_formatting.py @@ -88,8 +88,7 @@ def test_placeholder_with_format_type(self): postfix = ConfluenceState._format_postfix( postfix=confluence_publish_prefix, docname=test_docname, config=config) - self.assertEqual(postfix, '- ({hash})'.format( - hash=self.test_hash[0:10])) + self.assertEqual(postfix, f'- ({self.test_hash[0:10]})') class TestRegisterTitle(ConfluenceTestCase): diff --git a/tests/unit-tests/test_sphinx_image_candidate.py b/tests/unit-tests/test_sphinx_image_candidate.py index 356d19f4..d1986620 100644 --- a/tests/unit-tests/test_sphinx_image_candidate.py +++ b/tests/unit-tests/test_sphinx_image_candidate.py @@ -26,8 +26,7 @@ def test_storage_sphinx_image_candidate(self): self.assertIsNotNone(ext) - pyver = 'py{}{}'.format(sys.version_info.major, - sys.version_info.minor) + pyver = f'py{sys.version_info.major}{sys.version_info.minor}' doc_dir = prepare_dirs(postfix=f'-{pyver}-docs-{ext[1:]}') out_dir = prepare_dirs(postfix=f'-{pyver}-out-{ext[1:]}')