Repository: pallets/werkzeug

Issue:
deprecate utils.format_string
It appears to do exactly what `string.Template` does.


Discussion:
I would be glad to help with this.
You're welcome to work on issues, no need to ask first. The deprecation warning should be something like `'format_string' is deprecated and will be removed in 2.1. Use 'string.Template' instead.` There's a few places the function is used internally which should be replaced with `string.Template`, as well as the implementation itself.
Okay, I will get to it and write a PR in the next few days.

Resolving patch:
diff --git a/src/werkzeug/routing.py b/src/werkzeug/routing.py
--- a/src/werkzeug/routing.py
+++ b/src/werkzeug/routing.py
@@ -101,6 +101,7 @@
 import uuid
 import warnings
 from pprint import pformat
+from string import Template
 from threading import Lock
 
 from ._internal import _encode_idna
@@ -120,7 +121,6 @@
 from .urls import url_join
 from .urls import url_quote
 from .utils import cached_property
-from .utils import format_string
 from .utils import redirect
 from .wsgi import get_host
 
@@ -473,15 +473,15 @@ def get_rules(self, map):
                     new_defaults = {}
                     for key, value in rule.defaults.items():
                         if isinstance(value, str):
-                            value = format_string(value, self.context)
+                            value = Template(value).substitute(self.context)
                         new_defaults[key] = value
                 if rule.subdomain is not None:
-                    subdomain = format_string(rule.subdomain, self.context)
+                    subdomain = Template(rule.subdomain).substitute(self.context)
                 new_endpoint = rule.endpoint
                 if isinstance(new_endpoint, str):
-                    new_endpoint = format_string(new_endpoint, self.context)
+                    new_endpoint = Template(new_endpoint).substitute(self.context)
                 yield Rule(
-                    format_string(rule.rule, self.context),
+                    Template(rule.rule).substitute(self.context),
                     new_defaults,
                     subdomain,
                     rule.methods,
diff --git a/src/werkzeug/utils.py b/src/werkzeug/utils.py
--- a/src/werkzeug/utils.py
+++ b/src/werkzeug/utils.py
@@ -14,13 +14,13 @@
 import pkgutil
 import re
 import sys
+import warnings
 from html.entities import name2codepoint
 
 from ._internal import _DictAccessorProperty
 from ._internal import _missing
 from ._internal import _parse_signature
 
-_format_re = re.compile(r"\$(?:([a-zA-Z_][a-zA-Z0-9_]*)|\{([a-zA-Z_][a-zA-Z0-9_]*)\})")
 _entity_re = re.compile(r"&([^;]+);")
 _filename_ascii_strip_re = re.compile(r"[^A-Za-z0-9_.-]")
 _windows_device_files = (
@@ -355,20 +355,23 @@ def format_string(string, context):
     >>> format_string('$foo and ${foo}s', dict(foo=42))
     '42 and 42s'
 
-    This does not do any attribute lookup etc.  For more advanced string
-    formattings have a look at the `werkzeug.template` module.
+    This does not do any attribute lookup.
 
     :param string: the format string.
     :param context: a dict with the variables to insert.
-    """
 
-    def lookup_arg(match):
-        x = context[match.group(1) or match.group(2)]
-        if not isinstance(x, str):
-            x = type(string)(x)
-        return x
+    .. deprecated:: 2.0
+        Will be removed in 2.1. Use :class:`string.Template` instead.
+    """
+    from string import Template
 
-    return _format_re.sub(lookup_arg, string)
+    warnings.warn(
+        "'utils.format_string' is deprecated and will be removed in"
+        " 2.1. Use 'string.Template' instead.",
+        DeprecationWarning,
+        stacklevel=2,
+    )
+    return Template(string).substitute(context)
 
 
 def secure_filename(filename):


Test patch: