f-strings everywhere

This commit is contained in:
David Lord 2020-04-04 11:39:03 -07:00
parent 524fd0bc8c
commit 2ae740dd49
No known key found for this signature in database
GPG key ID: 7A1C87E3F5BC42A8
35 changed files with 227 additions and 245 deletions

View file

@ -585,7 +585,7 @@ class Flask(_PackageBoundObject):
bool(static_host) == host_matching
), "Invalid static_host/host_matching combination"
self.add_url_rule(
self.static_url_path + "/<path:filename>",
f"{self.static_url_path}/<path:filename>",
endpoint="static",
host=static_host,
view_func=self.send_static_file,
@ -711,7 +711,7 @@ class Flask(_PackageBoundObject):
prefix, package_path = find_package(self.import_name)
if prefix is None:
return os.path.join(package_path, "instance")
return os.path.join(prefix, "var", self.name + "-instance")
return os.path.join(prefix, "var", f"{self.name}-instance")
def open_instance_resource(self, resource, mode="rb"):
"""Opens a resource from the application's instance folder
@ -1084,10 +1084,11 @@ class Flask(_PackageBoundObject):
if blueprint.name in self.blueprints:
assert self.blueprints[blueprint.name] is blueprint, (
"A name collision occurred between blueprints %r and %r. Both"
' share the same name "%s". Blueprints that are created on the'
" fly need unique names."
% (blueprint, self.blueprints[blueprint.name], blueprint.name)
"A name collision occurred between blueprints"
f" {blueprint!r} and {self.blueprints[blueprint.name]!r}."
f" Both share the same name {blueprint.name!r}."
f" Blueprints that are created on the fly need unique"
f" names."
)
else:
self.blueprints[blueprint.name] = blueprint
@ -1209,8 +1210,8 @@ class Flask(_PackageBoundObject):
old_func = self.view_functions.get(endpoint)
if old_func is not None and old_func != view_func:
raise AssertionError(
"View function mapping is overwriting an "
"existing endpoint function: %s" % endpoint
"View function mapping is overwriting an existing"
f" endpoint function: {endpoint}"
)
self.view_functions[endpoint] = view_func
@ -1341,17 +1342,18 @@ class Flask(_PackageBoundObject):
"""
if isinstance(code_or_exception, HTTPException): # old broken behavior
raise ValueError(
"Tried to register a handler for an exception instance {!r}."
" Handlers can only be registered for exception classes or"
" HTTP error codes.".format(code_or_exception)
"Tried to register a handler for an exception instance"
f" {code_or_exception!r}. Handlers can only be"
" registered for exception classes or HTTP error codes."
)
try:
exc_class, code = self._get_exc_class_and_code(code_or_exception)
except KeyError:
raise KeyError(
"'{}' is not a recognized HTTP error code. Use a subclass of"
" HTTPException with that code instead.".format(code_or_exception)
f"'{code_or_exception}' is not a recognized HTTP error"
" code. Use a subclass of HTTPException with that code"
" instead."
)
handlers = self.error_handler_spec.setdefault(key, {}).setdefault(code, {})
@ -1730,7 +1732,7 @@ class Flask(_PackageBoundObject):
# message, add it in manually.
# TODO: clean up once Werkzeug >= 0.15.5 is required
if e.args[0] not in e.get_description():
e.description = "KeyError: '{}'".format(*e.args)
e.description = f"KeyError: {e.args[0]!r}"
elif not hasattr(BadRequestKeyError, "show_exception"):
e.args = ()
@ -2006,9 +2008,9 @@ class Flask(_PackageBoundObject):
# the body must not be None
if rv is None:
raise TypeError(
'The view function for "{}" did not return a valid response. The'
" function either returned None or ended without a return"
" statement.".format(request.endpoint)
f"The view function for {request.endpoint!r} did not"
" return a valid response. The function either returned"
" None or ended without a return statement."
)
# make sure the body is an instance of the response class
@ -2028,17 +2030,17 @@ class Flask(_PackageBoundObject):
rv = self.response_class.force_type(rv, request.environ)
except TypeError as e:
raise TypeError(
"{e}\nThe view function did not return a valid"
" response. The return type must be a string, dict, tuple,"
" Response instance, or WSGI callable, but it was a"
" {rv.__class__.__name__}.".format(e=e, rv=rv)
f"{e}\nThe view function did not return a valid"
" response. The return type must be a string,"
" dict, tuple, Response instance, or WSGI"
f" callable, but it was a {type(rv).__name__}."
).with_traceback(sys.exc_info()[2])
else:
raise TypeError(
"The view function did not return a valid"
" response. The return type must be a string, dict, tuple,"
" Response instance, or WSGI callable, but it was a"
" {rv.__class__.__name__}.".format(rv=rv)
" response. The return type must be a string,"
" dict, tuple, Response instance, or WSGI"
f" callable, but it was a {type(rv).__name__}."
)
# prefer the status if it was provided
@ -2375,4 +2377,4 @@ class Flask(_PackageBoundObject):
return self.wsgi_app(environ, start_response)
def __repr__(self):
return f"<{self.__class__.__name__} {self.name!r}>"
return f"<{type(self).__name__} {self.name!r}>"

View file

@ -246,7 +246,7 @@ class Blueprint(_PackageBoundObject):
if self.has_static_folder:
state.add_url_rule(
self.static_url_path + "/<path:filename>",
f"{self.static_url_path}/<path:filename>",
view_func=self.send_static_file,
endpoint="static",
)

View file

@ -62,13 +62,13 @@ def find_best_app(script_info, module):
return matches[0]
elif len(matches) > 1:
raise NoAppException(
'Detected multiple Flask applications in module "{module}". Use '
'"FLASK_APP={module}:name" to specify the correct '
"one.".format(module=module.__name__)
"Detected multiple Flask applications in module"
f" {module.__name__!r}. Use 'FLASK_APP={module.__name__}:name'"
f" to specify the correct one."
)
# Search for app factory functions.
for attr_name in ("create_app", "make_app"):
for attr_name in {"create_app", "make_app"}:
app_factory = getattr(module, attr_name, None)
if inspect.isfunction(app_factory):
@ -81,15 +81,16 @@ def find_best_app(script_info, module):
if not _called_with_wrong_args(app_factory):
raise
raise NoAppException(
'Detected factory "{factory}" in module "{module}", but '
"could not call it without arguments. Use "
"\"FLASK_APP='{module}:{factory}(args)'\" to specify "
"arguments.".format(factory=attr_name, module=module.__name__)
f"Detected factory {attr_name!r} in module {module.__name__!r},"
" but could not call it without arguments. Use"
f" \"FLASK_APP='{module.__name__}:{attr_name}(args)'\""
" to specify arguments."
)
raise NoAppException(
'Failed to find Flask application or factory in module "{module}". '
'Use "FLASK_APP={module}:name to specify one.'.format(module=module.__name__)
"Failed to find Flask application or factory in module"
f" {module.__name__!r}. Use 'FLASK_APP={module.__name__}:name'"
" to specify one."
)
@ -150,8 +151,7 @@ def find_app_by_string(script_info, module, app_name):
if not match:
raise NoAppException(
'"{name}" is not a valid variable name or function '
"expression.".format(name=app_name)
f"{app_name!r} is not a valid variable name or function expression."
)
name, args = match.groups()
@ -165,11 +165,8 @@ def find_app_by_string(script_info, module, app_name):
if args:
try:
args = ast.literal_eval(f"({args},)")
except (ValueError, SyntaxError) as e:
raise NoAppException(
"Could not parse the arguments in "
'"{app_name}".'.format(e=e, app_name=app_name)
)
except (ValueError, SyntaxError):
raise NoAppException(f"Could not parse the arguments in {app_name!r}.")
else:
args = ()
@ -180,10 +177,9 @@ def find_app_by_string(script_info, module, app_name):
raise
raise NoAppException(
'{e}\nThe factory "{app_name}" in module "{module}" could not '
"be called with the specified arguments.".format(
e=e, app_name=app_name, module=module.__name__
)
f"{e}\nThe factory {app_name!r} in module"
f" {module.__name__!r} could not be called with the"
" specified arguments."
)
else:
app = attr
@ -192,8 +188,8 @@ def find_app_by_string(script_info, module, app_name):
return app
raise NoAppException(
"A valid Flask application was not obtained from "
'"{module}:{app_name}".'.format(module=module.__name__, app_name=app_name)
"A valid Flask application was not obtained from"
f" '{module.__name__}:{app_name}'."
)
@ -236,11 +232,11 @@ def locate_app(script_info, module_name, app_name, raise_if_not_found=True):
# Determine this by checking whether the trace has a depth > 1.
if sys.exc_info()[2].tb_next:
raise NoAppException(
'While importing "{name}", an ImportError was raised:'
"\n\n{tb}".format(name=module_name, tb=traceback.format_exc())
f"While importing {module_name!r}, an ImportError was"
f" raised:\n\n{traceback.format_exc()}"
)
elif raise_if_not_found:
raise NoAppException(f'Could not import "{module_name}".')
raise NoAppException(f"Could not import {module_name!r}.")
else:
return
@ -259,14 +255,10 @@ def get_version(ctx, param, value):
import werkzeug
from . import __version__
message = "Python %(python)s\nFlask %(flask)s\nWerkzeug %(werkzeug)s"
click.echo(
message
% {
"python": platform.python_version(),
"flask": __version__,
"werkzeug": werkzeug.__version__,
},
f"Python {platform.python_version()}\n"
f"Flask {__version__}\n"
f"Werkzeug {werkzeug.__version__}",
color=ctx.color,
)
ctx.exit()
@ -659,7 +651,7 @@ def show_server_banner(env, debug, app_import_path, eager_loading):
return
if app_import_path is not None:
message = f' * Serving Flask app "{app_import_path}"'
message = f" * Serving Flask app {app_import_path!r}"
if not eager_loading:
message += " (lazy loading)"
@ -670,14 +662,14 @@ def show_server_banner(env, debug, app_import_path, eager_loading):
if env == "production":
click.secho(
" WARNING: This is a development server. "
"Do not use it in a production deployment.",
" WARNING: This is a development server. Do not use it in"
" a production deployment.",
fg="red",
)
click.secho(" Use a production WSGI server instead.", dim=True)
if debug is not None:
click.echo(" * Debug mode: {}".format("on" if debug else "off"))
click.echo(f" * Debug mode: {'on' if debug else 'off'}")
class CertParamType(click.ParamType):
@ -809,7 +801,7 @@ class SeparatedPathType(click.Path):
type=SeparatedPathType(),
help=(
"Extra files that trigger a reload on change. Multiple paths"
" are separated by '{}'.".format(os.path.pathsep)
f" are separated by {os.path.pathsep!r}."
),
)
@pass_script_info
@ -863,8 +855,10 @@ def shell_command():
from .globals import _app_ctx_stack
app = _app_ctx_stack.top.app
banner = "Python {} on {}\nApp: {} [{}]\nInstance: {}".format(
sys.version, sys.platform, app.import_name, app.env, app.instance_path,
banner = (
f"Python {sys.version} on {sys.platform}\n"
f"App: {app.import_name} [{app.env}]\n"
f"Instance: {app.instance_path}"
)
ctx = {}

View file

@ -98,10 +98,10 @@ class Config(dict):
if silent:
return False
raise RuntimeError(
"The environment variable %r is not set "
"and as such configuration could not be "
"loaded. Set this variable and make it "
"point to a configuration file" % variable_name
f"The environment variable {variable_name!r} is not set"
" and as such configuration could not be loaded. Set"
" this variable and make it point to a configuration"
" file"
)
return self.from_pyfile(rv, silent=silent)
@ -128,7 +128,7 @@ class Config(dict):
except OSError as e:
if silent and e.errno in (errno.ENOENT, errno.EISDIR, errno.ENOTDIR):
return False
e.strerror = "Unable to load configuration file (%s)" % e.strerror
e.strerror = f"Unable to load configuration file ({e.strerror})"
raise
self.from_object(d)
return True
@ -200,7 +200,7 @@ class Config(dict):
if silent and e.errno in (errno.ENOENT, errno.EISDIR):
return False
e.strerror = "Unable to load configuration file (%s)" % e.strerror
e.strerror = f"Unable to load configuration file ({e.strerror})"
raise
return self.from_mapping(obj)
@ -219,7 +219,7 @@ class Config(dict):
mappings.append(mapping[0])
elif len(mapping) > 1:
raise TypeError(
"expected at most 1 positional argument, got %d" % len(mapping)
f"expected at most 1 positional argument, got {len(mapping)}"
)
mappings.append(kwargs.items())
for mapping in mappings:
@ -270,4 +270,4 @@ class Config(dict):
return rv
def __repr__(self):
return "<{} {}>".format(self.__class__.__name__, dict.__repr__(self))
return f"<{type(self).__name__} {dict.__repr__(self)}>"

View file

@ -88,7 +88,7 @@ class _AppCtxGlobals:
def __repr__(self):
top = _app_ctx_stack.top
if top is not None:
return "<flask.g of %r>" % top.app.name
return f"<flask.g of {top.app.name!r}>"
return object.__repr__(self)
@ -445,9 +445,7 @@ class RequestContext:
self.auto_pop(exc_value)
def __repr__(self):
return "<{} '{}' [{}] of {}>".format(
self.__class__.__name__,
self.request.url,
self.request.method,
self.app.name,
return (
f"<{type(self).__name__} {self.request.url!r}"
f" [{self.request.method}] of {self.app.name}>"
)

View file

@ -29,17 +29,18 @@ class DebugFilesKeyError(KeyError, AssertionError):
def __init__(self, request, key):
form_matches = request.form.getlist(key)
buf = [
'You tried to access the file "%s" in the request.files '
"dictionary but it does not exist. The mimetype for the request "
'is "%s" instead of "multipart/form-data" which means that no '
"file contents were transmitted. To fix this error you should "
'provide enctype="multipart/form-data" in your form.'
% (key, request.mimetype)
f"You tried to access the file {key!r} in the request.files"
" dictionary but it does not exist. The mimetype for the"
f" request is {request.mimetype!r} instead of"
" 'multipart/form-data' which means that no file contents"
" were transmitted. To fix this error you should provide"
' enctype="multipart/form-data" in your form.'
]
if form_matches:
names = ", ".join(repr(x) for x in form_matches)
buf.append(
"\n\nThe browser instead transmitted some file names. "
"This was submitted: %s" % ", ".join('"%s"' % x for x in form_matches)
f"This was submitted: {names}"
)
self.msg = "".join(buf)
@ -56,24 +57,24 @@ class FormDataRoutingRedirect(AssertionError):
def __init__(self, request):
exc = request.routing_exception
buf = [
"A request was sent to this URL (%s) but a redirect was "
'issued automatically by the routing system to "%s".'
% (request.url, exc.new_url)
f"A request was sent to this URL ({request.url}) but a"
" redirect was issued automatically by the routing system"
f" to {exc.new_url!r}."
]
# In case just a slash was appended we can be extra helpful
if request.base_url + "/" == exc.new_url.split("?")[0]:
if f"{request.base_url}/" == exc.new_url.split("?")[0]:
buf.append(
" The URL was defined with a trailing slash so "
"Flask will automatically redirect to the URL "
"with the trailing slash if it was accessed "
"without one."
" The URL was defined with a trailing slash so Flask"
" will automatically redirect to the URL with the"
" trailing slash if it was accessed without one."
)
buf.append(
" Make sure to directly send your %s-request to this URL "
"since we can't make browsers or HTTP clients redirect "
"with form data reliably or without user interaction." % request.method
" Make sure to directly send your"
f" {request.method}-request to this URL since we can't make"
" browsers or HTTP clients redirect with form data reliably"
" or without user interaction."
)
buf.append("\n\nNote: this exception is only raised in debug mode")
AssertionError.__init__(self, "".join(buf).encode("utf-8"))
@ -101,16 +102,16 @@ def attach_enctype_error_multidict(request):
def _dump_loader_info(loader):
yield "class: {}.{}".format(type(loader).__module__, type(loader).__name__)
yield f"class: {type(loader).__module__}.{type(loader).__name__}"
for key, value in sorted(loader.__dict__.items()):
if key.startswith("_"):
continue
if isinstance(value, (tuple, list)):
if not all(isinstance(x, str) for x in value):
continue
yield "%s:" % key
yield f"{key}:"
for item in value:
yield " - %s" % item
yield f" - {item}"
continue
elif not isinstance(value, (str, int, float, bool)):
continue
@ -119,7 +120,7 @@ def _dump_loader_info(loader):
def explain_template_loading_attempts(app, template, attempts):
"""This should help developers understand what failed"""
info = ['Locating template "%s":' % template]
info = [f"Locating template {template!r}:"]
total_found = 0
blueprint = None
reqctx = _request_ctx_stack.top
@ -128,23 +129,23 @@ def explain_template_loading_attempts(app, template, attempts):
for idx, (loader, srcobj, triple) in enumerate(attempts):
if isinstance(srcobj, Flask):
src_info = 'application "%s"' % srcobj.import_name
src_info = f"application {srcobj.import_name!r}"
elif isinstance(srcobj, Blueprint):
src_info = f'blueprint "{srcobj.name}" ({srcobj.import_name})'
src_info = f"blueprint {srcobj.name!r} ({srcobj.import_name})"
else:
src_info = repr(srcobj)
info.append("% 5d: trying loader of %s" % (idx + 1, src_info))
info.append(f"{idx + 1:5}: trying loader of {src_info}")
for line in _dump_loader_info(loader):
info.append(" %s" % line)
info.append(f" {line}")
if triple is None:
detail = "no match"
else:
detail = "found (%r)" % (triple[1] or "<string>")
detail = f"found ({triple[1] or '<string>'!r})"
total_found += 1
info.append(" -> %s" % detail)
info.append(f" -> {detail}")
seems_fishy = False
if total_found == 0:
@ -156,8 +157,8 @@ def explain_template_loading_attempts(app, template, attempts):
if blueprint is not None and seems_fishy:
info.append(
" The template was looked up from an endpoint that "
'belongs to the blueprint "%s".' % blueprint
" The template was looked up from an endpoint that belongs"
f" to the blueprint {blueprint!r}."
)
info.append(" Maybe you did not place a template in the right folder?")
info.append(" See https://flask.palletsprojects.com/blueprints/#templates")
@ -169,11 +170,10 @@ def explain_ignored_app_run():
if os.environ.get("WERKZEUG_RUN_MAIN") != "true":
warn(
Warning(
"Silently ignoring app.run() because the "
"application is run from the flask command line "
"executable. Consider putting app.run() behind an "
'if __name__ == "__main__" guard to silence this '
"warning."
"Silently ignoring app.run() because the application is"
" run from the flask command line executable. Consider"
' putting app.run() behind an if __name__ == "__main__"'
" guard to silence this warning."
),
stacklevel=3,
)

View file

@ -311,7 +311,7 @@ def url_for(endpoint, **values):
if endpoint[:1] == ".":
if blueprint_name is not None:
endpoint = blueprint_name + endpoint
endpoint = f"{blueprint_name}{endpoint}"
else:
endpoint = endpoint[1:]
@ -364,7 +364,7 @@ def url_for(endpoint, **values):
return appctx.app.handle_url_build_error(error, endpoint, values)
if anchor is not None:
rv += "#" + url_quote(anchor)
rv += f"#{url_quote(anchor)}"
return rv
@ -608,11 +608,12 @@ def send_file(
try:
attachment_filename = attachment_filename.encode("ascii")
except UnicodeEncodeError:
quoted = url_quote(attachment_filename, safe="")
filenames = {
"filename": unicodedata.normalize("NFKD", attachment_filename).encode(
"ascii", "ignore"
),
"filename*": "UTF-8''%s" % url_quote(attachment_filename, safe=""),
"filename*": f"UTF-8''{quoted}",
}
else:
filenames = {"filename": attachment_filename}
@ -661,23 +662,19 @@ def send_file(
from warnings import warn
try:
rv.set_etag(
"%s-%s-%s"
% (
os.path.getmtime(filename),
os.path.getsize(filename),
adler32(
filename.encode("utf-8")
if isinstance(filename, str)
else filename
)
& 0xFFFFFFFF,
check = (
adler32(
filename.encode("utf-8") if isinstance(filename, str) else filename
)
& 0xFFFFFFFF
)
rv.set_etag(
f"{os.path.getmtime(filename)}-{os.path.getsize(filename)}-{check}"
)
except OSError:
warn(
"Access %s failed, maybe it does not exist, so ignore etags in "
"headers" % filename,
f"Access {filename} failed, maybe it does not exist, so"
" ignore etags in headers",
stacklevel=2,
)
@ -806,13 +803,12 @@ def get_root_path(import_name):
# first module that is contained in our package.
if filepath is None:
raise RuntimeError(
"No root path can be found for the provided "
'module "%s". This can happen because the '
"module came from an import hook that does "
"not provide file name information or because "
"it's a namespace package. In this case "
"the root path needs to be explicitly "
"provided." % import_name
"No root path can be found for the provided module"
f" {import_name!r}. This can happen because the module"
" came from an import hook that does not provide file"
" name information or because it's a namespace package."
" In this case the root path needs to be explicitly"
" provided."
)
# filepath is import_name.py for a module, or __init__.py for a package.
@ -823,6 +819,7 @@ def _matching_loader_thinks_module_is_package(loader, mod_name):
"""Given the loader that loaded a module and the module this function
attempts to figure out if the given module is actually a package.
"""
cls = type(loader)
# If the loader can tell us if something is a package, we can
# directly ask the loader.
if hasattr(loader, "is_package"):
@ -830,20 +827,13 @@ def _matching_loader_thinks_module_is_package(loader, mod_name):
# importlib's namespace loaders do not have this functionality but
# all the modules it loads are packages, so we can take advantage of
# this information.
elif (
loader.__class__.__module__ == "_frozen_importlib"
and loader.__class__.__name__ == "NamespaceLoader"
):
elif cls.__module__ == "_frozen_importlib" and cls.__name__ == "NamespaceLoader":
return True
# Otherwise we need to fail with an error that explains what went
# wrong.
raise AttributeError(
(
"%s.is_package() method is missing but is required by Flask of "
"PEP 302 import hooks. If you do not use import hooks and "
"you encounter this error please file a bug against Flask."
)
% loader.__class__.__name__
f"{cls.__name__}.is_package() method is missing but is required"
" for PEP 302 import hooks."
)
@ -1014,7 +1004,7 @@ class _PackageBoundObject:
if self.static_folder is not None:
basename = os.path.basename(self.static_folder)
return ("/" + basename).rstrip("/")
return f"/{basename}".rstrip("/")
@static_url_path.setter
def static_url_path(self, value):

View file

@ -364,7 +364,7 @@ def jsonify(*args, **kwargs):
data = args or kwargs
return current_app.response_class(
dumps(data, indent=indent, separators=separators) + "\n",
f"{dumps(data, indent=indent, separators=separators)}\n",
mimetype=current_app.config["JSONIFY_MIMETYPE"],
)

View file

@ -105,7 +105,7 @@ class TagDict(JSONTag):
def to_json(self, value):
key = next(iter(value))
return {key + "__": self.serializer.tag(value[key])}
return {f"{key}__": self.serializer.tag(value[key])}
def to_python(self, value):
key = next(iter(value))

View file

@ -208,13 +208,13 @@ class SessionInterface:
rv = rv.rsplit(":", 1)[0].lstrip(".")
if "." not in rv:
# Chrome doesn't allow names without a '.'
# this should only come up with localhost
# hack around this by not setting the name, and show a warning
# Chrome doesn't allow names without a '.'. This should only
# come up with localhost. Hack around this by not setting
# the name, and show a warning.
warnings.warn(
'"{rv}" is not a valid cookie domain, it must contain a ".".'
" Add an entry to your hosts file, for example"
' "{rv}.localdomain", and use that instead.'.format(rv=rv)
f"{rv!r} is not a valid cookie domain, it must contain"
" a '.'. Add an entry to your hosts file, for example"
f" '{rv}.localdomain', and use that instead."
)
app.config["SESSION_COOKIE_DOMAIN"] = False
return None
@ -232,7 +232,7 @@ class SessionInterface:
# if this is not an ip and app is mounted at the root, allow subdomain
# matching by adding a '.' prefix
if self.get_cookie_path(app) == "/" and not ip:
rv = "." + rv
rv = f".{rv}"
app.config["SESSION_COOKIE_DOMAIN"] = rv
return rv

View file

@ -69,10 +69,9 @@ class EnvironBuilder(werkzeug.test.EnvironBuilder):
url_scheme = app.config["PREFERRED_URL_SCHEME"]
url = url_parse(path)
base_url = "{scheme}://{netloc}/{path}".format(
scheme=url.scheme or url_scheme,
netloc=url.netloc or http_host,
path=app_root.lstrip("/"),
base_url = (
f"{url.scheme or url_scheme}://{url.netloc or http_host}"
f"/{app_root.lstrip('/')}"
)
path = url.path
@ -114,7 +113,7 @@ class FlaskClient(Client):
super().__init__(*args, **kwargs)
self.environ_base = {
"REMOTE_ADDR": "127.0.0.1",
"HTTP_USER_AGENT": "werkzeug/" + werkzeug.__version__,
"HTTP_USER_AGENT": f"werkzeug/{werkzeug.__version__}",
}
@contextmanager

View file

@ -26,7 +26,7 @@ class View:
methods = ['GET']
def dispatch_request(self, name):
return 'Hello %s!' % name
return f"Hello {name}!"
app.add_url_rule('/hello/<name>', view_func=MyView.as_view('myview'))
@ -157,5 +157,5 @@ class MethodView(View, metaclass=MethodViewType):
if meth is None and request.method == "HEAD":
meth = getattr(self, "get", None)
assert meth is not None, "Unimplemented method %r" % request.method
assert meth is not None, f"Unimplemented method {request.method!r}"
return meth(*args, **kwargs)