Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
镜像
Python_Packaging_Authority
pip
提交
06a3406a
P
pip
项目概览
镜像
/
Python_Packaging_Authority
/
pip
12 个月 前同步成功
通知
0
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
P
pip
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
未验证
提交
06a3406a
编写于
3月 18, 2020
作者:
P
Pradyun Gedam
提交者:
GitHub
3月 18, 2020
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #7861 from uranusjr/resolver-implement
Implement resolver methods on provider interface
上级
e5375aff
dad77a9e
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
188 addition
and
3 deletion
+188
-3
src/pip/_internal/resolution/resolvelib/resolver.py
src/pip/_internal/resolution/resolvelib/resolver.py
+107
-3
tests/unit/resolution_resolvelib/test_resolver.py
tests/unit/resolution_resolvelib/test_resolver.py
+81
-0
未找到文件。
src/pip/_internal/resolution/resolvelib/resolver.py
浏览文件 @
06a3406a
import
functools
from
pip._vendor.packaging.utils
import
canonicalize_name
from
pip._vendor.resolvelib
import
BaseReporter
from
pip._vendor.resolvelib
import
Resolver
as
RLResolver
from
pip._internal.resolution.base
import
BaseResolver
from
pip._internal.utils.typing
import
MYPY_CHECK_RUNNING
if
MYPY_CHECK_RUNNING
:
from
typing
import
List
,
Optional
,
Tuple
from
typing
import
Dict
,
List
,
Optional
,
Tuple
from
pip._vendor.resolvelib.resolvers
import
Result
from
pip._internal.index.package_finder
import
PackageFinder
from
pip._internal.operations.prepare
import
RequirementPreparer
...
...
@@ -10,6 +18,29 @@ if MYPY_CHECK_RUNNING:
from
pip._internal.req.req_set
import
RequirementSet
from
pip._internal.resolution.base
import
InstallRequirementProvider
from
.base
import
Candidate
,
Requirement
# FIXME: Import the actual implementation.
# This is a stub to pass typing checks.
class
PipProvider
(
object
):
def
__init__
(
self
,
finder
,
# type: PackageFinder
preparer
,
# type: RequirementPreparer
make_install_req
,
# type: InstallRequirementProvider
):
# type: (...) -> None
super
(
PipProvider
,
self
).
__init__
()
def
make_requirement
(
self
,
r
):
# type: (InstallRequirement) -> Requirement
raise
NotImplementedError
()
def
get_install_requirement
(
self
,
c
):
# type: (Candidate) -> InstallRequirement
raise
NotImplementedError
()
class
Resolver
(
BaseResolver
):
def
__init__
(
...
...
@@ -26,11 +57,84 @@ class Resolver(BaseResolver):
py_version_info
=
None
,
# type: Optional[Tuple[int, ...]]
):
super
(
Resolver
,
self
).
__init__
()
self
.
finder
=
finder
self
.
preparer
=
preparer
self
.
make_install_req
=
make_install_req
self
.
_result
=
None
# type: Optional[Result]
def
resolve
(
self
,
root_reqs
,
check_supported_wheels
):
# type: (List[InstallRequirement], bool) -> RequirementSet
raise
NotImplementedError
()
provider
=
PipProvider
(
self
.
finder
,
self
.
preparer
,
self
.
make_install_req
,
)
reporter
=
BaseReporter
()
resolver
=
RLResolver
(
provider
,
reporter
)
requirements
=
[
provider
.
make_requirement
(
r
)
for
r
in
root_reqs
]
self
.
_result
=
resolver
.
resolve
(
requirements
)
req_set
=
RequirementSet
(
check_supported_wheels
=
check_supported_wheels
)
for
candidate
in
self
.
_result
.
mapping
.
values
():
ireq
=
provider
.
get_install_requirement
(
candidate
)
req_set
.
add_named_requirement
(
ireq
)
return
req_set
def
get_installation_order
(
self
,
req_set
):
# type: (RequirementSet) -> List[InstallRequirement]
raise
NotImplementedError
()
"""Create a list that orders given requirements for installation.
The returned list should contain all requirements in ``req_set``,
so the caller can loop through it and have a requirement installed
before the requiring thing.
The current implementation walks the resolved dependency graph, and
make sure every node has a greater "weight" than all its parents.
"""
assert
self
.
_result
is
not
None
,
"must call resolve() first"
weights
=
{}
# type: Dict[Optional[str], int]
graph
=
self
.
_result
.
graph
key_count
=
len
(
self
.
_result
.
mapping
)
+
1
# Packages plus sentinal.
while
len
(
weights
)
<
key_count
:
progressed
=
False
for
key
in
graph
:
if
key
in
weights
:
continue
parents
=
list
(
graph
.
iter_parents
(
key
))
if
not
all
(
p
in
weights
for
p
in
parents
):
continue
if
parents
:
weight
=
max
(
weights
[
p
]
for
p
in
parents
)
+
1
else
:
weight
=
0
weights
[
key
]
=
weight
progressed
=
True
# FIXME: This check will fail if there are unbreakable cycles.
# Implement something to forcifully break them up to continue.
assert
progressed
,
"Order calculation stuck in dependency loop."
sorted_items
=
sorted
(
req_set
.
requirements
.
items
(),
key
=
functools
.
partial
(
_req_set_item_sorter
,
weights
=
weights
),
reverse
=
True
,
)
return
[
ireq
for
_
,
ireq
in
sorted_items
]
def
_req_set_item_sorter
(
item
,
# type: Tuple[str, InstallRequirement]
weights
,
# type: Dict[Optional[str], int]
):
# type: (...) -> Tuple[int, str]
"""Key function used to sort install requirements for installation.
Based on the "weight" mapping calculated in ``get_installation_order()``.
The canonical package name is returned as the second member as a tie-
breaker to ensure the result is predictable, which is useful in tests.
"""
name
=
canonicalize_name
(
item
[
0
])
return
weights
[
name
],
name
tests/unit/resolution_resolvelib/test_resolver.py
0 → 100644
浏览文件 @
06a3406a
import
mock
import
pytest
from
pip._vendor.packaging.utils
import
canonicalize_name
from
pip._vendor.resolvelib.resolvers
import
Result
from
pip._vendor.resolvelib.structs
import
DirectedGraph
from
pip._internal.req.constructors
import
install_req_from_line
from
pip._internal.req.req_set
import
RequirementSet
from
pip._internal.resolution.resolvelib.resolver
import
Resolver
@
pytest
.
fixture
()
def
resolver
(
preparer
,
finder
):
resolver
=
Resolver
(
preparer
=
preparer
,
finder
=
finder
,
make_install_req
=
mock
.
Mock
(),
use_user_site
=
"not-used"
,
ignore_dependencies
=
"not-used"
,
ignore_installed
=
"not-used"
,
ignore_requires_python
=
"not-used"
,
force_reinstall
=
"not-used"
,
upgrade_strategy
=
"not-used"
,
)
return
resolver
@
pytest
.
mark
.
parametrize
(
"edges, ordered_reqs"
,
[
(
[(
None
,
"require-simple"
),
(
"require-simple"
,
"simple"
)],
[
"simple==3.0"
,
"require-simple==1.0"
],
),
(
[(
None
,
"meta"
),
(
"meta"
,
"simple"
),
(
"meta"
,
"simple2"
)],
[
"simple2==3.0"
,
"simple==3.0"
,
"meta==1.0"
],
),
(
[
(
None
,
"toporequires"
),
(
None
,
"toporequire2"
),
(
None
,
"toporequire3"
),
(
None
,
"toporequire4"
),
(
"toporequires2"
,
"toporequires"
),
(
"toporequires3"
,
"toporequires"
),
(
"toporequires4"
,
"toporequires"
),
(
"toporequires4"
,
"toporequires2"
),
(
"toporequires4"
,
"toporequires3"
),
],
[
"toporequires==0.0.1"
,
"toporequires3==0.0.1"
,
"toporequires2==0.0.1"
,
"toporequires4==0.0.1"
,
],
),
],
)
def
test_rlr_resolver_get_installation_order
(
resolver
,
edges
,
ordered_reqs
):
# Build graph from edge declarations.
graph
=
DirectedGraph
()
for
parent
,
child
in
edges
:
parent
=
canonicalize_name
(
parent
)
if
parent
else
None
child
=
canonicalize_name
(
child
)
if
child
else
None
for
v
in
(
parent
,
child
):
if
v
not
in
graph
:
graph
.
add
(
v
)
graph
.
connect
(
parent
,
child
)
# Mapping values and criteria are not used in test, so we stub them out.
mapping
=
{
vertex
:
None
for
vertex
in
graph
if
vertex
is
not
None
}
resolver
.
_result
=
Result
(
mapping
,
graph
,
criteria
=
None
)
reqset
=
RequirementSet
()
for
r
in
ordered_reqs
:
reqset
.
add_named_requirement
(
install_req_from_line
(
r
))
ireqs
=
resolver
.
get_installation_order
(
reqset
)
req_strs
=
[
str
(
r
.
req
)
for
r
in
ireqs
]
assert
req_strs
==
ordered_reqs
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录