From 37a377b9532e19633c57878e3ca32908e8553774 Mon Sep 17 00:00:00 2001 From: UlrichB22 <97119703+UlrichB22@users.noreply.github.com> Date: Tue, 12 Mar 2024 18:05:37 +0100 Subject: [PATCH] Use f-strings for logging messages and more. --- src/moin/apps/feed/views.py | 14 ++-- src/moin/apps/frontend/views.py | 12 +-- src/moin/auth/__init__.py | 28 +++---- src/moin/auth/http.py | 13 ++-- src/moin/auth/ldap_login.py | 39 +++++----- src/moin/auth/log.py | 2 +- src/moin/auth/smb_mount.py | 2 +- src/moin/cli/maint/index.py | 4 +- src/moin/cli/maint/modify_item.py | 10 +-- src/moin/cli/migration/moin19/_logfile19.py | 27 ++++--- src/moin/cli/migration/moin19/import19.py | 69 +++++++++--------- src/moin/converters/docbook_in.py | 2 +- src/moin/converters/docbook_out.py | 16 ++-- src/moin/converters/html_in.py | 8 +- src/moin/converters/macro.py | 8 +- src/moin/converters/markdown_in.py | 6 +- src/moin/converters/moinwiki_out.py | 81 ++++++++++----------- src/moin/converters/opendocument_in.py | 2 +- src/moin/i18n/__init__.py | 12 +-- src/moin/items/__init__.py | 44 +++++------ src/moin/items/content.py | 34 ++++----- src/moin/log.py | 11 ++- src/moin/mail/sendmail.py | 12 +-- src/moin/signalling/log.py | 4 +- src/moin/storage/middleware/indexing.py | 22 +++--- src/moin/themes/__init__.py | 27 ++++--- src/moin/utils/clock.py | 4 +- src/moin/utils/edit_locking.py | 9 +-- src/moin/utils/filesys.py | 3 +- src/moin/utils/interwiki.py | 21 +++--- src/moin/utils/subscriptions.py | 13 ++-- 31 files changed, 272 insertions(+), 287 deletions(-) diff --git a/src/moin/apps/feed/views.py b/src/moin/apps/feed/views.py index 3c2fb7ebe..c65e1dca0 100644 --- a/src/moin/apps/feed/views.py +++ b/src/moin/apps/feed/views.py @@ -57,9 +57,9 @@ def atom(item_name): cid = None if content is None: if not item_name: - title = "{0}".format(app.cfg.sitename) + title = f"{app.cfg.sitename}" else: - title = "{0} - {1}".format(app.cfg.sitename, fqname) + title = f"{app.cfg.sitename} - {fqname}" feed = FeedGenerator() feed.id(request.url) feed.title(title) @@ -88,7 +88,7 @@ def atom(item_name): content = render_template('atom.html', get='first_revision', rev=this_rev, content=Markup(hl_item.content._render_data()), revision=this_revid) except Exception: - logging.exception("content rendering crashed on item {0}".format(name)) + logging.exception(f"content rendering crashed on item {name}") content = _('MoinMoin feels unhappy.') author = get_editor_info(rev.meta, external=True) rev_comment = rev.meta.get(COMMENT, '') @@ -97,12 +97,12 @@ def atom(item_name): if len(rev_comment) > 80: content = render_template('atom.html', get='comment_cont_merge', comment=rev_comment[79:], content=Markup(content)) - rev_comment = "{0}...".format(rev_comment[:79]) - feed_title = "{0} - {1}".format(author.get(NAME, ''), rev_comment) + rev_comment = f"{rev_comment[:79]}..." + feed_title = f"{author.get(NAME, '')} - {rev_comment}" else: - feed_title = "{0}".format(author.get(NAME, '')) + feed_title = f"{author.get(NAME, '')}" if not item_name: - feed_title = "{0} - {1}".format(name, feed_title) + feed_title = f"{name} - {feed_title}" feed_entry = feed.add_entry() feed_entry.id(url_for_item(name, rev=this_revid, _external=True)) feed_entry.title(feed_title) diff --git a/src/moin/apps/frontend/views.py b/src/moin/apps/frontend/views.py index ea8d6b9bb..1bdac145d 100644 --- a/src/moin/apps/frontend/views.py +++ b/src/moin/apps/frontend/views.py @@ -509,8 +509,8 @@ def add_presenter(wrapped, view, add_trail=False, abort404=True): :param add_trail: whether to call flaskg.user.add_trail :param abort404: whether to abort(404) for nonexistent items """ - @frontend.route('/+{view}/+/'.format(view=view)) - @frontend.route('/+{view}/'.format(view=view), defaults=dict(rev=CURRENT)) + @frontend.route(f'/+{view}/+/') + @frontend.route(f'/+{view}/', defaults=dict(rev=CURRENT)) @wraps(wrapped) def wrapper(item_name, rev): if add_trail: @@ -1142,7 +1142,7 @@ def log_destroy_action(item, subitem_names, comment, revision=None): elif subitem_names: destroy_info[0] = ('An item and all item subitems have been destroyed', '') for name, val in destroy_info: - logging.info('{0}: {1}'.format(name, val)) + logging.info(f'{name}: {val}') @frontend.route('/+destroy/+/', methods=['GET', 'POST']) @@ -2577,7 +2577,7 @@ def _common_type(ct1, ct2): def _crash(item, oldrev, newrev): """This is called from several places, need to handle passed message""" error_id = uuid.uuid4() - logging.exception("An exception happened in _render_data (error_id = %s ):" % error_id) + logging.exception(f"An exception happened in _render_data (error_id = {error_id} ):") return render_template("crash_view.html", server_time=time.strftime("%Y-%m-%d %H:%M:%S %Z"), url=request.url, @@ -2795,7 +2795,7 @@ def global_tags(namespace): tags_counts = {} for meta in metas: tags = meta.get(TAGS, []) - logging.debug("name {0!r} rev {1} tags {2!r}".format(meta[NAME], meta[REVID], tags)) + logging.debug(f"name {meta[NAME]!r} rev {meta[REVID]} tags {tags!r}") for tag in tags: tags_counts[tag] = tags_counts.setdefault(tag, 0) + 1 tags_counts = sorted(tags_counts.items()) @@ -2813,7 +2813,7 @@ def global_tags(namespace): def cls(count): # return the css class for this tag weight = scale * (count - count_min) - return "weight{0}".format(int(weight)) # weight0, ..., weight9 + return f"weight{int(weight)}" # weight0, ..., weight9 tags = [(cls(count), tag) for tag, count in tags_counts] else: tags = [] diff --git a/src/moin/auth/__init__.py b/src/moin/auth/__init__.py index 4bd7868b2..8699c25f1 100644 --- a/src/moin/auth/__init__.py +++ b/src/moin/auth/__init__.py @@ -166,7 +166,7 @@ def get_multistage_continuation_url(auth_name, extra_fields={}): # the url should be absolute so we use _external url = url_for('frontend.login', login_submit='1', stage=auth_name, _external=True, **extra_fields) - logging.debug("multistage_continuation_url: {0}".format(url)) + logging.debug(f"multistage_continuation_url: {url}") return url @@ -216,7 +216,7 @@ class BaseAuth: def __init__(self, trusted=False, **kw): self.trusted = trusted if kw: - raise TypeError("got unexpected arguments %r" % kw) + raise TypeError(f"got unexpected arguments {kw!r}") def login(self, user_obj, **kw): return ContinueLogin(user_obj) @@ -226,7 +226,7 @@ def request(self, user_obj, **kw): def logout(self, user_obj, **kw): if self.name and user_obj and user_obj.auth_method == self.name: - logging.debug("{0}: logout - invalidating user {1!r}".format(self.name, user_obj.name)) + logging.debug(f"{self.name}: logout - invalidating user {user_obj.name!r}") user_obj.valid = False return user_obj, True @@ -254,17 +254,17 @@ def login(self, user_obj, **kw): if not username and not password: return ContinueLogin(user_obj) - logging.debug("{0}: performing login action".format(self.name)) + logging.debug(f"{self.name}: performing login action") if username and not password: return ContinueLogin(user_obj, _('Missing password. Please enter user name and password.')) u = user.User(name=username, password=password, auth_method=self.name, trusted=self.trusted) if u.valid: - logging.debug("{0}: successfully authenticated user {1!r} (valid)".format(self.name, u.name)) + logging.debug(f"{self.name}: successfully authenticated user {u.name!r} (valid)") return ContinueLogin(u) else: - logging.debug("{0}: could not authenticate user {1!r} (not valid)".format(self.name, username)) + logging.debug(f"{self.name}: could not authenticate user {username!r} (not valid)") return ContinueLogin(user_obj, _("Invalid username or password.")) def login_hint(self): @@ -356,23 +356,23 @@ def request(self, user_obj, **kw): else: auth_username = request.environ.get(self.env_var) - logging.debug("auth_username = {0!r}".format(auth_username)) + logging.debug(f"auth_username = {auth_username!r}") if auth_username: auth_username = self.decode_username(auth_username) auth_username = self.transform_username(auth_username) - logging.debug("auth_username (after decode/transform) = {0!r}".format(auth_username)) + logging.debug(f"auth_username (after decode/transform) = {auth_username!r}") u = user.User(auth_username=auth_username, auth_method=self.name, auth_attribs=('name', 'password'), trusted=self.trusted) - logging.debug("u: {0!r}".format(u)) + logging.debug(f"u: {u!r}") if u and self.autocreate: logging.debug("autocreating user") u.create_or_update() if u and u.valid: - logging.debug("returning valid user {0!r}".format(u)) + logging.debug(f"returning valid user {u!r}") return u, True # True to get other methods called, too else: - logging.debug("returning {0!r}".format(user_obj)) + logging.debug(f"returning {user_obj!r}") return user_obj, True @@ -455,8 +455,8 @@ def setup_from_session(): auth_method = session['user.auth_method'] auth_attribs = session['user.auth_attribs'] session_token = session['user.session_token'] - logging.debug("got from session: {0!r} {1!r} {2!r} {3!r}".format(itemid, trusted, auth_method, auth_attribs)) - logging.debug("current auth methods: {0!r}".format(app.cfg.auth_methods)) + logging.debug(f"got from session: {itemid!r} {trusted!r} {auth_method!r} {auth_attribs!r}") + logging.debug(f"current auth methods: {app.cfg.auth_methods!r}") if auth_method and auth_method in app.cfg.auth_methods: userobj = user.User(itemid, auth_method=auth_method, @@ -468,5 +468,5 @@ def setup_from_session(): userobj.logout_session(False) # We didn't find user in session data. userobj = None - logging.debug("session started for user {0!r}".format(userobj)) + logging.debug(f"session started for user {userobj!r}") return userobj diff --git a/src/moin/auth/http.py b/src/moin/auth/http.py index da2d3a2de..3d7dd40c4 100644 --- a/src/moin/auth/http.py +++ b/src/moin/auth/http.py @@ -48,26 +48,25 @@ def request(self, user_obj, **kw): auth = request.authorization if auth and auth.username and auth.password is not None: - logging.debug("http basic auth, received username: {0!r} password: {1!r}".format( - auth.username, auth.password)) + logging.debug(f"http basic auth, received username: {auth.username!r} password: {auth.password!r}") u = user.User(name=auth.username, password=auth.password, auth_method=self.name, auth_attribs=[], trusted=self.trusted) - logging.debug("user: {0!r}".format(u)) + logging.debug(f"user: {u!r}") if not u or not u.valid: from werkzeug import Response from werkzeug.exceptions import abort response = Response(_('Please log in first.'), 401, - {'WWW-Authenticate': 'Basic realm="{0}"'.format(self.realm)}) + {'WWW-Authenticate': f'Basic realm="{self.realm}"'}) abort(response) - logging.debug("u: {0!r}".format(u)) + logging.debug(f"u: {u!r}") if u and self.autocreate: logging.debug("autocreating user") u.create_or_update() if u and u.valid: - logging.debug("returning valid user {0!r}".format(u)) + logging.debug(f"returning valid user {u!r}") return u, True # True to get other methods called, too else: - logging.debug("returning {0!r}".format(user_obj)) + logging.debug(f"returning {user_obj!r}") return user_obj, True diff --git a/src/moin/auth/ldap_login.py b/src/moin/auth/ldap_login.py index 92c6fa8b0..023360ff4 100644 --- a/src/moin/auth/ldap_login.py +++ b/src/moin/auth/ldap_login.py @@ -29,7 +29,7 @@ try: import ldap except ImportError as err: - logging.error("You need to have python-ldap installed ({0!s}).".format(err)) + logging.error(f"You need to have python-ldap installed ({err!s}).") raise @@ -157,28 +157,28 @@ def login(self, user_obj, **kw): if value is not None: ldap.set_option(option, value) - logging.debug("Trying to initialize {0!r}.".format(server)) + logging.debug(f"Trying to initialize {server!r}.") conn = ldap.initialize(server) - logging.debug("Connected to LDAP server {0!r}.".format(server)) + logging.debug(f"Connected to LDAP server {server!r}.") if self.start_tls and server.startswith('ldap:'): - logging.debug("Trying to start TLS to {0!r}.".format(server)) + logging.debug(f"Trying to start TLS to {server!r}.") try: conn.start_tls_s() - logging.debug("Using TLS to {0!r}.".format(server)) + logging.debug(f"Using TLS to {server!r}.") except (ldap.SERVER_DOWN, ldap.CONNECT_ERROR) as err: - logging.warning("Couldn't establish TLS to {0!r} (err: {1!s}).".format(server, err)) + logging.warning(f"Couldn't establish TLS to {server!r} (err: {err!s}).") raise # you can use %(username)s and %(password)s here to get the stuff entered in the form: binddn = self.bind_dn % locals() bindpw = self.bind_pw % locals() conn.simple_bind_s(binddn, bindpw) - logging.debug("Bound with binddn {0!r}".format(binddn)) + logging.debug(f"Bound with binddn {binddn!r}") # you can use %(username)s here to get the stuff entered in the form: filterstr = self.search_filter % locals() - logging.debug("Searching {0!r}".format(filterstr)) + logging.debug(f"Searching {filterstr!r}") attrs = [getattr(self, attr) for attr in [ 'email_attribute', 'displayname_attribute', @@ -190,17 +190,16 @@ def login(self, user_obj, **kw): # we remove entries with dn == None to get the real result list: lusers = [(_dn, _ldap_dict) for _dn, _ldap_dict in lusers if _dn is not None] for _dn, _ldap_dict in lusers: - logging.debug("dn:{0!r}".format(_dn)) + logging.debug(f"dn:{_dn!r}") for key, val in _ldap_dict.items(): - logging.debug(" {0!r}: {1!r}".format(key, val)) + logging.debug(f" {key!r}: {val!r}") result_length = len(lusers) if result_length != 1: if result_length > 1: - logging.warning("Search found more than one ({0}) matches for {1!r}.".format( - result_length, filterstr)) + logging.warning(f"Search found more than one ({result_length}) matches for {filterstr!r}.") if result_length == 0: - logging.debug("Search found no matches for {0!r}.".format(filterstr, )) + logging.debug(f"Search found no matches for {filterstr!r}.") if self.report_invalid_credentials: return ContinueLogin(user_obj, _("Invalid username or password.")) else: @@ -208,9 +207,9 @@ def login(self, user_obj, **kw): dn, ldap_dict = lusers[0] if not self.bind_once: - logging.debug("DN found is {0!r}, trying to bind with pw".format(dn)) + logging.debug(f"DN found is {dn!r}, trying to bind with pw") conn.simple_bind_s(dn, password) - logging.debug("Bound with dn {0!r} (username: {1!r})".format(dn, username)) + logging.debug(f"Bound with dn {dn!r} (username: {username!r})") if self.email_callback is None: if self.email_attribute: @@ -229,7 +228,7 @@ def login(self, user_obj, **kw): sn = ldap_dict.get(self.surname_attribute, [''])[0] gn = ldap_dict.get(self.givenname_attribute, [''])[0] if sn and gn: - display_name = "{0}, {1}".format(sn, gn) + display_name = f"{sn}, {gn}" elif sn: display_name = sn @@ -251,12 +250,11 @@ def login(self, user_obj, **kw): username, email, display_name)) except ldap.INVALID_CREDENTIALS: - logging.debug("invalid credentials (wrong password?) for dn {0!r} (username: {1!r})".format( - dn, username)) + logging.debug(f"invalid credentials (wrong password?) for dn {dn!r} (username: {username!r})") return CancelLogin(_("Invalid username or password.")) if u and self.autocreate: - logging.debug("calling create_or_update to autocreate user {0!r}".format(u.name)) + logging.debug(f"calling create_or_update to autocreate user {u.name!r}") u.create_or_update(True) return ContinueLogin(u) @@ -265,8 +263,7 @@ def login(self, user_obj, **kw): # authenticator object in cfg.auth list (there could be some second # ldap authenticator that queries a backup server or any other auth # method). - logging.error("LDAP server {0} failed ({1!s}). " - "Trying to authenticate with next auth list entry.".format(server, err)) + logging.error(f"LDAP server {server} failed ({err!s}). Trying to authenticate with next auth list entry.") return ContinueLogin(user_obj, _("LDAP server {server} failed.").format(server=server)) except: # noqa diff --git a/src/moin/auth/log.py b/src/moin/auth/log.py index 855e7d3ef..60aaee9d1 100644 --- a/src/moin/auth/log.py +++ b/src/moin/auth/log.py @@ -23,7 +23,7 @@ def __init__(self, **kw): super(AuthLog, self).__init__(**kw) def log(self, action, user_obj, kw): - logging.info('{0}: user_obj={1!r} kw={2!r}'.format(action, user_obj, kw)) + logging.info(f'{action}: user_obj={user_obj!r} kw={kw!r}') def login(self, user_obj, **kw): self.log('login', user_obj, kw) diff --git a/src/moin/auth/smb_mount.py b/src/moin/auth/smb_mount.py index 34125caa2..8a6277c21 100644 --- a/src/moin/auth/smb_mount.py +++ b/src/moin/auth/smb_mount.py @@ -51,7 +51,7 @@ def __init__( self.coding = coding def do_smb(self, username, password, login): - logging.debug("login={0} logout={1}: got name={2!r}".format(login, not login, username)) + logging.debug(f"login={login} logout={not login}: got name={username!r}") import os import pwd diff --git a/src/moin/cli/maint/index.py b/src/moin/cli/maint/index.py index 776265afb..ae463b77b 100644 --- a/src/moin/cli/maint/index.py +++ b/src/moin/cli/maint/index.py @@ -78,7 +78,7 @@ def IndexDestroy(tmp): @click.option('--storage-create', '-s', is_flag=True, required=False, default=False) def IndexBuild(tmp, procs, limitmb, **kwargs): if not wiki_index_exists(): - logging.error("{} Run 'moin index-create' first.".format(ERR_NO_INDEX)) + logging.error(f"{ERR_NO_INDEX} Run 'moin index-create' first.") raise SystemExit(1) logging.info("Index build started") flaskg.add_lineno_attr = False # no need to add lineno attributes while building indexes @@ -131,7 +131,7 @@ def IndexDump(tmp, truncate): raise SystemExit(1) logging.info("Index dump started") for idx_name in [LATEST_REVS, ALL_REVS]: - print(" {0} {1} {2}".format("-" * 10, idx_name, "-" * 60)) + print(f" {'-' * 10} {idx_name} {'-' * 60}") for kvs in app.storage.dump(tmp=tmp, idx_name=idx_name): for k, v in kvs: v = repr(v) diff --git a/src/moin/cli/maint/modify_item.py b/src/moin/cli/maint/modify_item.py index 5ee8f4618..01d621b16 100644 --- a/src/moin/cli/maint/modify_item.py +++ b/src/moin/cli/maint/modify_item.py @@ -126,7 +126,7 @@ def PutItem(meta_file, data_file, overwrite): meta.pop(REVID, None) meta.pop(DATAID, None) query = {ITEMID: meta[ITEMID], NAMESPACE: meta[NAMESPACE]} - logging.debug("query: {}".format(str(query))) + logging.debug(f"query: {str(query)}") item = app.storage.get_item(**query) # we want \r\n line endings in data out because \r\n is required in form textareas @@ -168,11 +168,11 @@ def LoadHelp(namespace, path_to_help): path_to_help = _get_path_to_help() path_to_items = os.path.normpath(os.path.join(path_to_help, namespace)) if not os.path.isdir(path_to_items): - print('Abort: the {0} directory does not exist'.format(path_to_items)) + print(f'Abort: the {path_to_items} directory does not exist') return file_list = os.listdir(path_to_items) if len(file_list) == 0: - print('Abort: the {0} directory is empty'.format(path_to_items)) + print(f'Abort: the {path_to_items} directory is empty') return count = 0 for f in file_list: @@ -185,7 +185,7 @@ def LoadHelp(namespace, path_to_help): PutItem(meta_file, data_file, "true") print('Item loaded:', item_name) count += 1 - print('Success: help namespace {0} loaded successfully with {1} items'.format(namespace, count)) + print(f'Success: help namespace {namespace} loaded successfully with {count} items') @cli.command('dump-help', help='Dump a namespace of user help items to .data and .meta file pairs') @@ -222,7 +222,7 @@ def DumpHelp(namespace, path_to_help, crlf): no_alias_dups += alias_names print('Item dumped::', file_.relname) count += 1 - print('Success: help namespace {0} saved with {1} items'.format(namespace, count)) + print(f'Success: help namespace {namespace} saved with {count} items') @cli.command('maint-validate-metadata', help='Find and optionally fix issues with item metadata') diff --git a/src/moin/cli/migration/moin19/_logfile19.py b/src/moin/cli/migration/moin19/_logfile19.py index c779fbe0d..3ab482fd1 100644 --- a/src/moin/cli/migration/moin19/_logfile19.py +++ b/src/moin/cli/migration/moin19/_logfile19.py @@ -49,7 +49,7 @@ def __init__(self, file, offset, size, forward=True): self.loglevel = logging.NOTSET if forward: begin = offset - logging.log(self.loglevel, "LineBuffer.init: forward seek {0} read {1}".format(begin, size)) + logging.log(self.loglevel, f"LineBuffer.init: forward seek {begin} read {size}") file.seek(begin) lines = file.readlines(size) else: @@ -58,7 +58,7 @@ def __init__(self, file, offset, size, forward=True): size = offset else: begin = offset - size - logging.log(self.loglevel, "LineBuffer.init: backward seek {0} read {1}".format(begin, size)) + logging.log(self.loglevel, f"LineBuffer.init: backward seek {begin} read {size}") file.seek(begin) lines = file.read(size).splitlines(True) if begin != 0: @@ -119,7 +119,7 @@ def reverse(self): self.to_end() while True: try: - logging.log(self.loglevel, "LogFile.reverse {0}".format(self.__filename)) + logging.log(self.loglevel, f"LogFile.reverse {self.__filename}") result = self.previous() except StopIteration: return @@ -131,7 +131,7 @@ def sanityCheck(self): :rtype: string (error message) or None """ if not os.access(self.__filename, os.W_OK): - return "The log '{0}' is not writable!".format(self.__filename) + return f"The log '{self.__filename}' is not writable!" return None def __getattr__(self, name): @@ -162,8 +162,7 @@ def __getattr__(self, name): f.close() self._input = open(self.__filename, "rb", ) else: - logging.error("logfile: {0!r} IOERROR errno {1} ({2})".format(self.__filename, - err.errno, os.strerror(err.errno))) + logging.error(f"logfile: {self.__filename!r} IOERROR errno {err.errno} ({os.strerror(err.errno)})") raise return self._input elif name == "_output": @@ -222,7 +221,7 @@ def peek(self, lines): :returns: True if moving more than to the beginning and moving to the end or beyond """ - logging.log(self.loglevel, "LogFile.peek {0}".format(self.__filename)) + logging.log(self.loglevel, f"LogFile.peek {self.__filename}") self.__rel_index += lines while self.__rel_index < 0: if self.__buffer is self.__buffer2: @@ -293,7 +292,7 @@ def next(self): result = None while result is None: while result is None: - logging.log(self.loglevel, "LogFile.next {0}".format(self.__filename)) + logging.log(self.loglevel, f"LogFile.next {self.__filename}") result = self.__next() if self.filter and not self.filter(result): result = None @@ -315,7 +314,7 @@ def previous(self): result = None while result is None: while result is None: - logging.log(self.loglevel, "LogFile.previous {0}".format(self.__filename)) + logging.log(self.loglevel, f"LogFile.previous {self.__filename}") result = self.__previous() if self.filter and not self.filter(result): result = None @@ -323,7 +322,7 @@ def previous(self): def to_begin(self): """moves file position to the begin""" - logging.log(self.loglevel, "LogFile.to_begin {0}".format(self.__filename)) + logging.log(self.loglevel, f"LogFile.to_begin {self.__filename}") if self.__buffer1 is None or self.__buffer1.offsets[0] != 0: self.__buffer1 = LineBuffer(self._input, 0, @@ -337,7 +336,7 @@ def to_begin(self): def to_end(self): """moves file position to the end""" - logging.log(self.loglevel, "LogFile.to_end {0}".format(self.__filename)) + logging.log(self.loglevel, f"LogFile.to_end {self.__filename}") self._input.seek(0, 2) # to end of file size = self._input.tell() if self.__buffer2 is None or size > self.__buffer2.offsets[-1]: @@ -368,11 +367,11 @@ def seek(self, position, line_no=None): .seek is much more efficient for moving long distances than .peek. raises ValueError if position is invalid """ - logging.log(self.loglevel, "LogFile.seek {0} pos {1}".format(self.__filename, position)) + logging.log(self.loglevel, f"LogFile.seek {self.__filename} pos {position}") if self.__buffer1: - logging.log(self.loglevel, "b1 {0!r} {1!r}".format(self.__buffer1.offsets[0], self.__buffer1.offsets[-1])) + logging.log(self.loglevel, f"b1 {self.__buffer1.offsets[0]!r} {self.__buffer1.offsets[-1]!r}") if self.__buffer2: - logging.log(self.loglevel, "b2 {0!r} {1!r}".format(self.__buffer2.offsets[0], self.__buffer2.offsets[-1])) + logging.log(self.loglevel, f"b2 {self.__buffer2.offsets[0]!r} {self.__buffer2.offsets[-1]!r}") if self.__buffer1 and self.__buffer1.offsets[0] <= position < self.__buffer1.offsets[-1]: # position is in .__buffer1 self.__rel_index = self.__buffer1.offsets.index(position) diff --git a/src/moin/cli/migration/moin19/import19.py b/src/moin/cli/migration/moin19/import19.py index 1b35edb0d..c0347df27 100644 --- a/src/moin/cli/migration/moin19/import19.py +++ b/src/moin/cli/migration/moin19/import19.py @@ -99,7 +99,7 @@ def migr_logging(msg_id, log_msg): if migr_stat[msg_id] < migr_warn_max: logging.warning(log_msg) elif migr_stat[msg_id] == migr_warn_max: - logging.warning("{}: further messages printed to debug log only.".format(msg_id)) + logging.warning(f"{msg_id}: further messages printed to debug log only.") logging.debug(log_msg) else: logging.debug(log_msg) @@ -107,17 +107,17 @@ def migr_logging(msg_id, log_msg): def migr_statistics(unknown_macros): logging.info("Migration statistics:") - logging.info("Users: {0:6d}".format(migr_stat['users'])) - logging.info("Items: {0:6d}".format(migr_stat['items'])) - logging.info("Revisions: {0:6d}".format(migr_stat['revs'])) - logging.info("Attachments: {0:6d}".format(migr_stat['attachments'])) + logging.info(f"Users: {migr_stat['users']:6d}") + logging.info(f"Items: {migr_stat['items']:6d}") + logging.info(f"Revisions: {migr_stat['revs']:6d}") + logging.info(f"Attachments: {migr_stat['attachments']:6d}") for message in ['missing_user', 'missing_file', 'del_item']: if migr_stat[message] > 0: - logging.info("Warnings: {0:6d} - {1}".format(migr_stat[message], message)) + logging.info(f"Warnings: {migr_stat[message]:6d} - {message}") if len(unknown_macros) > 0: - logging.info("Warnings: {0:6d} - unknown macros {1}".format(len(unknown_macros), str(unknown_macros)[1:-1])) + logging.info(f"Warnings: {len(unknown_macros):6d} - unknown macros {str(unknown_macros)[1:-1]}") @cli.command('import19', help='Import content and user data from a moin 1.9 wiki') @@ -180,7 +180,7 @@ def ImportMoin19(data_dir=None, markup_out=None, namespace=None): refs_conv = reg.get(type_moin_document, type_moin_document, items='refs') for item_name, (revno, namespace) in sorted(last_moin19_rev.items()): try: - logging.debug('Processing item "{0}", namespace "{1}", revision "{2}"'.format(item_name, namespace, revno)) + logging.debug(f'Processing item "{item_name}", namespace "{namespace}", revision "{revno}"') except UnicodeEncodeError: logging.debug('Processing item "{0}", namespace "{1}", revision "{2}"'.format( item_name.encode('ascii', errors='replace'), namespace, revno)) @@ -303,12 +303,11 @@ def __iter__(self): pass # a message was already output except (IOError, AttributeError): migr_logging('missing_file', - "Missing file 'current' or 'edit-log' for {0}".format( - os.path.normcase(os.path.join(pages_dir, f))) + f"Missing file 'current' or 'edit-log' for {os.path.normcase(os.path.join(pages_dir, f))}" ) except Exception: - logging.exception(("PageItem {0!r} raised exception:".format(itemname))).encode('utf-8') + logging.exception(f"PageItem {itemname!r} raised exception:").encode('utf-8') else: for rev in item.iter_revisions(): yield rev @@ -327,9 +326,9 @@ def __init__(self, backend, path, itemname, target_namespace): self.target_namespace = target_namespace try: - logging.debug("Processing item {0}".format(itemname)) + logging.debug(f"Processing item {itemname}") except UnicodeEncodeError: - logging.debug("Processing item {0}".format(itemname.encode('ascii', errors='replace'))) + logging.debug(f"Processing item {itemname.encode('ascii', errors='replace')}") currentpath = os.path.join(self.path, 'current') with open(currentpath, 'r') as f: self.current = int(f.read().strip()) @@ -338,10 +337,10 @@ def __init__(self, backend, path, itemname, target_namespace): self.acl = None self.itemid = make_uuid() if backend.deleted_mode == DELETED_MODE_KILL: - revpath = os.path.join(self.path, 'revisions', '{0:08d}'.format(self.current)) + revpath = os.path.join(self.path, 'revisions', f'{self.current:08d}') if not os.path.exists(revpath): migr_logging('del_item', - 'Deleted item not migrated: {0}, last revision no: {1}'.format(itemname, self.current) + f'Deleted item not migrated: {itemname}, last revision no: {self.current}' ) raise KillRequested('deleted_mode wants killing/ignoring') else: @@ -367,7 +366,7 @@ def iter_revisions(self): yield page_rev except Exception: - logging.exception("PageRevision {0!r} {1!r} raised exception:".format(self.name, fname)) + logging.exception(f"PageRevision {self.name!r} {fname!r} raised exception:") def iter_attachments(self): attachmentspath = os.path.join(self.path, 'attachments') @@ -381,7 +380,7 @@ def iter_attachments(self): yield AttachmentRevision(self.name, attachname, os.path.join(attachmentspath, fname), self.editlog, self.acl) except Exception: - logging.exception("AttachmentRevision {0!r}/{1!r} raised exception:".format(self.name, attachname)) + logging.exception(f"AttachmentRevision {self.name!r}/{attachname!r} raised exception:") class PageRevision: @@ -406,7 +405,7 @@ def __init__(self, item, revno, path, target_namespace): # if we have an entry there } try: - revpath = os.path.join(item.path, 'revisions', '{0:08d}'.format(revno - 1)) + revpath = os.path.join(item.path, 'revisions', f'{revno - 1:08d}') previous_meta = PageRevision(item, revno - 1, revpath, target_namespace).meta # if this page revision is deleted, we have no on-page metadata. # but some metadata is required, thus we have to copy it from the @@ -421,19 +420,18 @@ def __init__(self, item, revno, path, target_namespace): try: editlog_data = editlog.find_rev(revno) except KeyError: - logging.warning('Missing edit log data: item = {0}, revision = {1}'.format(item_name, revno)) + logging.warning(f'Missing edit log data: item = {item_name}, revision = {revno}') if 0 <= revno <= item.current: editlog_data = { # make something up ACTION: 'SAVE/DELETE', } else: - raise NoSuchRevisionError('Item {0!r} has no revision {1} (not even a deleted one)!'.format( - item.name, revno)) + raise NoSuchRevisionError(f'Item {item.name!r} has no revision {revno} (not even a deleted one)!') else: try: editlog_data = editlog.find_rev(revno) except KeyError: - logging.warning('Missing edit log data: name = {0}, revision = {1}'.format(item_name, revno)) + logging.warning(f'Missing edit log data: name = {item_name}, revision = {revno}') if 1 <= revno <= item.current: editlog_data = { # make something up NAME: [item.name], @@ -476,8 +474,7 @@ def __init__(self, item, revno, path, target_namespace): if meta[NAME][0] == custom_namespace: # cannot have itemname == namespace_name, so we rename. XXX may create an item with duplicate name new_name = app.cfg.root_mapping.get(meta[NAME][0], app.cfg.default_root) - logging.warning("Converting {0} to namespace:homepage {1}:{2}".format( - meta[NAME][0], custom_namespace, new_name)) + logging.warning(f"Converting {meta[NAME][0]} to namespace:homepage {custom_namespace}:{new_name}") meta[NAMESPACE] = custom_namespace meta[NAME] = [new_name] break @@ -584,8 +581,8 @@ def migrate_itemlinks(dom, namespace, itemlinks2chg): if node.tag.name == 'a' and not isinstance(node.attrib[xlink.href], str): path_19 = str(node.attrib[xlink.href].path) if node.attrib[xlink.href].scheme == 'wiki.local' and path_19 in itemlinks2chg: - logging.debug("Changing link from {} to {}/{}".format(path_19, namespace, path_19)) - node.attrib[xlink.href].path = '{}/{}'.format(namespace, path_19) + logging.debug(f"Changing link from {path_19} to {namespace}/{path_19}") + node.attrib[xlink.href].path = f'{namespace}/{path_19}' def process_categories(meta, data, item_category_regex): @@ -631,8 +628,8 @@ def __init__(self, item_name, attach_name, attpath, editlog, acl): ACTION: ACTION_SAVE, } migr_stat['attachments'] += 1 - meta[NAME] = ['{0}/{1}'.format(item_name, attach_name)] - logging.debug('Migrating attachment {0}'.format(meta[NAME])) + meta[NAME] = [f'{item_name}/{attach_name}'] + logging.debug(f'Migrating attachment {meta[NAME]}') if acl is not None: meta[ACL] = acl meta[CONTENTTYPE] = str(MimeType(filename=attach_name).content_type()) @@ -747,7 +744,7 @@ def regenerate_acl(acl_string, acl_rights_valid=ACL_RIGHTS_CONTENTS): )) result = ' '.join(result) if result != acl_string: - logging.debug("regenerate_acl {0!r} -> {1!r}".format(acl_string, result)) + logging.debug(f"regenerate_acl {acl_string!r} -> {result!r}") return result @@ -843,7 +840,7 @@ def _process_usermeta(self, metadata): # rename aliasname to display_name: metadata[DISPLAY_NAME] = metadata.get('aliasname') - logging.debug("Processing user {0} {1} {2}".format(metadata[NAME][0], self.uid, metadata[EMAIL])) + logging.debug(f"Processing user {metadata[NAME][0]} {self.uid} {metadata[EMAIL]}") migr_stat['users'] += 1 # transfer subscribed_pages to subscription_patterns @@ -924,22 +921,22 @@ def migrate_subscriptions(self, subscribed_items): RECHARS = r'.^$*+?{\|(' subscriptions = [] for subscribed_item in subscribed_items: - logging.debug('User is subscribed to {0}'.format(subscribed_item)) + logging.debug(f'User is subscribed to {subscribed_item}') if flaskg.item_name2id.get(subscribed_item): - subscriptions.append("{0}:{1}".format(ITEMID, flaskg.item_name2id.get(subscribed_item))) + subscriptions.append(f"{ITEMID}:{flaskg.item_name2id.get(subscribed_item)}") else: wikiname = "" if ":" in subscribed_item: wikiname, subscribed_item = subscribed_item.split(":", 1) if not any(x in subscribed_item for x in RECHARS): - subscriptions.append("{0}:{1}:{2}".format(NAME, wikiname, subscribed_item)) + subscriptions.append(f"{NAME}:{wikiname}:{subscribed_item}") elif (subscribed_item.endswith(".*") and len(subscribed_item) > 2 and not subscribed_item.endswith("/.*") and not any(x in subscribed_item[:-2] for x in RECHARS)): - subscriptions.append("{0}:{1}:{2}".format(NAMEPREFIX, wikiname, subscribed_item[:-2])) + subscriptions.append(f"{NAMEPREFIX}:{wikiname}:{subscribed_item[:-2]}") else: - subscriptions.append("{0}:{1}:{2}".format(NAMERE, wikiname, subscribed_item)) + subscriptions.append(f"{NAMERE}:{wikiname}:{subscribed_item}") return subscriptions @@ -961,7 +958,7 @@ def __iter__(self): try: rev = UserRevision(self.path, uid) except Exception: - logging.exception("Exception in user item processing {0}".format(uid)) + logging.exception(f"Exception in user item processing {uid}") else: yield rev diff --git a/src/moin/converters/docbook_in.py b/src/moin/converters/docbook_in.py index 94499be0f..a157ab180 100644 --- a/src/moin/converters/docbook_in.py +++ b/src/moin/converters/docbook_in.py @@ -384,7 +384,7 @@ def visit_docbook(self, element, depth): # We should ignore this element if element.tag.name in self.ignored_tags: - logging.warning("Ignored tag:{0}".format(element.tag.name)) + logging.warning(f"Ignored tag:{element.tag.name}") return # We have an admonition element diff --git a/src/moin/converters/docbook_out.py b/src/moin/converters/docbook_out.py index 0dd6d7dd4..cd6e0046a 100644 --- a/src/moin/converters/docbook_out.py +++ b/src/moin/converters/docbook_out.py @@ -159,7 +159,7 @@ def visit_moinpage(self, element): # Check that the tag is supported if element.tag.name in self.unsupported_tags: - logging.warning("Unsupported tag : {0}".format(element.tag.name)) + logging.warning(f"Unsupported tag : {element.tag.name}") return self.do_children(element) method_name = 'visit_moinpage_' + element.tag.name.replace('-', '_') @@ -168,7 +168,7 @@ def visit_moinpage(self, element): return method(element) # Otherwise we process the children of the unknown element - logging.warning("Unknown tag : {0}".format(element.tag.name)) + logging.warning(f"Unknown tag : {element.tag.name}") return self.do_children(element) def visit_moinpage_a(self, element): @@ -273,7 +273,7 @@ def visit_moinpage_h(self, element): # Need more test elif depth < self.current_section: if self.parent_section != 0: - section_tag = 'sect{0}'.format(self.parent_section) + section_tag = f'sect{self.parent_section}' section = ET.Element(docbook(section_tag), attrib={}, children=self.section_children[self.current_section]) self.section_children[self.parent_section].append(section) @@ -403,7 +403,7 @@ def visit_moinpage_table(self, element): title = element.get(html('title')) if not title: # TODO: Translation - title = "Table {0}".format(self.table_counter) + title = f"Table {self.table_counter}" self.table_counter += 1 caption = ET.Element(docbook('caption'), attrib={}, children=[title]) children = [caption] @@ -418,7 +418,7 @@ def visit_moinpage_table_cell(self, element): attrib = {} rowspan = element.get(moin_page('number-rows-spanned')) colspan = element.get(moin_page('number-columns-spanned')) - print("rowspan : {0}".format(rowspan)) + print(f"rowspan : {rowspan}") if rowspan: attrib[docbook.rowspan] = rowspan if colspan: @@ -466,12 +466,12 @@ def visit_moinpage_page(self, element): section = None for k, v in self.section_children: if section: - section_tag = 'sect{0}'.format(k) + section_tag = f'sect{k}' v.append(section) section = ET.Element(docbook(section_tag), attrib={}, children=v) else: - section_tag = 'sect{0}'.format(k) + section_tag = f'sect{k}' section = ET.Element(docbook(section_tag), attrib={}, children=v) return ET.Element(docbook.article, @@ -480,7 +480,7 @@ def visit_moinpage_page(self, element): c.insert(0, info) return ET.Element(docbook.article, attrib={}, children=c) - raise RuntimeError('page:page need to contain exactly one page body tag, got {0!r}'.format(element[:])) + raise RuntimeError(f'page:page need to contain exactly one page body tag, got {element[:]!r}') def visit_moinpage_p(self, element): """ diff --git a/src/moin/converters/html_in.py b/src/moin/converters/html_in.py index 5503ab040..228f93f63 100644 --- a/src/moin/converters/html_in.py +++ b/src/moin/converters/html_in.py @@ -127,13 +127,13 @@ def __call__(self, data, contenttype=None, arguments=None): except AssertionError as reason: # we suspect user has created or uploaded malformed HTML, try to show input as preformatted code msg = _('Error: malformed HTML: {reason}.').format(reason=reason) - msg = '

