Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
P
python-poetry
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
open
python-poetry
Commits
5d69edd7
Unverified
Commit
5d69edd7
authored
Jun 03, 2018
by
Sébastien Eustace
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix handling of duplicate dependencies with same constraint
parent
906f8360
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
274 additions
and
31 deletions
+274
-31
CHANGELOG.md
+1
-0
poetry/mixology/version_solver.py
+3
-0
poetry/puzzle/provider.py
+92
-28
poetry/puzzle/solver.py
+21
-3
tests/installation/fixtures/with-pypi-repository.test
+10
-0
tests/puzzle/test_solver.py
+26
-0
tests/repositories/fixtures/pypi.org/json/setuptools.json
+121
-0
No files found.
CHANGELOG.md
View file @
5d69edd7
...
@@ -8,6 +8,7 @@
...
@@ -8,6 +8,7 @@
-
Fixed
`self:update`
not picking up new versions.
-
Fixed
`self:update`
not picking up new versions.
-
Fixed a
`RuntimeError`
on Python 3.7.
-
Fixed a
`RuntimeError`
on Python 3.7.
-
Fixed bad version number being picked with private repositories.
-
Fixed bad version number being picked with private repositories.
-
Fixed handling of duplicate dependencies with same constraint.
## [0.10.2] - 2018-05-31
## [0.10.2] - 2018-05-31
...
...
poetry/mixology/version_solver.py
View file @
5d69edd7
...
@@ -374,6 +374,9 @@ class VersionSolver:
...
@@ -374,6 +374,9 @@ class VersionSolver:
return
dependency
.
name
return
dependency
.
name
if
not
version
.
is_root
():
version
=
self
.
_provider
.
complete_package
(
version
)
conflict
=
False
conflict
=
False
for
incompatibility
in
self
.
_provider
.
incompatibilities_for
(
version
):
for
incompatibility
in
self
.
_provider
.
incompatibilities_for
(
version
):
self
.
_add_incompatibility
(
incompatibility
)
self
.
_add_incompatibility
(
incompatibility
)
...
...
poetry/puzzle/provider.py
View file @
5d69edd7
...
@@ -264,12 +264,10 @@ class Provider:
...
@@ -264,12 +264,10 @@ class Provider:
won't return incompatibilities that have already been returned by a
won't return incompatibilities that have already been returned by a
previous call to _incompatibilities_for().
previous call to _incompatibilities_for().
"""
"""
if
package
.
source_type
in
[
"git"
,
"file"
,
"directory"
]:
if
package
.
is_root
():
dependencies
=
package
.
requires
elif
package
.
is_root
():
dependencies
=
package
.
all_requires
dependencies
=
package
.
all_requires
else
:
else
:
dependencies
=
self
.
_dependencies_for
(
package
)
dependencies
=
package
.
requires
if
not
self
.
_package
.
python_constraint
.
allows_any
(
package
.
python_constraint
):
if
not
self
.
_package
.
python_constraint
.
allows_any
(
package
.
python_constraint
):
return
[
return
[
...
@@ -295,41 +293,107 @@ class Provider:
...
@@ -295,41 +293,107 @@ class Provider:
for
dep
in
dependencies
for
dep
in
dependencies
]
]
def
dependencies_for
(
def
complete_package
(
self
,
package
):
# type: (str, Version) -> Package
self
,
package
if
package
.
is_root
()
or
package
.
source_type
in
{
"git"
,
"file"
,
"directory"
}:
):
# type: (Package) -> Union[List[Dependency], Dependencies]
return
package
if
package
.
source_type
in
[
"git"
,
"file"
,
"directory"
]:
# Information should already be set
return
[
r
for
r
in
package
.
requires
if
not
r
.
is_activated
()
and
r
.
name
not
in
self
.
UNSAFE_PACKAGES
]
else
:
return
Dependencies
(
package
,
self
)
def
_dependencies_for
(
self
,
package
):
# type: (Package) -> List[Dependency]
package
=
self
.
_pool
.
package
(
complete_package
=
self
.
_pool
.
package
(
package
.
name
,
package
.
version
.
text
,
extras
=
package
.
requires_extras
package
.
name
,
package
.
version
.
text
,
extras
=
package
.
requires_extras
)
)
# Update package with new information
dependencies
=
[
package
.
requires
=
complete_package
.
requires
package
.
description
=
complete_package
.
description
package
.
python_versions
=
complete_package
.
python_versions
package
.
platform
=
complete_package
.
platform
package
.
hashes
=
complete_package
.
hashes
package
.
extras
=
complete_package
.
extras
return
[
r
r
for
r
in
package
.
requires
for
r
in
package
.
requires
if
r
.
is_activated
()
if
r
.
is_activated
()
and
self
.
_package
.
python_constraint
.
allows_any
(
r
.
python_constraint
)
and
self
.
_package
.
python_constraint
.
allows_any
(
r
.
python_constraint
)
and
self
.
_package
.
platform_constraint
.
matches
(
package
.
platform_constraint
)
and
self
.
_package
.
platform_constraint
.
matches
(
package
.
platform_constraint
)
and
r
.
name
not
in
self
.
UNSAFE_PACKAGES
]
]
# Searching for duplicate dependencies
#
# If the duplicate dependencies have the same constraint,
# the requirements will be merged.
#
# For instance:
# - enum34; python_version=="2.7"
# - enum34; python_version=="3.3"
#
# will become:
# - enum34; python_version=="2.7" or python_version=="3.3"
#
# TODO: If the duplicate dependencies have different constraints
# we should notify the resolver in some way to make it split the
# current graph.
#
# An example of this is:
# - pypiwin32 (220); sys_platform == "win32" and python_version >= "3.6"
# - pypiwin32 (219); sys_platform == "win32" and python_version < "3.6"
if
not
package
.
is_root
():
duplicates
=
{}
for
dep
in
dependencies
:
if
dep
.
name
not
in
duplicates
:
duplicates
[
dep
.
name
]
=
[]
duplicates
[
dep
.
name
]
.
append
(
dep
)
dependencies
=
[]
for
dep_name
,
deps
in
duplicates
.
items
():
if
len
(
deps
)
==
1
:
dependencies
.
append
(
deps
[
0
])
continue
# Regrouping by constraint
by_constraint
=
{}
for
dep
in
deps
:
if
dep
.
constraint
not
in
by_constraint
:
by_constraint
[
dep
.
constraint
]
=
[]
by_constraint
[
dep
.
constraint
]
.
append
(
dep
)
# We merge by constraint
for
constraint
,
_deps
in
by_constraint
.
items
():
new_markers
=
[]
for
dep
in
_deps
:
pep_508_dep
=
dep
.
to_pep_508
()
if
";"
not
in
pep_508_dep
:
continue
markers
=
pep_508_dep
.
split
(
";"
)[
1
]
.
strip
()
new_markers
.
append
(
"({})"
.
format
(
markers
))
if
not
new_markers
:
dependencies
+=
_deps
continue
dep
=
_deps
[
0
]
new_requirement
=
"{}; {}"
.
format
(
dep
.
to_pep_508
()
.
split
(
";"
)[
0
],
" or "
.
join
(
new_markers
)
)
new_dep
=
dependency_from_pep_508
(
new_requirement
)
if
dep
.
is_optional
()
and
not
dep
.
is_activated
():
new_dep
.
deactivate
()
else
:
new_dep
.
activate
()
by_constraint
[
constraint
]
=
[
new_dep
]
continue
if
len
(
by_constraint
)
==
1
:
dependencies
.
append
(
list
(
by_constraint
.
values
())[
0
][
0
])
continue
# At this point, we have one dependency by constraint
# So we add them to the dependency set
for
constraint
,
_deps
in
by_constraint
.
items
():
_dep
=
_deps
[
0
]
dependencies
.
append
(
_dep
)
package
.
requires
=
dependencies
return
package
# UI
# UI
@property
@property
...
...
poetry/puzzle/solver.py
View file @
5d69edd7
...
@@ -39,9 +39,9 @@ class Solver:
...
@@ -39,9 +39,9 @@ class Solver:
packages
=
result
.
packages
packages
=
result
.
packages
requested
=
self
.
_package
.
all_requires
requested
=
self
.
_package
.
all_requires
graph
=
self
.
_build_graph
(
self
.
_package
,
packages
)
for
package
in
packages
:
for
package
in
packages
:
graph
=
self
.
_build_graph
(
self
.
_package
,
packages
)
category
,
optional
,
python
,
platform
=
self
.
_get_tags_for_package
(
category
,
optional
,
python
,
platform
=
self
.
_get_tags_for_package
(
package
,
graph
package
,
graph
)
)
...
@@ -163,10 +163,28 @@ class Solver:
...
@@ -163,10 +163,28 @@ class Solver:
for
pkg
in
packages
:
for
pkg
in
packages
:
if
pkg
.
name
==
dependency
.
name
:
if
pkg
.
name
==
dependency
.
name
:
graph
[
"children"
]
.
append
(
# If there is already a child with this name
self
.
_build_graph
(
pkg
,
packages
,
dependency
,
dep
or
dependency
)
# we merge the requirements
existing
=
None
for
child
in
graph
[
"children"
]:
if
child
[
"name"
]
==
pkg
.
name
:
existing
=
child
continue
child_graph
=
self
.
_build_graph
(
pkg
,
packages
,
dependency
,
dep
or
dependency
)
)
if
existing
:
existing
[
"python_version"
]
=
str
(
parse_constraint
(
existing
[
"python_version"
])
.
union
(
parse_constraint
(
child_graph
[
"python_version"
])
)
)
continue
graph
[
"children"
]
.
append
(
child_graph
)
return
graph
return
graph
def
_get_tags_for_package
(
self
,
package
,
graph
):
def
_get_tags_for_package
(
self
,
package
,
graph
):
...
...
tests/installation/fixtures/with-pypi-repository.test
View file @
5d69edd7
...
@@ -81,6 +81,15 @@ funcsigs = "*"
...
@@ -81,6 +81,15 @@ funcsigs = "*"
colorama
=
"*"
colorama
=
"*"
[[
package
]]
[[
package
]]
name
=
"setuptools"
version
=
"39.2.0"
description
=
"Easily download, build, install, upgrade, and uninstall Python packages"
category
=
"dev"
optional
=
false
python
-
versions
=
">=2.7,!=3.0.*,!=3.1.*,!=3.2.*"
platform
=
"*"
[[
package
]]
name
=
"six"
name
=
"six"
version
=
"1.11.0"
version
=
"1.11.0"
description
=
"Python 2 and 3 compatibility utilities"
description
=
"Python 2 and 3 compatibility utilities"
...
@@ -102,4 +111,5 @@ more-itertools = [ "11a625025954c20145b37ff6309cd54e39ca94f72f6bb9576d1195db6fa2
...
@@ -102,4 +111,5 @@ more-itertools = [ "11a625025954c20145b37ff6309cd54e39ca94f72f6bb9576d1195db6fa2
pluggy
=
[
"7f8ae7f5bdf75671a718d2daf0a64b7885f74510bcd98b1a0bb420eb9a9d0cff"
,]
pluggy
=
[
"7f8ae7f5bdf75671a718d2daf0a64b7885f74510bcd98b1a0bb420eb9a9d0cff"
,]
py
=
[
"983f77f3331356039fdd792e9220b7b8ee1aa6bd2b25f567a963ff1de5a64f6a"
,
"29c9fab495d7528e80ba1e343b958684f4ace687327e6f789a94bf3d1915f881"
,]
py
=
[
"983f77f3331356039fdd792e9220b7b8ee1aa6bd2b25f567a963ff1de5a64f6a"
,
"29c9fab495d7528e80ba1e343b958684f4ace687327e6f789a94bf3d1915f881"
,]
pytest
=
[
"6266f87ab64692112e5477eba395cfedda53b1933ccd29478e671e73b420c19c"
,
"fae491d1874f199537fd5872b5e1f0e74a009b979df9d53d1553fd03da1703e1"
,]
pytest
=
[
"6266f87ab64692112e5477eba395cfedda53b1933ccd29478e671e73b420c19c"
,
"fae491d1874f199537fd5872b5e1f0e74a009b979df9d53d1553fd03da1703e1"
,]
setuptools
=
[
"8fca9275c89964f13da985c3656cb00ba029d7f3916b37990927ffdf264e7926"
,
"f7cddbb5f5c640311eb00eab6e849f7701fa70bf6a183fc8a2c33dd1d1672fb2"
,]
six
=
[
"832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb"
,
"70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9"
,]
six
=
[
"832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb"
,
"70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9"
,]
tests/puzzle/test_solver.py
View file @
5d69edd7
...
@@ -759,3 +759,29 @@ def test_solver_circular_dependency(solver, repo, package):
...
@@ -759,3 +759,29 @@ def test_solver_circular_dependency(solver, repo, package):
{
"job"
:
"install"
,
"package"
:
package_a
},
{
"job"
:
"install"
,
"package"
:
package_a
},
],
],
)
)
def
test_solver_duplicate_dependencies_same_constraint
(
solver
,
repo
,
package
):
package
.
add_dependency
(
"A"
)
package_a
=
get_package
(
"A"
,
"1.0"
)
package_a
.
add_dependency
(
"B"
,
{
"version"
:
"^1.0"
,
"python"
:
"2.7"
})
package_a
.
add_dependency
(
"B"
,
{
"version"
:
"^1.0"
,
"python"
:
">=3.4"
})
package_b
=
get_package
(
"B"
,
"1.0"
)
repo
.
add_package
(
package_a
)
repo
.
add_package
(
package_b
)
ops
=
solver
.
solve
()
check_solver_result
(
ops
,
[
{
"job"
:
"install"
,
"package"
:
package_b
},
{
"job"
:
"install"
,
"package"
:
package_a
},
],
)
op
=
ops
[
0
]
assert
op
.
package
.
requirements
==
{
"python"
:
"~2.7 || >=3.4"
}
tests/repositories/fixtures/pypi.org/json/setuptools.json
0 → 100644
View file @
5d69edd7
{
"info"
:
{
"author"
:
"Python Packaging Authority"
,
"author_email"
:
"distutils-sig@python.org"
,
"bugtrack_url"
:
""
,
"classifiers"
:
[
"Development Status :: 5 - Production/Stable"
,
"Intended Audience :: Developers"
,
"License :: OSI Approved :: MIT License"
,
"Operating System :: OS Independent"
,
"Programming Language :: Python :: 2"
,
"Programming Language :: Python :: 2.7"
,
"Programming Language :: Python :: 3"
,
"Programming Language :: Python :: 3.3"
,
"Programming Language :: Python :: 3.4"
,
"Programming Language :: Python :: 3.5"
,
"Programming Language :: Python :: 3.6"
,
"Topic :: Software Development :: Libraries :: Python Modules"
,
"Topic :: System :: Archiving :: Packaging"
,
"Topic :: System :: Systems Administration"
,
"Topic :: Utilities"
],
"description"
:
""
,
"description_content_type"
:
"text/x-rst; charset=UTF-8"
,
"docs_url"
:
null
,
"download_url"
:
""
,
"downloads"
:
{
"last_day"
:
-1
,
"last_month"
:
-1
,
"last_week"
:
-1
},
"home_page"
:
"https://github.com/pypa/setuptools"
,
"keywords"
:
"CPAN PyPI distutils eggs package management"
,
"license"
:
""
,
"maintainer"
:
""
,
"maintainer_email"
:
""
,
"name"
:
"setuptools"
,
"package_url"
:
"https://pypi.org/project/setuptools/"
,
"platform"
:
""
,
"project_url"
:
"https://pypi.org/project/setuptools/"
,
"release_url"
:
"https://pypi.org/project/setuptools/39.2.0/"
,
"requires_dist"
:
[
"wincertstore (==0.2); (sys_platform=='win32') and extra == 'ssl'"
,
"certifi (==2016.9.26); extra == 'certs'"
],
"requires_python"
:
">=2.7,!=3.0.*,!=3.1.*,!=3.2.*"
,
"summary"
:
"Easily download, build, install, upgrade, and uninstall Python packages"
,
"version"
:
"39.2.0"
},
"last_serial"
:
3879671
,
"releases"
:
{
"39.2.0"
:
[
{
"comment_text"
:
""
,
"digests"
:
{
"md5"
:
"8d066d2201311ed30be535b473e32fed"
,
"sha256"
:
"8fca9275c89964f13da985c3656cb00ba029d7f3916b37990927ffdf264e7926"
},
"downloads"
:
-1
,
"filename"
:
"setuptools-39.2.0-py2.py3-none-any.whl"
,
"has_sig"
:
false
,
"md5_digest"
:
"8d066d2201311ed30be535b473e32fed"
,
"packagetype"
:
"bdist_wheel"
,
"python_version"
:
"py2.py3"
,
"size"
:
567556
,
"upload_time"
:
"2018-05-19T19:19:22"
,
"url"
:
"https://files.pythonhosted.org/packages/7f/e1/820d941153923aac1d49d7fc37e17b6e73bfbd2904959fffbad77900cf92/setuptools-39.2.0-py2.py3-none-any.whl"
},
{
"comment_text"
:
""
,
"digests"
:
{
"md5"
:
"dd4e3fa83a21bf7bf9c51026dc8a4e59"
,
"sha256"
:
"f7cddbb5f5c640311eb00eab6e849f7701fa70bf6a183fc8a2c33dd1d1672fb2"
},
"downloads"
:
-1
,
"filename"
:
"setuptools-39.2.0.zip"
,
"has_sig"
:
false
,
"md5_digest"
:
"dd4e3fa83a21bf7bf9c51026dc8a4e59"
,
"packagetype"
:
"sdist"
,
"python_version"
:
"source"
,
"size"
:
851112
,
"upload_time"
:
"2018-05-19T19:19:24"
,
"url"
:
"https://files.pythonhosted.org/packages/1a/04/d6f1159feaccdfc508517dba1929eb93a2854de729fa68da9d5c6b48fa00/setuptools-39.2.0.zip"
}
]
},
"urls"
:
[
{
"comment_text"
:
""
,
"digests"
:
{
"md5"
:
"8d066d2201311ed30be535b473e32fed"
,
"sha256"
:
"8fca9275c89964f13da985c3656cb00ba029d7f3916b37990927ffdf264e7926"
},
"downloads"
:
-1
,
"filename"
:
"setuptools-39.2.0-py2.py3-none-any.whl"
,
"has_sig"
:
false
,
"md5_digest"
:
"8d066d2201311ed30be535b473e32fed"
,
"packagetype"
:
"bdist_wheel"
,
"python_version"
:
"py2.py3"
,
"size"
:
567556
,
"upload_time"
:
"2018-05-19T19:19:22"
,
"url"
:
"https://files.pythonhosted.org/packages/7f/e1/820d941153923aac1d49d7fc37e17b6e73bfbd2904959fffbad77900cf92/setuptools-39.2.0-py2.py3-none-any.whl"
},
{
"comment_text"
:
""
,
"digests"
:
{
"md5"
:
"dd4e3fa83a21bf7bf9c51026dc8a4e59"
,
"sha256"
:
"f7cddbb5f5c640311eb00eab6e849f7701fa70bf6a183fc8a2c33dd1d1672fb2"
},
"downloads"
:
-1
,
"filename"
:
"setuptools-39.2.0.zip"
,
"has_sig"
:
false
,
"md5_digest"
:
"dd4e3fa83a21bf7bf9c51026dc8a4e59"
,
"packagetype"
:
"sdist"
,
"python_version"
:
"source"
,
"size"
:
851112
,
"upload_time"
:
"2018-05-19T19:19:24"
,
"url"
:
"https://files.pythonhosted.org/packages/1a/04/d6f1159feaccdfc508517dba1929eb93a2854de729fa68da9d5c6b48fa00/setuptools-39.2.0.zip"
}
]
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment