diff --git a/pytools/__init__.py b/pytools/__init__.py
index bb7994c0a70285f19836a6f1065c8ae794cf4c37..ec878b57659ff92db73ad5c67361ed8817097007 100644
--- a/pytools/__init__.py
+++ b/pytools/__init__.py
@@ -25,6 +25,7 @@ THE SOFTWARE.
 """
 
 
+import re
 from functools import reduce, wraps
 import operator
 import sys
@@ -163,6 +164,11 @@ Sorting in natural order
 .. autofunction:: natorder
 .. autofunction:: natsorted
 
+Backports of newer Python functionality
+---------------------------------------
+
+.. autofunction:: resolve_name
+
 Type Variables Used
 -------------------
 
@@ -2543,6 +2549,62 @@ def natsorted(iterable, key=None, reverse=False):
 # }}}
 
 
+# {{{ resolve_name
+
+# https://github.com/python/cpython/commit/1ed61617a4a6632905ad6a0b440cd2cafb8b6414
+
+_DOTTED_WORDS = r"[a-z_]\w*(\.[a-z_]\w*)*"
+_NAME_PATTERN = re.compile(f"^({_DOTTED_WORDS})(:({_DOTTED_WORDS})?)?$", re.I)
+del _DOTTED_WORDS
+
+
+def resolve_name(name):
+    """A backport of :func:`pkgutil.resolve_name` (added in Python 3.9).
+
+    .. versionadded:: 2021.1.2
+    """
+    # Delete the tail of the function and deprecate this once we require Python 3.9.
+    if sys.version_info >= (3, 9):
+        # use the official version
+        import pkgutil
+        return pkgutil.resolve_name(name)  # pylint: disable=no-member
+
+    import importlib
+
+    m = _NAME_PATTERN.match(name)
+    if not m:
+        raise ValueError(f"invalid format: {name!r}")
+    groups = m.groups()
+    if groups[2]:
+        # there is a colon - a one-step import is all that's needed
+        mod = importlib.import_module(groups[0])
+        parts = groups[3].split(".") if groups[3] else []
+    else:
+        # no colon - have to iterate to find the package boundary
+        parts = name.split(".")
+        modname = parts.pop(0)
+        # first part *must* be a module/package.
+        mod = importlib.import_module(modname)
+        while parts:
+            p = parts[0]
+            s = f"{modname}.{p}"
+            try:
+                mod = importlib.import_module(s)
+                parts.pop(0)
+                modname = s
+            except ImportError:
+                break
+    # if we reach this point, mod is the module, already imported, and
+    # parts is the list of parts in the object hierarchy to be traversed, or
+    # an empty list if just the module is wanted.
+    result = mod
+    for p in parts:
+        result = getattr(result, p)
+    return result
+
+# }}}
+
+
 def _test():
     import doctest
     doctest.testmod()
diff --git a/pytools/version.py b/pytools/version.py
index 2d25ff45eabb27341762df1c288ac7a149e00b13..8b36d4f9e9fce9d4f7b324fbb69d561f854d7a36 100644
--- a/pytools/version.py
+++ b/pytools/version.py
@@ -1,3 +1,3 @@
-VERSION = (2021, 1, 1)
+VERSION = (2021, 1, 2)
 VERSION_STATUS = ""
 VERSION_TEXT = ".".join(str(x) for x in VERSION) + VERSION_STATUS