%s

' % msg + msg = f'

{msg}

' html_str = ''.join(['', msg, '
', html_str, '
']) try: html_tree = HTML(html_str) except ValueError: msg = _('Error: malformed HTML. Try viewing source with Highlight or Modify links.') - msg = '

%s

' % msg + msg = f'

{msg}

' html_str = ''.join(['', msg, '']) html_tree = HTML(html_str) @@ -269,14 +269,14 @@ def visit_xhtml(self, element): msg = _("Tag '{invalid_tag}' is not supported; all tag contents are discarded." ).format(invalid_tag=element.tag.name) self.no_dups_flash.log(msg, "info") - logging.debug("WARNING : Ignored tag : {0}".format(element.tag.name)) + logging.debug(f"WARNING : Ignored tag : {element.tag.name}") return # Otherwise we process children of the unknown element msg = _("Tag '{invalid_tag}' is not known; tag ignored but children are processed." ).format(invalid_tag=element.tag.name) self.no_dups_flash.log(msg, "info") - logging.debug("WARNING : Unknown tag : {0}".format(element.tag.name)) + logging.debug(f"WARNING : Unknown tag : {element.tag.name}") return self.do_children(element) # TODO: if this is useful, it should be documented. Normally tags are in and diff --git a/src/moin/converters/macro.py b/src/moin/converters/macro.py index 97dd292d9..a100a55fa 100644 --- a/src/moin/converters/macro.py +++ b/src/moin/converters/macro.py @@ -31,7 +31,7 @@ def _factory(cls, input, output, macros=None, **kw): return cls() def handle_macro(self, elem, page): - logging.debug("handle_macro elem: %r" % elem) + logging.debug(f"handle_macro elem: {elem!r}") type = elem.get(moin_page.content_type) alt = elem.get(moin_page.alt) @@ -40,7 +40,7 @@ def handle_macro(self, elem, page): type = Type(type) if not (type.type == 'x-moin' and type.subtype == 'macro'): - logging.debug("not a macro, skipping: %r" % (type, )) + logging.debug(f"not a macro, skipping: {type!r}") return name = type.parameters['name'] @@ -56,14 +56,14 @@ def handle_macro(self, elem, page): elem_body.append(ret) except PluginMissingError: - elem_error.append('<<%s>> %s' % (name, _('Error: invalid macro name.'))) + elem_error.append(f"<<{name}>> {_('Error: invalid macro name.')}") except Exception as e: # we do not want that a faulty macro aborts rendering of the page # and makes the wiki UI unusable (by emitting a Server Error), # thus, in case of exceptions, we just log the problem and return # some standard text. - logging.exception("Macro {0} raised an exception:".format(name)) + logging.exception(f"Macro {name} raised an exception:") elem_error.append(_('<<{macro_name}: execution failed [{error_msg}] (see also the log)>>' ).format(macro_name=name, error_msg=str(e))) diff --git a/src/moin/converters/markdown_in.py b/src/moin/converters/markdown_in.py index 8904e6325..ddb79ecbf 100644 --- a/src/moin/converters/markdown_in.py +++ b/src/moin/converters/markdown_in.py @@ -393,10 +393,10 @@ def visit(self, element): # We should ignore this tag if element.tag in self.ignored_tags: - logging.info("INFO : Ignored tag : {0}".format(element.tag)) + logging.info(f"INFO : Ignored tag : {element.tag}") return - logging.info("INFO : Unhandled tag : {0}".format(element.tag)) + logging.info(f"INFO : Unhandled tag : {element.tag}") return # }}} end of html conversion @@ -489,7 +489,7 @@ def embedded_markup(self, text): """ try: # we enclose plain text and span tags with P-tags - p_text = html_in_converter('

