Skip to content

Commit

Permalink
Handle (*) constraint for pre-release only packages
Browse files Browse the repository at this point in the history
This change ensures that packages that only have a pre-release versions
are pragmatically discovered via `find_packages` when a constraint (*)
is specified.

Resolves: #2819
  • Loading branch information
abn committed Aug 17, 2020
1 parent 0d48fb6 commit ff3fa62
Show file tree
Hide file tree
Showing 8 changed files with 220 additions and 14 deletions.
36 changes: 24 additions & 12 deletions poetry/repositories/legacy_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,8 @@ def find_packages(
if not constraint.is_any():
key = "{}:{}".format(key, str(constraint))

ignored_pre_release_versions = []

if self._cache.store("matches").has(key):
versions = self._cache.store("matches").get(key)
else:
Expand All @@ -256,28 +258,38 @@ def find_packages(
versions = []
for version in page.versions:
if version.is_prerelease() and not allow_prereleases:
if constraint.is_any():
# we need this when all versions of the package are pre-releases
ignored_pre_release_versions.append(version)
continue

if constraint.allows(version):
versions.append(version)

self._cache.store("matches").put(key, versions, 5)

for version in versions:
package = Package(name, version)
package.source_type = "legacy"
package.source_reference = self.name
package.source_url = self._url
for package_versions in (versions, ignored_pre_release_versions):
for version in package_versions:
package = Package(name, version)
package.source_type = "legacy"
package.source_reference = self.name
package.source_url = self._url

if extras is not None:
package.requires_extras = extras
if extras is not None:
package.requires_extras = extras

packages.append(package)
packages.append(package)

self._log(
"{} packages found for {} {}".format(len(packages), name, str(constraint)),
level="debug",
)
self._log(
"{} packages found for {} {}".format(
len(packages), name, str(constraint)
),
level="debug",
)

if packages or not constraint.is_any():
# we have matching packages, or constraint is not (*)
break

return packages

Expand Down
6 changes: 5 additions & 1 deletion poetry/repositories/pypi_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ def find_packages(
return []

packages = []
ignored_pre_release_packages = []

for version, release in info["releases"].items():
if not release:
Expand All @@ -138,6 +139,9 @@ def find_packages(
continue

if package.is_prerelease() and not allow_prereleases:
if constraint.is_any():
# we need this when all versions of the package are pre-releases
ignored_pre_release_packages.append(package)
continue

if not constraint or (constraint and constraint.allows(package.version)):
Expand All @@ -151,7 +155,7 @@ def find_packages(
level="debug",
)

return packages
return packages or ignored_pre_release_packages

def package(
self,
Expand Down
7 changes: 6 additions & 1 deletion poetry/repositories/repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ def find_packages(
):
name = name.lower()
packages = []
ignored_pre_release_packages = []

if extras is None:
extras = []

Expand Down Expand Up @@ -71,6 +73,9 @@ def find_packages(
):
# If prereleases are not allowed and the package is a prerelease
# and is a standard package then we skip it
if constraint.is_any():
# we need this when all versions of the package are pre-releases
ignored_pre_release_packages.append(package)
continue

if constraint.allows(package.version):
Expand All @@ -89,7 +94,7 @@ def find_packages(

packages.append(package)

return packages
return packages or ignored_pre_release_packages

def has_package(self, package):
package_id = package.unique_name
Expand Down
10 changes: 10 additions & 0 deletions tests/repositories/fixtures/legacy/black.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<title>Links for black</title></head>
<body>
<h1>Links for black</h1>
<a href="https://files.pythonhosted.org/packages/b0/dc/ecd83b973fb7b82c34d828aad621a6e5865764d52375b8ac1d7a45e23c8d/black-19.10b0.tar.gz#sha256=c2edb73a08e9e0e6f65a0e6af18b059b8b1cdd5bef997d7a0b181df93dc81539" data-requires-python=">=3.6">black-19.10b0.tar.gz</a>
</body>
</html>
<!--SERIAL 6044498-->
Binary file not shown.
146 changes: 146 additions & 0 deletions tests/repositories/fixtures/pypi.org/json/black.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
{
"info": {
"author": "\u0141ukasz Langa",
"author_email": "lukasz@langa.pl",
"bugtrack_url": null,
"classifiers": [
"Development Status :: 4 - Beta",
"Environment :: Console",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3 :: Only",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Software Development :: Quality Assurance"
],
"description": "",
"description_content_type": "text/markdown",
"docs_url": null,
"download_url": "",
"downloads": {
"last_day": -1,
"last_month": -1,
"last_week": -1
},
"home_page": "https://github.com/psf/black",
"keywords": "automation formatter yapf autopep8 pyfmt gofmt rustfmt",
"license": "MIT",
"maintainer": "",
"maintainer_email": "",
"name": "black",
"package_url": "https://pypi.org/project/black/",
"platform": "",
"project_url": "https://pypi.org/project/black/",
"project_urls": {
"Homepage": "https://github.com/psf/black"
},
"release_url": "https://pypi.org/project/black/19.10b0/",
"requires_dist": [
"click (>=6.5)",
"attrs (>=18.1.0)",
"appdirs",
"toml (>=0.9.4)",
"typed-ast (>=1.4.0)",
"regex",
"pathspec (<1,>=0.6)",
"aiohttp (>=3.3.2) ; extra == 'd'",
"aiohttp-cors ; extra == 'd'"
],
"requires_python": ">=3.6",
"summary": "The uncompromising code formatter.",
"version": "19.10b0",
"yanked": false,
"yanked_reason": null
},
"last_serial": 6044498,
"releases": {
"19.10b0": [
{
"comment_text": "",
"digests": {
"md5": "067efd0498107b5fb2299fbfb000b0b6",
"sha256": "1b30e59be925fafc1ee4565e5e08abef6b03fe455102883820fe5ee2e4734e0b"
},
"downloads": -1,
"filename": "black-19.10b0-py36-none-any.whl",
"has_sig": true,
"md5_digest": "067efd0498107b5fb2299fbfb000b0b6",
"packagetype": "bdist_wheel",
"python_version": "py36",
"requires_python": ">=3.6",
"size": 97525,
"upload_time": "2019-10-28T23:53:54",
"upload_time_iso_8601": "2019-10-28T23:53:54.000711Z",
"url": "https://files.pythonhosted.org/packages/fd/bb/ad34bbc93d1bea3de086d7c59e528d4a503ac8fe318bd1fa48605584c3d2/black-19.10b0-py36-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"md5": "496632a95b73b8f5c5081d795a4e6af1",
"sha256": "c2edb73a08e9e0e6f65a0e6af18b059b8b1cdd5bef997d7a0b181df93dc81539"
},
"downloads": -1,
"filename": "black-19.10b0.tar.gz",
"has_sig": true,
"md5_digest": "496632a95b73b8f5c5081d795a4e6af1",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.6",
"size": 1019740,
"upload_time": "2019-10-28T23:54:05",
"upload_time_iso_8601": "2019-10-28T23:54:05.455213Z",
"url": "https://files.pythonhosted.org/packages/b0/dc/ecd83b973fb7b82c34d828aad621a6e5865764d52375b8ac1d7a45e23c8d/black-19.10b0.tar.gz",
"yanked": false,
"yanked_reason": null
}
]
},
"urls": [
{
"comment_text": "",
"digests": {
"md5": "067efd0498107b5fb2299fbfb000b0b6",
"sha256": "1b30e59be925fafc1ee4565e5e08abef6b03fe455102883820fe5ee2e4734e0b"
},
"downloads": -1,
"filename": "black-19.10b0-py36-none-any.whl",
"has_sig": true,
"md5_digest": "067efd0498107b5fb2299fbfb000b0b6",
"packagetype": "bdist_wheel",
"python_version": "py36",
"requires_python": ">=3.6",
"size": 97525,
"upload_time": "2019-10-28T23:53:54",
"upload_time_iso_8601": "2019-10-28T23:53:54.000711Z",
"url": "https://files.pythonhosted.org/packages/fd/bb/ad34bbc93d1bea3de086d7c59e528d4a503ac8fe318bd1fa48605584c3d2/black-19.10b0-py36-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"md5": "496632a95b73b8f5c5081d795a4e6af1",
"sha256": "c2edb73a08e9e0e6f65a0e6af18b059b8b1cdd5bef997d7a0b181df93dc81539"
},
"downloads": -1,
"filename": "black-19.10b0.tar.gz",
"has_sig": true,
"md5_digest": "496632a95b73b8f5c5081d795a4e6af1",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.6",
"size": 1019740,
"upload_time": "2019-10-28T23:54:05",
"upload_time_iso_8601": "2019-10-28T23:54:05.455213Z",
"url": "https://files.pythonhosted.org/packages/b0/dc/ecd83b973fb7b82c34d828aad621a6e5865764d52375b8ac1d7a45e23c8d/black-19.10b0.tar.gz",
"yanked": false,
"yanked_reason": null
}
]
}
21 changes: 21 additions & 0 deletions tests/repositories/test_legacy_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,27 @@ def test_find_packages_no_prereleases():
assert packages[0].source_url == repo.url


@pytest.mark.parametrize("constraint,count", [("*", 1), (">=1", 0), (">=19.0.0a0", 1)])
def test_find_packages_only_prereleases(constraint, count):
repo = MockRepository()
packages = repo.find_packages("black", constraint=constraint)

assert len(packages) == count

if count >= 0:
for package in packages:
assert package.source_type == "legacy"
assert package.source_reference == repo.name
assert package.source_url == repo.url


def test_find_packages_only_prereleases_empty_when_not_any():
repo = MockRepository()
packages = repo.find_packages("black", constraint=">=1")

assert len(packages) == 0


def test_get_package_information_chooses_correct_distribution():
repo = MockRepository()

Expand Down
8 changes: 8 additions & 0 deletions tests/repositories/test_pypi_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,14 @@ def test_find_packages_does_not_select_prereleases_if_not_allowed():
assert len(packages) == 1


@pytest.mark.parametrize("constraint,count", [("*", 1), (">=1", 0), (">=19.0.0a0", 1)])
def test_find_packages_only_prereleases(constraint, count):
repo = MockRepository()
packages = repo.find_packages("black", constraint=constraint)

assert len(packages) == count


def test_package():
repo = MockRepository()

Expand Down

0 comments on commit ff3fa62

Please sign in to comment.