diff --git a/meta/classes-recipe/pypi.bbclass b/meta/classes-recipe/pypi.bbclass
index 08788fcb9a9..e45e3115305 100644
--- a/meta/classes-recipe/pypi.bbclass
+++ b/meta/classes-recipe/pypi.bbclass
@@ -7,28 +7,37 @@
 def pypi_default_package(d):
     """
     Return a reasonable guess for the PyPI package name by
-    stripping any python- prefix from PN.
+    stripping any python- prefix from PN and normalising it.
     """
     bpn = d.getVar('BPN')
     if bpn.startswith('python-'):
-        return bpn[7:]
+        return pypi_package_normalise(bpn[7:])
     elif bpn.startswith('python3-'):
-        return bpn[8:]
-    return bpn
+        return pypi_package_normalise(bpn[8:])
+    return pypi_package_normalise(bpn)
 
-# The PyPi package name (defaults to PN without the python3- prefix)
+# The PyPI package name, normalised as per
+# https://packaging.python.org/en/latest/specifications/name-normalization/.
+# Defaults to BPN without a python3- prefix.
 PYPI_PACKAGE ?= "${@pypi_default_package(d)}"
+
+# The name of the sdist. This defaults to the normalised name with underscores as per
+# https://packaging.python.org/en/latest/specifications/source-distribution-format/,
+# but can be overridden if needed.
+PYPI_PACKAGE_SDIST ?= "${@d.getVar("PYPI_PACKAGE").replace("-", "_")}"
+
 # The file extension of the source archive
 PYPI_PACKAGE_EXT ?= "tar.gz"
+
 # An optional prefix for the download file in the case of name collisions
 PYPI_ARCHIVE_NAME_PREFIX ?= ""
 
 def pypi_src_uri(d):
     """
-    Construct a source URL as per https://warehouse.pypa.io/api-reference/integration-guide.html#predictable-urls.
+    Construct a source URL as per https://docs.pypi.org/api/#predictable-urls.
     """
-    package = d.getVar('PYPI_PACKAGE')
-    archive_name = d.expand('${PYPI_PACKAGE}-${PV}.${PYPI_PACKAGE_EXT}')
+    package = d.getVar('PYPI_PACKAGE_SDIST')
+    archive_name = d.expand('${PYPI_PACKAGE_SDIST}-${PV}.${PYPI_PACKAGE_EXT}')
     url = 'https://files.pythonhosted.org/packages/source/%s/%s/%s' % (package[0], package, archive_name)
 
     download_prefix = d.getVar("PYPI_ARCHIVE_NAME_PREFIX")
@@ -37,34 +46,30 @@ def pypi_src_uri(d):
 
     return url
 
-def pypi_normalize(d):
-    """"
-    Normalize the package names to match PEP625 (https://peps.python.org/pep-0625/).
-    """
-    import re
-    return re.sub(r"[-_.]+", "-", d.getVar('PYPI_PACKAGE')).lower()
-
 PYPI_SRC_URI ?= "${@pypi_src_uri(d)}"
 
 HOMEPAGE ?= "https://pypi.python.org/pypi/${PYPI_PACKAGE}/"
 SECTION = "devel/python"
 SRC_URI:prepend = "${PYPI_SRC_URI} "
-S = "${UNPACKDIR}/${PYPI_PACKAGE}-${PV}"
+S = "${UNPACKDIR}/${PYPI_PACKAGE_SDIST}-${PV}"
 
-def pypi_normalize_regex(d):
-    # Use a regex wildcard instead of hyphen as the filenames
-    # may or may not have been normalised properly.
-    return pypi_normalize(d).replace("-", "[_-]")
-
-# Use the simple repository API rather than the potentially unstable project URL
-# More information on the pypi API specification is avaialble here:
+# More information on the PyPI API specification is available here:
 # https://packaging.python.org/en/latest/specifications/simple-repository-api/
 #
-# NOTE: All URLs for the simple API MUST request canonical normalized URLs per the spec
-UPSTREAM_CHECK_URI ?= "https://pypi.org/simple/${@pypi_normalize(d)}/"
-UPSTREAM_CHECK_REGEX ?= "(?i)${@pypi_normalize_regex(d)}-(?P<pver>(\d+(\.[\d\-]+)*(\.post\d+)?))\.(tar\.gz|tgz|zip|tar\.bz2)"
+# Use a case-insensitive regex wildcard instead of hyphen as the filenames may
+# or may not have been normalised.
+UPSTREAM_CHECK_URI ?= "https://pypi.org/simple/${PYPI_PACKAGE}/"
+UPSTREAM_CHECK_REGEX ?= "(?i)${@d.getVar("PYPI_PACKAGE").replace("-", "[_-]")}-(?P<pver>(\d+(\.[\d\-]+)*(\.post\d+)?))\.(tar\.gz|tgz|zip|tar\.bz2)"
 
 CVE_PRODUCT ?= "python:${PYPI_PACKAGE}"
 
 # Generate ecosystem-specific Package URL for SPDX
-SPDX_PACKAGE_URLS =+ "pkg:pypi/${@pypi_normalize(d)}@${PV} "
+SPDX_PACKAGE_URLS =+ "pkg:pypi/${PYPI_PACKAGE}@${PV} "
+
+def pypi_package_normalise(s):
+    """
+    Normalise the passed package name as per
+    https://packaging.python.org/en/latest/specifications/name-normalization/
+    """
+    import re
+    return re.sub(r"[-_.]+", "-", s).lower()