%s

' % text) + p_text = html_in_converter(f'

{text}

') # discard page and body tags return p_text[0][0] except AssertionError: diff --git a/src/moin/converters/moinwiki_out.py b/src/moin/converters/moinwiki_out.py index e749d3a28..592e55f86 100644 --- a/src/moin/converters/moinwiki_out.py +++ b/src/moin/converters/moinwiki_out.py @@ -163,7 +163,7 @@ def open_children(self, elem): ret = '\n' if child == '\n' and getattr(elem, 'level', 0): child = child + ' ' * (len(''.join(self.list_item_labels[:-1])) + len(self.list_item_labels[:-1])) - childrens_output.append('{0}{1}'.format(ret, child)) + childrens_output.append(f'{ret}{child}') self.last_closed = 'text' out = ''.join(childrens_output) return out @@ -197,7 +197,7 @@ def open_moinpage_a(self, elem): params['class'] = elem.get(html.class_, None) params['accesskey'] = elem.get(html.accesskey, None) # we sort so output order is predictable for tests - params = ','.join(['{0}="{1}"'.format(p, params[p]) for p in sorted(params) if params[p]]) + params = ','.join([f'{p}="{params[p]}"' for p in sorted(params) if params[p]]) # XXX: We don't have Iri support for now if isinstance(href, Iri): @@ -221,7 +221,7 @@ def open_moinpage_a(self, elem): text = self.open_children(elem) if text == href: text = '' - ret = '{0}{1}|{2}|{3}'.format(href, args, text, params) + ret = f'{href}{args}|{text}|{params}' ret = ret.rstrip('|') if ret.startswith('wiki://'): # interwiki fixup @@ -235,8 +235,7 @@ def open_moinpage_blockcode(self, elem): for s in findall(r'}+', text): if max_subpage_lvl <= len(s): max_subpage_lvl = len(s) + 1 - ret = '{0}\n{1}\n{2}\n'.format( - Moinwiki.verbatim_open * max_subpage_lvl, text, Moinwiki.verbatim_close * max_subpage_lvl) + ret = f'{Moinwiki.verbatim_open * max_subpage_lvl}\n{text}\n{Moinwiki.verbatim_close * max_subpage_lvl}\n' return '\n' + ret + '\n' def open_moinpage_block_comment(self, elem): @@ -267,7 +266,7 @@ def open_moinpage_div(self, elem): def open_moinpage_emphasis(self, elem): childrens_output = self.open_children(elem) - return "{0}{1}{2}".format(Moinwiki.emphasis, childrens_output, Moinwiki.emphasis) + return f"{Moinwiki.emphasis}{childrens_output}{Moinwiki.emphasis}" def open_moinpage_h(self, elem): level = elem.get(moin_page.outline_level, 1) @@ -281,7 +280,7 @@ def open_moinpage_h(self, elem): level = 6 ret = Moinwiki.h * level + ' ' ret += ''.join(elem.itertext()) - ret += ' {0}\n'.format(Moinwiki.h * level) + ret += f' {Moinwiki.h * level}\n' return '\n' + ret def open_moinpage_line_break(self, elem): @@ -301,7 +300,7 @@ def open_moinpage_list(self, elem): list_start = elem.attrib.get(moin_page.list_start) if list_start: child_out1, child_out2 = childrens_output.split('.', 1) - childrens_output = '{0}.#{1}{2}'.format(child_out1, list_start, child_out2) + childrens_output = f'{child_out1}.#{list_start}{child_out2}' self.list_item_labels.pop() self.list_level -= 1 self.status.pop() @@ -309,7 +308,7 @@ def open_moinpage_list(self, elem): ret_end = '' else: ret_end = '\n' - return "{0}{1}{2}".format(ret, childrens_output, ret_end) + return f"{ret}{childrens_output}{ret_end}" def open_moinpage_list_item(self, elem): self.list_item_label = self.list_item_labels[-1] + ' ' @@ -323,9 +322,9 @@ def open_moinpage_list_item_label(self, elem): ret = ' ' * (len(''.join(self.list_item_labels[:-1])) + len(self.list_item_labels[:-1])) # self.list_level if self.last_closed: - ret = '\n{0}'.format(ret) + ret = f'\n{ret}' childrens_output = self.open_children(elem) - return "{0}{1}{2}".format(ret, childrens_output, Moinwiki.definition_list_marker) + return f"{ret}{childrens_output}{Moinwiki.definition_list_marker}" def open_moinpage_list_item_body(self, elem): ret = '' @@ -339,7 +338,7 @@ def open_moinpage_note(self, elem): class_ = elem.get(moin_page.note_class, "") if class_: if class_ == "footnote": - return '<>'.format(self.open_children(elem)) + return f'<>' return '\n<>\n' def open_moinpage_nowiki(self, elem): @@ -351,7 +350,7 @@ def open_moinpage_nowiki(self, elem): # this happens only with pytest, why wasn't open_moinpage_blockcode called? nowiki_args = '' nowiki_marker_len = int(nowiki_marker_len) - return '\n' + Moinwiki.verbatim_open * nowiki_marker_len + '{0}\n{1}\n'.format(nowiki_args, content) + \ + return '\n' + Moinwiki.verbatim_open * nowiki_marker_len + f'{nowiki_args}\n{content}\n' + \ Moinwiki.verbatim_close * nowiki_marker_len + '\n' def include_object(self, xpointer, href): @@ -374,16 +373,16 @@ def include_object(self, xpointer, href): for arg in args: key, val = arg.split('(') arguments[key] = val - parms = ',{0},{1}'.format(arguments.get('heading', ''), arguments.get('level', '')) + parms = f",{arguments.get('heading', '')},{arguments.get('level', '')}" for key in ('sort', 'items', 'skipitems'): if key in arguments: - parms += ',{0}="{1}"'.format(key, arguments[key]) + parms += f',{key}="{arguments[key]}"' while parms.endswith(','): parms = parms[:-1] if not href and 'pages' in arguments: # xpointer needs unescaping, see comments above href = arguments['pages'].replace('^(', '(').replace('^)', ')').replace('^^', '^') - return '<>'.format(href, parms) + return f'<>' def open_moinpage_object(self, elem): """ @@ -417,7 +416,7 @@ def open_moinpage_object(self, elem): options = [] for attr, value in sorted(elem.attrib.items()): if attr in whitelist.keys(): - options.append('{0}="{1}"'.format(whitelist[attr], value)) + options.append(f'{whitelist[attr]}="{value}"') if args: args = '&' + args @@ -426,7 +425,7 @@ def open_moinpage_object(self, elem): args += ' ' args += ' '.join(options) - ret = '{0}{1}|{2}|{3}{4}'.format(Moinwiki.object_open, href, alt, args, Moinwiki.object_close) + ret = f'{Moinwiki.object_open}{href}|{alt}|{args}{Moinwiki.object_close}' ret = sub(r"\|+}}", "}}", ret) return ret @@ -488,13 +487,13 @@ def open_moinpage_page(self, elem): def open_moinpage_body(self, elem): class_ = elem.get(moin_page.class_, '').replace(' ', '/') if class_: - ret = ' {0}\n'.format(class_) + ret = f' {class_}\n' elif len(self.status) > 2: ret = '\n' else: ret = '' childrens_output = self.open_children(elem) - return "{0}{1}".format(ret, childrens_output) + return f"{ret}{childrens_output}" def open_moinpage_part(self, elem): type = elem.get(moin_page.content_type, "").split(';') @@ -502,7 +501,7 @@ def open_moinpage_part(self, elem): if type[0] == "x-moin/macro": name = type[1].split('=')[1] if name not in macro_modules: - logging.debug("Unknown macro {} found.".format(name)) + logging.debug(f"Unknown macro {name} found.") if name not in self.unknown_macro_list: self.unknown_macro_list.append(name) eol = '\n\n' if elem.tag.name == 'part' else '' @@ -513,15 +512,15 @@ def open_moinpage_part(self, elem): return "{0}<<{1}()>>{0}".format(eol, name) elif type[0] == "x-moin/format": elem_it = iter(elem) - ret = "{{{{{{#!{0}".format(type[1].split('=')[1]) + ret = f"{{{{{{#!{type[1].split('=')[1]}" if len(elem) and next(elem_it).tag.name == "arguments": args = [] for arg in next(iter(elem)): if arg.tag.name == "argument": - args.append("{0}=\"{1}\"".format(arg.get(moin_page.name, ""), ' '.join(arg.itertext()))) - ret = '{0}({1})'.format(ret, ' '.join(args)) + args.append(f"{arg.get(moin_page.name, '')}=\"{' '.join(arg.itertext())}\"") + ret = f"{ret}({' '.join(args)})" elem = next(elem_it) - ret = "{0}\n{1}\n}}}}}}\n".format(ret, ' '.join(elem.itertext())) + ret = f"{ret}\n{' '.join(elem.itertext())}\n}}}}}}\n" return ret return Markup.unescape(elem.get(moin_page.alt, '')) + "\n" @@ -545,7 +544,7 @@ def open_moinpage_separator(self, elem, hr_class_prefix='moin-hr'): try: height = int(hr_class.split(hr_class_prefix)[1]) - 1 except (ValueError, IndexError, TypeError): - raise ElementException('page:separator has invalid class {0}'.format(hr_class)) + raise ElementException(f'page:separator has invalid class {hr_class}') else: if 0 <= height <= 5: hr_ending = ('-' * height) + hr_ending @@ -559,16 +558,16 @@ def open_moinpage_span(self, elem): baseline_shift = elem.get(moin_page.baseline_shift, '') class_ = elem.get(moin_page.class_, '') if class_ == 'comment': - return '/* {0} */'.format(self.open_children(elem)) + return f'/* {self.open_children(elem)} */' if font_size: return "{0}{1}{2}".format( Moinwiki.larger_open if font_size == "120%" else Moinwiki.smaller_open, self.open_children(elem), Moinwiki.larger_close if font_size == "120%" else Moinwiki.smaller_close) if baseline_shift == 'super': - return '^{0}^'.format(''.join(elem.itertext())) + return f"^{''.join(elem.itertext())}^" if baseline_shift == 'sub': - return ',,{0},,'.format(''.join(elem.itertext())) + return f",,{''.join(elem.itertext())},," return ''.join(self.open_children(elem)) def open_moinpage_del(self, elem): # stroke or strike-through @@ -584,7 +583,7 @@ def open_moinpage_u(self, elem): # underline via html_in return self.open_moinpage_ins(elem) def open_moinpage_strong(self, elem): - return "{0}{1}{2}".format(Moinwiki.strong, self.open_children(elem), Moinwiki.strong) + return f"{Moinwiki.strong}{self.open_children(elem)}{Moinwiki.strong}" def open_moinpage_table(self, elem): self.table_tableclass = elem.attrib.get(moin_page.class_, '') @@ -654,38 +653,38 @@ def open_moinpage_table_cell(self, elem): # TODO: maybe this can be written shorter if self.table_tableclass: - attrib.append('tableclass="{0}"'.format(self.table_tableclass)) + attrib.append(f'tableclass="{self.table_tableclass}"') self.table_tableclass = '' if self.table_tablestyle: - attrib.append('tablestyle="{0}"'.format(self.table_tablestyle)) + attrib.append(f'tablestyle="{self.table_tablestyle}"') self.table_tablestyle = '' if self.table_caption: - attrib.append('caption="{0}"'.format(self.table_caption)) + attrib.append(f'caption="{self.table_caption}"') self.table_caption = '' if self.table_rowclass: - attrib.append('rowclass="{0}"'.format(self.table_rowclass)) + attrib.append(f'rowclass="{self.table_rowclass}"') self.table_rowclass = '' if self.table_rowstyle: - attrib.append('rowstyle="{0}"'.format(self.table_rowstyle)) + attrib.append(f'rowstyle="{self.table_rowstyle}"') self.table_rowstyle = '' if table_cellclass: - attrib.append('class="{0}"'.format(table_cellclass)) + attrib.append(f'class="{table_cellclass}"') if table_cellstyle: - attrib.append('style="{0}"'.format(table_cellstyle)) + attrib.append(f'style="{table_cellstyle}"') if number_rows_spanned: - attrib.append('rowspan="{0}"'.format(number_rows_spanned)) + attrib.append(f'rowspan="{number_rows_spanned}"') if number_columns_spanned > 1: - attrib.append('colspan="{0}"'.format(number_columns_spanned)) + attrib.append(f'colspan="{number_columns_spanned}"') attrib = ' '.join(attrib) if attrib: - ret += '<{0}>'.format(attrib) + ret += f'<{attrib}>' childrens_output = self.open_children(elem) return ret + childrens_output def open_moinpage_table_of_content(self, elem): - return "<>\n".format(elem.get(moin_page.outline_level, "")) + return f"<>\n" def open_xinclude(self, elem): """Processing of transclusions is similar to objects.""" diff --git a/src/moin/converters/opendocument_in.py b/src/moin/converters/opendocument_in.py index 8844bd0a6..8c9844c67 100644 --- a/src/moin/converters/opendocument_in.py +++ b/src/moin/converters/opendocument_in.py @@ -32,7 +32,7 @@ def __call__(self, rev, contenttype=None, arguments=None): text = strip_xml(text) return text except AttributeError as e: - logging.warning("Content of file {} is not seekable. {}".format(rev.meta[NAME], str(e))) + logging.warning(f"Content of file {rev.meta[NAME]} is not seekable. {str(e)}") finally: zf.close() diff --git a/src/moin/i18n/__init__.py b/src/moin/i18n/__init__.py index f5e90a49b..0e4e12d4e 100644 --- a/src/moin/i18n/__init__.py +++ b/src/moin/i18n/__init__.py @@ -45,26 +45,26 @@ def get_locale(): if u and u.locale is not None: # locale is given in user profile, use it locale = u.locale - logging.debug("user locale = {0!r}".format(locale)) + logging.debug(f"user locale = {locale!r}") else: # try to guess the language from the user accept # header the browser transmits. The best match wins. cli_no_request_ctx = False try: - logging.debug("request.accept_languages = {0!r}".format(request.accept_languages)) + logging.debug(f"request.accept_languages = {request.accept_languages!r}") except RuntimeError: # CLI call has no valid request context cli_no_request_ctx = True supported_locales = [Locale('en')] + current_app.extensions['babel'].instance.list_translations() - logging.debug("supported_locales = {0!r}".format(supported_locales)) + logging.debug(f"supported_locales = {supported_locales!r}") supported_languages = [str(locale) for locale in supported_locales] - logging.debug("supported_languages = {0!r}".format(supported_languages)) + logging.debug(f"supported_languages = {supported_languages!r}") if not cli_no_request_ctx: locale = request.accept_languages.best_match(supported_languages, 'en') - logging.debug("best match locale = {0!r}".format(locale)) + logging.debug(f"best match locale = {locale!r}") if not locale: locale = current_app.cfg.locale_default - logging.debug("default locale = {0!r}".format(locale)) + logging.debug(f"default locale = {locale!r}") return locale diff --git a/src/moin/items/__init__.py b/src/moin/items/__init__.py index a125e9898..f632edda5 100644 --- a/src/moin/items/__init__.py +++ b/src/moin/items/__init__.py @@ -133,9 +133,9 @@ def wiki_matches(fq_name, fq_names, start_re=None, end_re=None): :returns: start, end, matches dict """ if start_re is None: - start_re = re.compile('([{0}][{1}]+)'.format(CHARS_UPPER, CHARS_LOWER)) + start_re = re.compile(f'([{CHARS_UPPER}][{CHARS_LOWER}]+)') if end_re is None: - end_re = re.compile('([{0}][{1}]+)$'.format(CHARS_UPPER, CHARS_LOWER)) + end_re = re.compile(f'([{CHARS_UPPER}][{CHARS_LOWER}]+)$') # If we don't get results with wiki words matching, fall back to # simple first word and last word, using spaces. @@ -377,12 +377,12 @@ def get_storage_revision(fqname, itemtype=None, contenttype=None, rev_id=CURRENT if item.fqname: fqname = item.fqname if not item: # except NoSuchItemError: - logging.debug("No such item: {0!r}".format(fqname)) + logging.debug(f"No such item: {fqname!r}") item = DummyItem(fqname) rev = DummyRev(item, itemtype, contenttype) - logging.debug("Item {0!r}, created dummy revision with contenttype {1!r}".format(fqname, contenttype)) + logging.debug(f"Item {fqname!r}, created dummy revision with contenttype {contenttype!r}") else: - logging.debug("Got item: {0!r}".format(fqname)) + logging.debug(f"Got item: {fqname!r}") try: rev = item.get_revision(rev_id) except KeyError: # NoSuchRevisionError: @@ -390,10 +390,10 @@ def get_storage_revision(fqname, itemtype=None, contenttype=None, rev_id=CURRENT rev = item.get_revision(CURRENT) # fall back to current revision # XXX add some message about invalid revision except KeyError: # NoSuchRevisionError: - logging.debug("Item {0!r} has no revisions.".format(fqname)) + logging.debug(f"Item {fqname!r} has no revisions.") rev = DummyRev(item, itemtype, contenttype) - logging.debug("Item {0!r}, created dummy revision with contenttype {1!r}".format(fqname, contenttype)) - logging.debug("Got item {0!r}, revision: {1!r}".format(fqname, rev_id)) + logging.debug(f"Item {fqname!r}, created dummy revision with contenttype {contenttype!r}") + logging.debug(f"Got item {fqname!r}, revision: {rev_id!r}") return rev @@ -630,11 +630,11 @@ def create(cls, name='', itemtype=None, contenttype=None, rev_id=CURRENT, item=N """ fqname = split_fqname(name) if fqname.field not in UFIELDS: # Need a unique key to extract stored item. - raise FieldNotUniqueError("field {0} is not in UFIELDS".format(fqname.field)) + raise FieldNotUniqueError(f"field {fqname.field} is not in UFIELDS") rev = get_storage_revision(fqname, itemtype, contenttype, rev_id, item) contenttype = rev.meta.get(CONTENTTYPE) or contenttype - logging.debug("Item {0!r}, got contenttype {1!r} from revision meta".format(name, contenttype)) + logging.debug(f"Item {name!r}, got contenttype {contenttype!r} from revision meta") # logging.debug("Item %r, rev meta dict: %r" % (name, dict(rev.meta))) # XXX Cannot pass item=item to Content.__init__ via @@ -642,10 +642,10 @@ def create(cls, name='', itemtype=None, contenttype=None, rev_id=CURRENT, item=N content = Content.create(contenttype) itemtype = rev.meta.get(ITEMTYPE) or itemtype or ITEMTYPE_DEFAULT - logging.debug("Item {0!r}, got itemtype {1!r} from revision meta".format(name, itemtype)) + logging.debug(f"Item {name!r}, got itemtype {itemtype!r} from revision meta") item = item_registry.get(itemtype, fqname, rev=rev, content=content) - logging.debug("Item class {0!r} handles {1!r}".format(item.__class__, itemtype)) + logging.debug(f"Item class {item.__class__!r} handles {itemtype!r}") content.item = item return item @@ -1085,7 +1085,7 @@ def handle_variables(self, data, meta): @rtype: string @return: new text of wikipage, variables replaced """ - logging.debug("handle_variable data: %r" % data) + logging.debug(f"handle_variable data: {data!r}") if self.contenttype not in CONTENTTYPE_VARIABLES: return data if '@' not in data: @@ -1102,19 +1102,19 @@ def handle_variables(self, data, meta): 'PAGE': item_name, 'ITEM': item_name, 'TIMESTAMP': strftime("%Y-%m-%d %H:%M:%S %Z"), - 'TIME': "<>" % strftime("%Y-%m-%dT%H:%M:%SZ"), - 'DATE': "<>" % strftime("%Y-%m-%dT%H:%M:%SZ"), + 'TIME': f"<>", + 'DATE': f"<>", 'ME': flaskg.user.name0, 'USERNAME': signature, - 'USER': "-- %s" % signature, - 'SIG': "-- %s <>" % (signature, strftime("%Y-%m-%dT%H:%M:%SZ")), + 'USER': f"-- {signature}", + 'SIG': f"-- {signature} <>", } email = flaskg.user.profile._meta.get('email', None) if email: obfuscated_email_address = encodeSpamSafeEmail(email) - variables['MAILTO'] = "<>".format(obfuscated_email_address) - variables['EMAIL'] = "<>".format(email) + variables['MAILTO'] = f"<>" + variables['EMAIL'] = f"<>" else: # penalty for not being logged in is a mangled variable, # else next user to save item may accidentally reveal his email address @@ -1123,9 +1123,9 @@ def handle_variables(self, data, meta): for name in variables: try: - data = data.replace('@{0}@'.format(name), variables[name]) + data = data.replace(f'@{name}@', variables[name]) except UnicodeError: - logging.warning("handle_variables: UnicodeError! name: %r value: %r" % (name, variables[name])) + logging.warning(f"handle_variables: UnicodeError! name: {name!r} value: {variables[name]!r}") return data @property @@ -1540,7 +1540,7 @@ def do_modify(self): if app.cfg.edit_locking_policy == LOCK: locked_msg = edit_utils.unlock_item() if locked_msg: - logging.error("Item saved but locked by someone else: {0!r}".format(self.fqname)) + logging.error(f"Item saved but locked by someone else: {self.fqname!r}") flash(locked_msg, "info") edit_utils.cursor_close() return redirect(url_for_item(**self.fqname.split)) diff --git a/src/moin/items/content.py b/src/moin/items/content.py index 9ffcfb2c8..dd50a79e1 100644 --- a/src/moin/items/content.py +++ b/src/moin/items/content.py @@ -109,7 +109,7 @@ def register(self, e, group): # If group is specified and contenttype is not a wildcard one if group and e.content_type.type and e.content_type.subtype: if group not in self.groups: - raise ValueError('Unknown group name: {0}'.format(group)) + raise ValueError(f'Unknown group name: {group}') self.groups[group].append(e) self.groups[group].sort(key=attrgetter('ingroup_order')) return self._register(e) @@ -128,7 +128,7 @@ def register(self, e, group): def register(cls): if not cls.display_name or len(ENABLED_CONTENT_TYPES) == 0 or cls.display_name in ENABLED_CONTENT_TYPES: - logging.debug("register contenttype {0} in group {1}".format(cls.display_name, cls.group)) + logging.debug(f"register contenttype {cls.display_name} in group {cls.group}") content_registry.register(RegistryContent.Entry(cls._factory, Type(cls.contenttype), cls.default_contenttype_params, cls.display_name, cls.ingroup_order, RegistryContent.PRIORITY_MIDDLE), cls.group) @@ -162,7 +162,7 @@ def _factory(cls, *args, **kw): @classmethod def create(cls, contenttype, item=None): content = content_registry.get(contenttype, item) - logging.debug("Content class {0!r} handles {1!r}".format(content.__class__, contenttype)) + logging.debug(f"Content class {content.__class__!r} handles {contenttype!r}") return content def __init__(self, contenttype, item=None): @@ -209,7 +209,7 @@ def internal_representation(self, attributes=None, preview=None): from moin.converters import default_registry as reg input_conv = reg.get(Type(self.contenttype), type_moin_document) if not input_conv: - raise TypeError("We cannot handle the conversion from {0} to the DOM tree".format(self.contenttype)) + raise TypeError(f"We cannot handle the conversion from {self.contenttype} to the DOM tree") smiley_conv = reg.get(type_moin_document, type_moin_document, icon='smiley') # We can process the conversion @@ -269,7 +269,7 @@ def _render_data(self, preview=None): # converter does not crash the item view (otherwise a user might # not be able to fix it from the UI). error_id = uuid.uuid4() - logging.exception("An exception happened in _render_data (error_id = %s ):" % error_id) + logging.exception(f"An exception happened in _render_data (error_id = {error_id} ):") rendered_data = render_template('crash.html', server_time=time.strftime("%Y-%m-%d %H:%M:%S %Z"), url=request.url, @@ -467,7 +467,7 @@ def put_member(self, name, content, content_length, expected_members): :param expected_members: set of expected member file names """ if name not in expected_members: - raise StorageError("tried to add unexpected member {0!r} to container item {1!r}".format(name, self.name)) + raise StorageError(f"tried to add unexpected member {name!r} to container item {self.name!r}") assert isinstance(name, str) temp_fname = os.path.join(tempfile.gettempdir(), 'TarContainer_' + cache_key(usage='TarContainer', name=self.name)) @@ -478,8 +478,8 @@ def put_member(self, name, content, content_length, expected_members): content_length = len(content) content = BytesIO(content) # we need a file obj elif not hasattr(content, 'read'): - logging.error("unsupported content object: {0!r}".format(content)) - raise StorageError("unsupported content object: {0!r}".format(content)) + logging.error(f"unsupported content object: {content!r}") + raise StorageError(f"unsupported content object: {content!r}") else: raise NotImplementedError assert content_length >= 0 # we don't want -1 interpreted as 4G-1 @@ -487,7 +487,7 @@ def put_member(self, name, content, content_length, expected_members): tf.addfile(ti, content) tf_members = set(tf.getnames()) if tf_members - expected_members: - msg = "found unexpected members in container item {0!r}".format(self.name) + msg = f"found unexpected members in container item {self.name!r}" logging.error(msg) os.remove(temp_fname) raise StorageError(msg) @@ -658,7 +658,7 @@ def _transform(self, content_type, size=None, transpose_op=None): elif content_type == 'image/gif': output_type = 'GIF' else: - raise ValueError("content_type {0!r} not supported".format(content_type)) + raise ValueError(f"content_type {content_type!r} not supported") # revision obj has read() seek() tell(), thus this works: image = PILImage.open(self.rev.data) @@ -739,14 +739,14 @@ def _render_data_diff_atom(self, oldrev, newrev): url = url_for('frontend.diffraw', _external=True, item_name=self.name, rev1=oldrev.revid, rev2=newrev.revid) return render_template('atom.html', oldrev=oldrev, newrev=newrev, get='binary', - content=Markup(''.format(escape(url)))) + content=Markup(f'')) def _render_data_diff(self, oldrev, newrev, rev_links={}, fqname=None): if PIL is None: # no PIL, we can't do anything, we just call the base class method return super(TransformableBitmapImage, self)._render_data_diff(oldrev, newrev) url = url_for('frontend.diffraw', item_name=self.name, rev1=oldrev.revid, rev2=newrev.revid) - return Markup(''.format(escape(url))) + return Markup(f'') def _render_data_diff_raw(self, oldrev, newrev): hash_name = HASH_ALGORITHM @@ -767,7 +767,7 @@ def _render_data_diff_raw(self, oldrev, newrev): elif content_type == 'image/gif': output_type = 'GIF' else: - raise ValueError("content_type {0!r} not supported".format(content_type)) + raise ValueError(f"content_type {content_type!r} not supported") try: oldimage = PILImage.open(oldrev.data) @@ -782,7 +782,7 @@ def _render_data_diff_raw(self, oldrev, newrev): headers = wikiutil.file_headers(content_type=content_type, content_length=len(data)) app.cache.set(cid, (headers, data)) except (IOError, ValueError) as err: - logging.exception("error during PILdiff: {0}".format(err)) + logging.exception(f"error during PILdiff: {err}") abort(404) # TODO render user friendly error image else: # XXX TODO check ACL behaviour @@ -1116,9 +1116,9 @@ def _render_data(self): if image_map: mapid, image_map = self._transform_map(image_map, title) title = _('Clickable drawing: {filename}').format(filename=self.name) - return Markup(image_map + '{1}'.format(png_url, title, mapid)) + return Markup(image_map + f'{title}') else: - return Markup('{1}'.format(png_url, title)) + return Markup(f'{title}') @register @@ -1148,4 +1148,4 @@ def _render_data(self): # of items and also rendering them with the code in base class could work drawing_url = url_for('frontend.get_item', item_name=self.name, member='drawing.svg', rev=self.rev.revid) png_url = url_for('frontend.get_item', item_name=self.name, member='drawing.png', rev=self.rev.revid) - return Markup('{1}'.format(png_url, drawing_url)) + return Markup(f'{drawing_url}') diff --git a/src/moin/log.py b/src/moin/log.py index 5a6c76fa1..489e88c17 100644 --- a/src/moin/log.py +++ b/src/moin/log.py @@ -109,7 +109,7 @@ def _log_warning(message, category, filename, lineno, file=None, line=None): # for warnings, we just want to use the logging system, not stderr or other files - msg = "{0}:{1}: {2}: {3}".format(filename, lineno, category.__name__, message) + msg = f"{filename}:{lineno}: {category.__name__}: {message}" logger = getLogger(__name__) # Note: the warning will look like coming from here, # but msg contains info about where it really comes from @@ -135,7 +135,7 @@ def load_config(conf_fname=None): f.close() configured = True logger = getLogger(__name__) - logger.debug('using logging configuration read from "{0}"'.format(conf_fname)) + logger.debug(f'using logging configuration read from "{conf_fname}"') warnings.showwarning = _log_warning except Exception as err: # XXX be more precise err_msg = str(err) @@ -146,13 +146,13 @@ def load_config(conf_fname=None): configured = True logger = getLogger(__name__) if err_msg: - logger.warning('load_config for "{0}" failed with "{1}".'.format(conf_fname, err_msg)) + logger.warning(f'load_config for "{conf_fname}" failed with "{err_msg}".') logger.debug('using logging configuration read from built-in fallback in moin.log module!') warnings.showwarning = _log_warning import moin code_path = os.path.dirname(moin.__file__) - logger.debug('Running %s %s code from %s' % (moin.project, moin.version, code_path)) + logger.debug(f'Running {moin.project} {moin.version} code from {code_path}') def getLogger(name): @@ -211,8 +211,7 @@ def emit(self, record): try: toaddrs = self.toaddrs if self.toaddrs else app.cfg.admin_emails log_level = logging.getLevelName(self.level) - subject = self.subject if self.subject else '[{0}][{1}] Log message'.format( - app.cfg.sitename, log_level) + subject = self.subject if self.subject else f'[{app.cfg.sitename}][{log_level}] Log message' msg = self.format(record) from moin.mail.sendmail import sendmail sendmail(subject, msg, to=toaddrs) diff --git a/src/moin/mail/sendmail.py b/src/moin/mail/sendmail.py index ff8470b4c..60d34b13b 100644 --- a/src/moin/mail/sendmail.py +++ b/src/moin/mail/sendmail.py @@ -55,8 +55,8 @@ def sendmail(subject, text, to=None, cc=None, bcc=None, mail_from=None, html=Non "because mail configuration is incomplete.")) mail_from = mail_from or cfg.mail_from - logging.debug("send mail, from: {0!r}, subj: {1!r}".format(mail_from, subject)) - logging.debug("send mail, to: {0!r}".format(to)) + logging.debug(f"send mail, from: {mail_from!r}, subj: {subject!r}") + logging.debug(f"send mail, to: {to!r}") if not to and not cc and not bcc: return 1, _("No recipients, nothing to do") @@ -87,7 +87,7 @@ def sendmail(subject, text, to=None, cc=None, bcc=None, mail_from=None, html=Non # Send the message if not cfg.mail_sendmail: try: - logging.debug("trying to send mail (smtp) via smtp server '{0}'".format(cfg.mail_smarthost)) + logging.debug(f"trying to send mail (smtp) via smtp server '{cfg.mail_smarthost}'") host, port = (cfg.mail_smarthost + ':25').split(':')[:2] server = smtplib.SMTP(host, int(port)) try: @@ -101,7 +101,7 @@ def sendmail(subject, text, to=None, cc=None, bcc=None, mail_from=None, html=Non logging.debug("could not establish a tls connection to smtp server, continuing without tls") # server.set_debuglevel(1) if cfg.mail_username is not None and cfg.mail_password is not None: - logging.debug("trying to log in to smtp server using account '{0}'".format(cfg.mail_username)) + logging.debug(f"trying to log in to smtp server using account '{cfg.mail_username}'") server.login(cfg.mail_username, cfg.mail_password) server.send_message(msg) finally: @@ -142,10 +142,10 @@ def encodeSpamSafeEmail(email_address, obfuscation_text=''): address = email_address.lower() # uppercase letters will be stripped by decodeSpamSafeEmail for word, sign in _transdict.items(): - address = address.replace(sign, ' {0} '.format(word)) + address = address.replace(sign, f' {word} ') if obfuscation_text.isalpha(): # is the obfuscation_text alphabetic - address = address.replace(' AT ', ' AT {0} '.format(obfuscation_text.upper())) + address = address.replace(' AT ', f' AT {obfuscation_text.upper()} ') return address diff --git a/src/moin/signalling/log.py b/src/moin/signalling/log.py index 01948c191..e5357b89b 100644 --- a/src/moin/signalling/log.py +++ b/src/moin/signalling/log.py @@ -16,13 +16,13 @@ @item_displayed.connect_via(ANY) def log_item_displayed(app, fqname): wiki_name = app.cfg.interwikiname - logging.info("item {0}:{1} displayed".format(wiki_name, str(fqname))) + logging.info(f"item {wiki_name}:{str(fqname)} displayed") @item_modified.connect_via(ANY) def log_item_modified(app, fqname, **kwargs): wiki_name = app.cfg.interwikiname - logging.info("item {0}:{1} modified".format(wiki_name, str(fqname))) + logging.info(f"item {wiki_name}:{str(fqname)} modified") @got_request_exception.connect_via(ANY) diff --git a/src/moin/storage/middleware/indexing.py b/src/moin/storage/middleware/indexing.py index 13d1139ac..d7beba746 100644 --- a/src/moin/storage/middleware/indexing.py +++ b/src/moin/storage/middleware/indexing.py @@ -264,7 +264,7 @@ def tell(self, *args, **kw): return self.data.tell(*args, **kw) if meta[CONTENTTYPE] in app.cfg.mimetypes_to_index_as_empty: - logging.debug("not indexing content of {0!r} as requested by configuration".format(meta[NAME])) + logging.debug(f"not indexing content of {meta[NAME]!r} as requested by configuration") return '' rev = PseudoRev(meta, data) @@ -307,11 +307,11 @@ def tell(self, *args, **kw): doc = output_conv(doc) return doc # no way - raise TypeError("No converter for {0} --> {1}".format(input_contenttype, output_contenttype)) + raise TypeError(f"No converter for {input_contenttype} --> {output_contenttype}") except Exception as e: # catch all exceptions, we don't want to break an indexing run logging.exception("Exception happened in conversion of item {0!r} rev {1} contenttype {2}:".format( item_name, meta.get(REVID, 'new'), meta.get(CONTENTTYPE, ''))) - doc = 'ERROR [{0!s}]'.format(e) + doc = f'ERROR [{e!s}]' return doc @@ -485,7 +485,7 @@ def get_storage_params(self, tmp=False): from whoosh.filedb.filestore import FileStorage cls = FileStorage else: - raise ValueError("index_storage = {0!r} is not supported!".format(kind)) + raise ValueError(f"index_storage = {kind!r} is not supported!") return kind, cls, params, kw def get_storage(self, tmp=False, create=False): @@ -653,7 +653,7 @@ def _modify_index(self, index, schema, wikiname, revids, mode='add', procs=1, li elif mode == 'delete': writer.delete_by_term(REVID, revid) else: - raise ValueError("mode must be 'update', 'add' or 'delete', not '{0}'".format(mode)) + raise ValueError(f"mode must be 'update', 'add' or 'delete', not '{mode}'") def _find_latest_backends_revids(self, index, query=None): """ @@ -1121,7 +1121,7 @@ def existing(cls, indexer, **query): raise NoSuchItemError(repr(query)) def __repr__(self): - return '' % (self.name, ) + return f'' def __bool__(self): """ @@ -1224,11 +1224,11 @@ def store_revision(self, meta, data, overwrite=False, if e.name == 'subscriptions': for sub in e.children: if sub.valid is False: - val.append('"{}". {}'.format(str(sub), str(sub.errors[0]))) + val.append(f'"{str(sub)}". {str(sub.errors[0])}') e.valid = False elif e.valid is False: val.append(str(e)) - logging.warning("{0}, {1}, {2}".format(e.valid, e.name, e.raw)) + logging.warning(f"{e.valid}, {e.name}, {e.raw}") if VALIDATION_HANDLING == VALIDATION_HANDLING_STRICT: raise ValueError(_('Error: metadata validation failed, invalid field value(s) = {0}').format( ', '.join(val) @@ -1250,7 +1250,7 @@ def store_revision(self, meta, data, overwrite=False, meta[SUMMARY] = "" if valid and not validate_data(meta, data): # need valid metadata to validate data - logging.warning("data validation failed for item {0} ".format(meta[NAME])) + logging.warning(f"data validation failed for item {meta[NAME]} ") if VALIDATION_HANDLING == VALIDATION_HANDLING_STRICT: raise ValueError(_('Error: nothing changed. Data unicode validation failed.')) @@ -1379,7 +1379,7 @@ def __lt__(self, other): return self.meta < other.meta def __repr__(self): - return '' % (self.revid[:6], self.name) + return f'' class Meta(Mapping): @@ -1430,4 +1430,4 @@ def __len__(self): return 0 # XXX def __repr__(self): - return "Meta _doc: {0!r} _meta: {1!r}".format(self._doc, self._meta) + return f"Meta _doc: {self._doc!r} _meta: {self._meta!r}" diff --git a/src/moin/themes/__init__.py b/src/moin/themes/__init__.py index 734a988aa..02edf93a6 100644 --- a/src/moin/themes/__init__.py +++ b/src/moin/themes/__init__.py @@ -51,8 +51,7 @@ def get_current_theme(): try: return get_theme(theme_name) except KeyError: - logging.warning("Theme {0!r} was not found; using default of {1!r} instead.".format( - theme_name, app.cfg.theme_default)) + logging.warning(f"Theme {theme_name!r} was not found; using default of {app.cfg.theme_default!r} instead.") theme_name = app.cfg.theme_default return get_theme(theme_name) @@ -258,7 +257,7 @@ def get_local_panel(self, fqname): for sub_item_name in app.cfg.supplementation_item_names: current_sub = fqname.value.rsplit('/', 1)[-1] if current_sub not in app.cfg.supplementation_item_names: - supp_name = '%s/%s' % (fqname.value, sub_item_name) + supp_name = f'{fqname.value}/{sub_item_name}' if flaskg.storage.has_item(supp_name) or flaskg.user.may.write(supp_name): subitem_exists = self.storage.has_item(supp_name) href = url_for('frontend.show_item', item_name=supp_name) @@ -359,7 +358,7 @@ def userhome(self): name = user.name0 display_name = user.display_name or name wikiname, itemname = getInterwikiHome(name) - title = "{0} @ {1}".format(display_name, wikiname) + title = f"{display_name} @ {wikiname}" # link to (interwiki) user homepage if is_local_wiki(wikiname): exists = self.storage.has_item(itemname) @@ -445,11 +444,11 @@ def navibar(self, fqname): elif endpoint in ["frontend.global_history", "frontend.global_tags"]: args['namespace'] = fqname.namespace if fqname and fqname.namespace: - link_text = '{0}/{1}'.format(fqname.namespace, link_text) + link_text = f'{fqname.namespace}/{link_text}' elif endpoint == "frontend.index": args['item_name'] = fqname.namespace if fqname and fqname.namespace: - link_text = '{0}/{1}'.format(fqname.namespace, link_text) + link_text = f'{fqname.namespace}/{link_text}' elif endpoint == "admin.index" and not getattr(flaskg.user.may, SUPERUSER)(): continue items.append((cls, url_for(endpoint, **args), link_text, title)) @@ -481,10 +480,10 @@ def navibar(self, fqname): pass # ignore invalid lines f.close() app.cache.set(cid, sisteritems) - logging.info("Site: {0!r} Status: Updated. Pages: {1}".format(sistername, len(sisteritems))) + logging.info(f"Site: {sistername!r} Status: Updated. Pages: {len(sisteritems)}") except IOError as err: (title, code, msg, headers) = err.args # code e.g. 304 - logging.warning("Site: {0!r} Status: Not updated.".format(sistername)) + logging.warning(f"Site: {sistername!r} Status: Not updated.") logging.exception("exception was:") if current in sisteritems: url = sisteritems[current] @@ -603,11 +602,11 @@ def get_editor_info(meta, external=False): # only tell ip / hostname if show_hosts is True if hostname: text = hostname[:15] # 15 = len(ipaddr) - name = title = '{0}[{1}]'.format(hostname, addr) + name = title = f'{hostname}[{addr}]' css = 'editor host' else: name = text = addr - title = '[{0}]'.format(addr) + title = f'[{addr}]' css = 'editor ip' userid = meta.get(USERID) @@ -618,7 +617,7 @@ def get_editor_info(meta, external=False): display_name = u.display_name or name if title: # we already have some address info - title = "{0} @ {1}".format(display_name, title) + title = f"{display_name} @ {title}" else: title = display_name if u.mailto_author and u.email: @@ -690,10 +689,10 @@ def shorten_item_name(name, length=25): # If it's not enough, replace the middle with '...' if len(name_part) > length: half, left = divmod(length - 3, 2) - name = '{0}...{1}'.format(name_part[:half + left], name_part[-half:]) + name = f'{name_part[:half + left]}...{name_part[-half:]}' elif len(name_part) < length - 6: # now it is too short, add back starting characters - name = '{0}...{1}'.format(name[:length - len(name_part) - 3], name_part) + name = f'{name[:length - len(name_part) - 3]}...{name_part}' else: name = name_part return name @@ -733,7 +732,7 @@ def contenttype_to_class(contenttype): if not cls: # just use the major part of mimetype cls = contenttype.split('/', 1)[0] - return 'moin-mime-{0}'.format(cls) + return f'moin-mime-{cls}' def utctimestamp(dt): diff --git a/src/moin/utils/clock.py b/src/moin/utils/clock.py index 19acc696a..f05228320 100644 --- a/src/moin/utils/clock.py +++ b/src/moin/utils/clock.py @@ -42,14 +42,14 @@ def start(self, timer): def stop(self, timer): if timer in self.timers: value = time.time() - self.timers[timer].pop() - logging.debug('timer {0}({1}): {2:.2f}ms'.format(timer, len(self.timers[timer]), value * 1000)) + logging.debug(f'timer {timer}({len(self.timers[timer])}): {value * 1000:.2f}ms') if not self.timers[timer]: del self.timers[timer] return value def __del__(self): if self.timers: - logging.warning('These timers have not been stopped: {0}'.format(', '.join(self.timers.keys()))) + logging.warning(f"These timers have not been stopped: {', '.join(self.timers.keys())}") def add_timing(f, name=None): diff --git a/src/moin/utils/edit_locking.py b/src/moin/utils/edit_locking.py index bd6f23ac7..564835aab 100644 --- a/src/moin/utils/edit_locking.py +++ b/src/moin/utils/edit_locking.py @@ -200,7 +200,7 @@ def get_draft(self): data = data.decode(self.coding) return draft, data except IOError: - logging.error("User {0} failed to load draft for: {1}".format(u_name, i_name)) + logging.error(f"User {u_name} failed to load draft for: {i_name}") return draft, None else: return draft, None @@ -225,7 +225,7 @@ def _delete_draft(self, save_time, rev_id): os.remove(draft_name) except IOError: # draft file is created only when user does Preview - logging.error("IOError when deleting draft named {0} for user {1}".format(draft_name, self.user_name)) + logging.error(f"IOError when deleting draft named {draft_name} for user {self.user_name}") self.cursor.execute('''DELETE FROM editdraft WHERE user_name = ? ''', (self.user_name, )) self.conn.commit() @@ -318,12 +318,11 @@ def unlock_item(self, cancel=False): return elif not cancel: # bug: someone else has active edit lock, relock_item() should have been called prior to item save - logging.error("User {0} tried to unlock item that was locked by someone else: {1}".format( - user_name, i_name)) + logging.error(f"User {user_name} tried to unlock item that was locked by someone else: {i_name}") msg = L_("Item '{item_name}' is locked by {user_name}. Edit lock error, " "check Item History to verify no changes were lost." ).format(item_name=i_name, user_name=u_name) return msg if not cancel: # bug: there should have been a lock_item call prior to unlock call - logging.error("User {0} tried to unlock item that was not locked: {1}".format(user_name, self.item_name)) + logging.error(f"User {user_name} tried to unlock item that was not locked: {self.item_name}") diff --git a/src/moin/utils/filesys.py b/src/moin/utils/filesys.py index 43a555d78..69760ca56 100644 --- a/src/moin/utils/filesys.py +++ b/src/moin/utils/filesys.py @@ -114,8 +114,7 @@ def wrapper(*args, **kwargs): if retry > max_retries: raise if err.errno == errno.EACCES: - logging.warning('{0}({1!r}, {2!r}) -> access denied. retrying...'.format( - fn.__name__, args, kwargs)) + logging.warning(f'{fn.__name__}({args!r}, {kwargs!r}) -> access denied. retrying...') time.sleep(0.01) continue raise diff --git a/src/moin/utils/interwiki.py b/src/moin/utils/interwiki.py index 6603577a2..0ac41537e 100644 --- a/src/moin/utils/interwiki.py +++ b/src/moin/utils/interwiki.py @@ -44,9 +44,9 @@ def get_fqname(item_name, field, namespace): composite name == [NAMESPACE/][@FIELD/]NAME """ if field and field != NAME_EXACT: - item_name = '@{0}/{1}'.format(field, item_name) + item_name = f'@{field}/{item_name}' if namespace: - item_name = '{0}/{1}'.format(namespace, item_name) + item_name = f'{namespace}/{item_name}' return item_name @@ -79,13 +79,13 @@ def url_for_item(item_name, wiki_name='', field='', namespace='', rev=CURRENT, try: wiki_base_url = app.cfg.interwiki_map[wiki_name] except KeyError: - logging.warning("no interwiki_map entry for {0!r}".format(wiki_name)) + logging.warning(f"no interwiki_map entry for {wiki_name!r}") item_name = get_fqname(item_name, field, namespace) if wiki_name: - url = '{0}/{1}'.format(wiki_name, item_name) + url = f'{wiki_name}/{item_name}' else: url = item_name - url = '/{0}'.format(url) + url = f'/{url}' else: if (rev is None or rev == CURRENT) and endpoint == 'frontend.show_item': # we just want to show latest revision (no special revision given) - @@ -104,7 +104,7 @@ def url_for_item(item_name, wiki_name='', field='', namespace='', rev=CURRENT, path = local_url[i + 1:] url = wiki_base_url + path if regex: - url += '?regex={0}'.format(url_quote(regex, encoding=CHARSET)) + url += f'?regex={url_quote(regex, encoding=CHARSET)}' return url @@ -115,7 +115,7 @@ def get_download_file_name(fqname): if fqname.field == NAME_EXACT: return fqname.value else: - return '{0}-{1}'.format(fqname.field, fqname.value) + return f'{fqname.field}-{fqname.value}' def _split_namespace(namespaces, url): @@ -136,7 +136,7 @@ def _split_namespace(namespaces, url): tokens_list = url.split('/') for token in tokens_list: if namespace: - token = '{0}/{1}'.format(namespace, token) + token = f'{namespace}/{token}' if token in namespaces: namespace = token else: @@ -290,7 +290,7 @@ def getInterwikiName(item_name): :rtype: str :returns: wiki_name:item_name """ - return "{0}/{1}".format(app.cfg.interwikiname, item_name) + return f"{app.cfg.interwikiname}/{item_name}" def getInterwikiHome(username): @@ -341,8 +341,7 @@ def __init__(self, s): name, url = line.split(None, 1) self.iwmap[name] = url except ValueError: - raise ValueError('malformed interwiki map string: {0}'.format( - line)) + raise ValueError(f'malformed interwiki map string: {line}') @staticmethod def from_string(ustring): diff --git a/src/moin/utils/subscriptions.py b/src/moin/utils/subscriptions.py index dba23d65b..6c3287ce0 100644 --- a/src/moin/utils/subscriptions.py +++ b/src/moin/utils/subscriptions.py @@ -39,13 +39,13 @@ def get_subscribers(**meta): tags = meta.get(TAGS) terms = [] if itemid is not None: - terms.extend([Term(SUBSCRIPTION_IDS, "{0}:{1}".format(ITEMID, itemid))]) + terms.extend([Term(SUBSCRIPTION_IDS, f"{ITEMID}:{itemid}")]) if namespace is not None: if name is not None: - terms.extend(Term(SUBSCRIPTION_IDS, "{0}:{1}:{2}".format(NAME, namespace, name_)) + terms.extend(Term(SUBSCRIPTION_IDS, f"{NAME}:{namespace}:{name_}") for name_ in name) if tags is not None: - terms.extend(Term(SUBSCRIPTION_IDS, "{0}:{1}:{2}".format(TAGS, namespace, tag)) + terms.extend(Term(SUBSCRIPTION_IDS, f"{TAGS}:{namespace}:{tag}") for tag in tags) query = Or(terms) with flaskg.storage.indexer.ix[LATEST_REVS].searcher() as searcher: @@ -83,14 +83,13 @@ def get_matched_subscription_patterns(subscription_patterns, **meta): try: keyword, value = subscription.split(":", 1) except ValueError: - logging.exception("User {0} has invalid subscription entry: {1}".format(flaskg.user.name[0], subscription)) + logging.exception(f"User {flaskg.user.name[0]} has invalid subscription entry: {subscription}") continue if keyword in (NAMEPREFIX, NAMERE, ) and item_namespace is not None and item_names: try: namespace, pattern = value.split(":", 1) except ValueError: - logging.exception("User {0} has invalid subscription entry: {1}".format( - flaskg.user.name[0], subscription)) + logging.exception(f"User {flaskg.user.name[0]} has invalid subscription entry: {subscription}") continue if item_namespace == namespace: if keyword == NAMEPREFIX: @@ -100,7 +99,7 @@ def get_matched_subscription_patterns(subscription_patterns, **meta): try: pattern = re.compile(pattern, re.U) except re.error: - logging.error("Subscription pattern '{0}' has failed compilation.".format(pattern)) + logging.error(f"Subscription pattern '{pattern}' has failed compilation.") continue if any(pattern.search(name) for name in item_names): matched_subscriptions.append(subscription)