diff --git a/docs/usage.rst b/docs/usage.rst
index e41f93a7..eecd993f 100644
--- a/docs/usage.rst
+++ b/docs/usage.rst
@@ -589,7 +589,7 @@ Check PyPI
source = "pypi"
-Check `PyPI `_ for updates.
+Check `PyPI `_ for updates. Yanked releases are ignored.
pypi
The name used on PyPI, e.g. ``PySide``.
@@ -683,7 +683,7 @@ Check crates.io
source = "cratesio"
-Check `crates.io `_ for updates.
+Check `crates.io `_ for updates. Yanked releases are ignored.
cratesio
The crate name on crates.io, e.g. ``tokio``.
diff --git a/nvchecker_source/pypi.py b/nvchecker_source/pypi.py
index 8cf04354..2237eec4 100644
--- a/nvchecker_source/pypi.py
+++ b/nvchecker_source/pypi.py
@@ -19,6 +19,10 @@ async def get_version(name, conf, *, cache, **kwargs):
data = await cache.get_json(url)
for version in data['releases'].keys():
+ # Skip versions that are marked as yanked.
+ if (vers := data['releases'][version]) and vers[0]['yanked']:
+ continue
+
try:
parsed_version = Version(version)
except InvalidVersion:
diff --git a/setup.cfg b/setup.cfg
index 2d757f42..00c3c6e3 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -39,10 +39,10 @@ classifiers =
[options]
zip_safe = True
+python_requires = >=3.8
packages = find_namespace:
install_requires =
- setuptools; python_version<"3.8"
tomli; python_version<"3.11"
structlog
platformdirs
diff --git a/tests/test_pypi.py b/tests/test_pypi.py
index 1d6643c5..d5a5d8ab 100644
--- a/tests/test_pypi.py
+++ b/tests/test_pypi.py
@@ -32,3 +32,8 @@ async def test_pypi_invalid_version(get_version):
"source": "pypi",
})
+async def test_pypi_yanked_version(get_version):
+ assert await get_version("urllib3", {
+ "source": "pypi",
+ "include_regex": "^(1\\..*)|(2\\.0\\.[0,1])",
+ }) == "1.26.20"