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
d22c5a71
Unverified
Commit
d22c5a71
authored
May 10, 2022
by
Tom Solberg
Committed by
GitHub
May 10, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
cmd/show: add --why option (#5444)
parent
5840ac5d
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
221 additions
and
12 deletions
+221
-12
docs/cli.md
+1
-0
src/poetry/console/commands/show.py
+105
-12
tests/console/commands/test_show.py
+115
-0
No files found.
docs/cli.md
View file @
d22c5a71
...
@@ -439,6 +439,7 @@ required by
...
@@ -439,6 +439,7 @@ required by
### Options
### Options
*
`--without`
: The dependency groups to ignore.
*
`--without`
: The dependency groups to ignore.
*
`--why`
: Include reverse dependencies where applicable.
*
`--with`
: The optional dependency groups to include.
*
`--with`
: The optional dependency groups to include.
*
`--only`
: The only dependency groups to include.
*
`--only`
: The only dependency groups to include.
*
`--default`
: Only include the main dependencies. (
**Deprecated**
)
*
`--default`
: Only include the main dependencies. (
**Deprecated**
)
...
...
src/poetry/console/commands/show.py
View file @
d22c5a71
...
@@ -22,6 +22,17 @@ if TYPE_CHECKING:
...
@@ -22,6 +22,17 @@ if TYPE_CHECKING:
from
poetry.repositories.repository
import
Repository
from
poetry.repositories.repository
import
Repository
def
reverse_deps
(
pkg
:
Package
,
repo
:
Repository
)
->
dict
[
str
,
str
]:
required_by
=
{}
for
locked
in
repo
.
packages
:
dependencies
=
{
d
.
name
:
d
.
pretty_constraint
for
d
in
locked
.
requires
}
if
pkg
.
name
in
dependencies
:
required_by
[
locked
.
pretty_name
]
=
dependencies
[
pkg
.
name
]
return
required_by
class
ShowCommand
(
GroupCommand
):
class
ShowCommand
(
GroupCommand
):
name
=
"show"
name
=
"show"
...
@@ -36,6 +47,11 @@ class ShowCommand(GroupCommand):
...
@@ -36,6 +47,11 @@ class ShowCommand(GroupCommand):
"Do not list the development dependencies. (<warning>Deprecated</warning>)"
,
"Do not list the development dependencies. (<warning>Deprecated</warning>)"
,
),
),
option
(
"tree"
,
"t"
,
"List the dependencies as a tree."
),
option
(
"tree"
,
"t"
,
"List the dependencies as a tree."
),
option
(
"why"
,
None
,
"When listing the tree for a single package, start from parents."
,
),
option
(
"latest"
,
"l"
,
"Show the latest version."
),
option
(
"latest"
,
"l"
,
"Show the latest version."
),
option
(
option
(
"outdated"
,
"outdated"
,
...
@@ -69,6 +85,23 @@ lists all packages available."""
...
@@ -69,6 +85,23 @@ lists all packages available."""
if
self
.
option
(
"tree"
):
if
self
.
option
(
"tree"
):
self
.
init_styles
(
self
.
io
)
self
.
init_styles
(
self
.
io
)
if
self
.
option
(
"why"
):
if
self
.
option
(
"tree"
)
and
package
is
None
:
self
.
line_error
(
"<error>Error: --why requires a package when combined with"
" --tree.</error>"
)
return
1
if
not
self
.
option
(
"tree"
)
and
package
:
self
.
line_error
(
"<error>Error: --why cannot be used without --tree when displaying"
" a single package.</error>"
)
return
1
if
self
.
option
(
"outdated"
):
if
self
.
option
(
"outdated"
):
self
.
_io
.
input
.
set_option
(
"latest"
,
True
)
self
.
_io
.
input
.
set_option
(
"latest"
,
True
)
...
@@ -83,7 +116,7 @@ lists all packages available."""
...
@@ -83,7 +116,7 @@ lists all packages available."""
root
=
self
.
project_with_activated_groups_only
()
root
=
self
.
project_with_activated_groups_only
()
# Show tree view if requested
# Show tree view if requested
if
self
.
option
(
"tree"
)
and
not
packag
e
:
if
self
.
option
(
"tree"
)
and
package
is
Non
e
:
requires
=
root
.
all_requires
requires
=
root
.
all_requires
packages
=
locked_repo
.
packages
packages
=
locked_repo
.
packages
for
p
in
packages
:
for
p
in
packages
:
...
@@ -121,17 +154,38 @@ lists all packages available."""
...
@@ -121,17 +154,38 @@ lists all packages available."""
if
not
pkg
:
if
not
pkg
:
raise
ValueError
(
f
"Package {package} not found"
)
raise
ValueError
(
f
"Package {package} not found"
)
required_by
=
reverse_deps
(
pkg
,
locked_repo
)
if
self
.
option
(
"tree"
):
if
self
.
option
(
"tree"
):
self
.
display_package_tree
(
self
.
io
,
pkg
,
locked_repo
)
if
self
.
option
(
"why"
):
# The default case if there's no reverse dependencies is to query
# the subtree for pkg but if any rev-deps exist we'll query for each
# of them in turn
packages
=
[
pkg
]
if
required_by
:
packages
=
[
p
for
p
in
locked_packages
for
r
in
required_by
.
keys
()
if
p
.
name
==
r
]
else
:
# if no rev-deps exist we'll make this clear as it can otherwise
# look very odd for packages that also have no or few direct
# dependencies
self
.
_io
.
write_line
(
f
"Package {package} is a direct dependency."
)
return
0
for
p
in
packages
:
self
.
display_package_tree
(
self
.
_io
,
p
,
locked_repo
,
why_package
=
pkg
)
required_by
=
{}
else
:
for
locked
in
locked_packages
:
self
.
display_package_tree
(
self
.
_io
,
pkg
,
locked_repo
)
dependencies
=
{
d
.
name
:
d
.
pretty_constraint
for
d
in
locked
.
requires
}
if
pkg
.
name
in
dependencies
:
return
0
required_by
[
locked
.
pretty_name
]
=
dependencies
[
pkg
.
name
]
rows
=
[
rows
=
[
[
"<info>name</>"
,
f
" : <c1>{pkg.pretty_name}</>"
],
[
"<info>name</>"
,
f
" : <c1>{pkg.pretty_name}</>"
],
...
@@ -163,7 +217,7 @@ lists all packages available."""
...
@@ -163,7 +217,7 @@ lists all packages available."""
show_all
=
self
.
option
(
"all"
)
show_all
=
self
.
option
(
"all"
)
terminal
=
Terminal
()
terminal
=
Terminal
()
width
=
terminal
.
width
width
=
terminal
.
width
name_length
=
version_length
=
latest_length
=
0
name_length
=
version_length
=
latest_length
=
required_by_length
=
0
latest_packages
=
{}
latest_packages
=
{}
latest_statuses
=
{}
latest_statuses
=
{}
installed_repo
=
InstalledRepository
.
load
(
self
.
env
)
installed_repo
=
InstalledRepository
.
load
(
self
.
env
)
...
@@ -208,6 +262,13 @@ lists all packages available."""
...
@@ -208,6 +262,13 @@ lists all packages available."""
)
)
),
),
)
)
if
self
.
option
(
"why"
):
required_by
=
reverse_deps
(
locked
,
locked_repo
)
required_by_length
=
max
(
required_by_length
,
len
(
" from "
+
","
.
join
(
required_by
.
keys
())),
)
else
:
else
:
name_length
=
max
(
name_length
,
current_length
)
name_length
=
max
(
name_length
,
current_length
)
version_length
=
max
(
version_length
=
max
(
...
@@ -219,9 +280,20 @@ lists all packages available."""
...
@@ -219,9 +280,20 @@ lists all packages available."""
),
),
)
)
if
self
.
option
(
"why"
):
required_by
=
reverse_deps
(
locked
,
locked_repo
)
required_by_length
=
max
(
required_by_length
,
len
(
" from "
+
","
.
join
(
required_by
.
keys
()))
)
write_version
=
name_length
+
version_length
+
3
<=
width
write_version
=
name_length
+
version_length
+
3
<=
width
write_latest
=
name_length
+
version_length
+
latest_length
+
3
<=
width
write_latest
=
name_length
+
version_length
+
latest_length
+
3
<=
width
write_description
=
name_length
+
version_length
+
latest_length
+
24
<=
width
why_end_column
=
(
name_length
+
version_length
+
latest_length
+
required_by_length
)
write_why
=
self
.
option
(
"why"
)
and
(
why_end_column
+
3
)
<=
width
write_description
=
(
why_end_column
+
24
)
<=
width
for
locked
in
locked_packages
:
for
locked
in
locked_packages
:
color
=
"cyan"
color
=
"cyan"
...
@@ -273,9 +345,21 @@ lists all packages available."""
...
@@ -273,9 +345,21 @@ lists all packages available."""
)
)
line
+=
f
" <fg={color}>{version:{latest_length}}</>"
line
+=
f
" <fg={color}>{version:{latest_length}}</>"
if
write_why
:
required_by
=
reverse_deps
(
locked
,
locked_repo
)
if
required_by
:
content
=
","
.
join
(
required_by
.
keys
())
# subtract 6 for ' from '
line
+=
f
" from {content:{required_by_length - 6}}"
else
:
line
+=
" "
*
required_by_length
if
write_description
:
if
write_description
:
description
=
locked
.
description
description
=
locked
.
description
remaining
=
width
-
name_length
-
version_length
-
4
remaining
=
(
width
-
name_length
-
version_length
-
required_by_length
-
4
)
if
show_latest
:
if
show_latest
:
remaining
-=
latest_length
remaining
-=
latest_length
...
@@ -285,10 +369,15 @@ lists all packages available."""
...
@@ -285,10 +369,15 @@ lists all packages available."""
line
+=
" "
+
description
line
+=
" "
+
description
self
.
line
(
line
)
self
.
line
(
line
)
return
None
return
None
def
display_package_tree
(
def
display_package_tree
(
self
,
io
:
IO
,
package
:
Package
,
installed_repo
:
Repository
self
,
io
:
IO
,
package
:
Package
,
installed_repo
:
Repository
,
why_package
:
Package
|
None
=
None
,
)
->
None
:
)
->
None
:
io
.
write
(
f
"<c1>{package.pretty_name}</c1>"
)
io
.
write
(
f
"<c1>{package.pretty_name}</c1>"
)
description
=
""
description
=
""
...
@@ -297,11 +386,15 @@ lists all packages available."""
...
@@ -297,11 +386,15 @@ lists all packages available."""
io
.
write_line
(
f
" <b>{package.pretty_version}</b>{description}"
)
io
.
write_line
(
f
" <b>{package.pretty_version}</b>{description}"
)
if
why_package
is
not
None
:
dependencies
=
[
p
for
p
in
package
.
requires
if
p
.
name
==
why_package
.
name
]
else
:
dependencies
=
package
.
requires
dependencies
=
package
.
requires
dependencies
=
sorted
(
dependencies
=
sorted
(
dependencies
,
dependencies
,
key
=
lambda
x
:
x
.
name
,
# type: ignore[no-any-return]
key
=
lambda
x
:
x
.
name
,
# type: ignore[no-any-return]
)
)
tree_bar
=
"├"
tree_bar
=
"├"
total
=
len
(
dependencies
)
total
=
len
(
dependencies
)
for
i
,
dependency
in
enumerate
(
dependencies
,
1
):
for
i
,
dependency
in
enumerate
(
dependencies
,
1
):
...
...
tests/console/commands/test_show.py
View file @
d22c5a71
...
@@ -1686,6 +1686,121 @@ cachy 0.2.0
...
@@ -1686,6 +1686,121 @@ cachy 0.2.0
assert
tester
.
io
.
fetch_output
()
==
expected
assert
tester
.
io
.
fetch_output
()
==
expected
def
test_show_tree_why_package
(
tester
:
CommandTester
,
poetry
:
Poetry
,
installed
:
Repository
):
poetry
.
package
.
add_dependency
(
Factory
.
create_dependency
(
"a"
,
"=0.0.1"
))
a
=
get_package
(
"a"
,
"0.0.1"
)
installed
.
add_package
(
a
)
a
.
add_dependency
(
Factory
.
create_dependency
(
"b"
,
"=0.0.1"
))
b
=
get_package
(
"b"
,
"0.0.1"
)
a
.
add_dependency
(
Factory
.
create_dependency
(
"c"
,
"=0.0.1"
))
installed
.
add_package
(
b
)
c
=
get_package
(
"c"
,
"0.0.1"
)
installed
.
add_package
(
c
)
poetry
.
locker
.
mock_lock_data
(
{
"package"
:
[
{
"name"
:
"a"
,
"version"
:
"0.0.1"
,
"dependencies"
:
{
"b"
:
"=0.0.1"
},
"python-versions"
:
"*"
,
"optional"
:
False
,
},
{
"name"
:
"b"
,
"version"
:
"0.0.1"
,
"dependencies"
:
{
"c"
:
"=0.0.1"
},
"python-versions"
:
"*"
,
"optional"
:
False
,
},
{
"name"
:
"c"
,
"version"
:
"0.0.1"
,
"python-versions"
:
"*"
,
"optional"
:
False
,
},
],
"metadata"
:
{
"python-versions"
:
"*"
,
"platform"
:
"*"
,
"content-hash"
:
"123456789"
,
"hashes"
:
{
"a"
:
[],
"b"
:
[],
"c"
:
[]},
},
}
)
tester
.
execute
(
"--tree --why b"
)
expected
=
"""
\
a 0.0.1
└── b =0.0.1
└── c =0.0.1
\n
"""
assert
tester
.
io
.
fetch_output
()
==
expected
def
test_show_tree_why
(
tester
:
CommandTester
,
poetry
:
Poetry
,
installed
:
Repository
):
poetry
.
package
.
add_dependency
(
Factory
.
create_dependency
(
"a"
,
"=0.0.1"
))
a
=
get_package
(
"a"
,
"0.0.1"
)
installed
.
add_package
(
a
)
a
.
add_dependency
(
Factory
.
create_dependency
(
"b"
,
"=0.0.1"
))
b
=
get_package
(
"b"
,
"0.0.1"
)
a
.
add_dependency
(
Factory
.
create_dependency
(
"c"
,
"=0.0.1"
))
installed
.
add_package
(
b
)
c
=
get_package
(
"c"
,
"0.0.1"
)
installed
.
add_package
(
c
)
poetry
.
locker
.
mock_lock_data
(
{
"package"
:
[
{
"name"
:
"a"
,
"version"
:
"0.0.1"
,
"dependencies"
:
{
"b"
:
"=0.0.1"
},
"python-versions"
:
"*"
,
"optional"
:
False
,
},
{
"name"
:
"b"
,
"version"
:
"0.0.1"
,
"dependencies"
:
{
"c"
:
"=0.0.1"
},
"python-versions"
:
"*"
,
"optional"
:
False
,
},
{
"name"
:
"c"
,
"version"
:
"0.0.1"
,
"python-versions"
:
"*"
,
"optional"
:
False
,
},
],
"metadata"
:
{
"python-versions"
:
"*"
,
"platform"
:
"*"
,
"content-hash"
:
"123456789"
,
"hashes"
:
{
"a"
:
[],
"b"
:
[],
"c"
:
[]},
},
}
)
tester
.
execute
(
"--why"
)
# this has to be on a single line due to the padding whitespace, which gets stripped
# by pre-commit.
expected
=
"""a 0.0.1
\n
b 0.0.1 from a
\n
c 0.0.1 from b
\n
"""
assert
tester
.
io
.
fetch_output
()
==
expected
def
test_show_required_by_deps
(
def
test_show_required_by_deps
(
tester
:
CommandTester
,
poetry
:
Poetry
,
installed
:
Repository
tester
:
CommandTester
,
poetry
:
Poetry
,
installed
:
Repository
):
):
...
...
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