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
2cc78814
Unverified
Commit
2cc78814
authored
Mar 07, 2018
by
Sébastien Eustace
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix extra installation
parent
4891cd25
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
196 additions
and
23 deletions
+196
-23
README.md
+4
-4
poetry/installation/installer.py
+47
-17
poetry/poetry.py
+7
-0
poetry/puzzle/solver.py
+2
-2
tests/fixtures/sample_project/pyproject.toml
+6
-0
tests/installation/fixtures/extras-with-dependencies.test
+52
-0
tests/installation/test_installer.py
+76
-0
tests/test_poetry.py
+2
-0
No files found.
README.md
View file @
2cc78814
...
@@ -248,7 +248,7 @@ the `--no-dev` option.
...
@@ -248,7 +248,7 @@ the `--no-dev` option.
poetry install
--no-dev
poetry install
--no-dev
```
```
You can also specify the extra
feature
s you want installed
You can also specify the extras you want installed
by passing the
`--E|--extras`
option (See
[
Extras
](
#extras
)
for more info)
by passing the
`--E|--extras`
option (See
[
Extras
](
#extras
)
for more info)
```
bash
```
bash
...
@@ -259,7 +259,7 @@ poetry install -E mysql -E pgsql
...
@@ -259,7 +259,7 @@ poetry install -E mysql -E pgsql
#### Options
#### Options
*
`--no-dev`
: Do not install dev dependencies.
*
`--no-dev`
: Do not install dev dependencies.
*
`-
f|--feature
s`
: Features to install (multiple values allowed).
*
`-
E|--extra
s`
: Features to install (multiple values allowed).
### update
### update
...
@@ -635,7 +635,7 @@ name = "awesome"
...
@@ -635,7 +635,7 @@ name = "awesome"
mandatory
=
"^1.0"
mandatory
=
"^1.0"
# A list of all of the optional dependencies, some of which are included in the
# A list of all of the optional dependencies, some of which are included in the
#
above `feature
s`. They can be opted into by apps.
#
below `extra
s`. They can be opted into by apps.
psycopg2
=
{
version
=
"^2.7"
,
optional
=
true
}
psycopg2
=
{
version
=
"^2.7"
,
optional
=
true
}
mysqlclient
=
{
version
=
"^1.3"
,
optional
=
true
}
mysqlclient
=
{
version
=
"^1.3"
,
optional
=
true
}
...
@@ -644,7 +644,7 @@ mysql = ["mysqlclient"]
...
@@ -644,7 +644,7 @@ mysql = ["mysqlclient"]
pgsql
=
["psycopg2"]
pgsql
=
["psycopg2"]
```
```
When installing packages, you can specify
feature
s by using the
`-E|--extras`
option:
When installing packages, you can specify
extra
s by using the
`-E|--extras`
option:
```
bash
```
bash
poet install
--extras
"mysql pgsql"
poet install
--extras
"mysql pgsql"
...
...
poetry/installation/installer.py
View file @
2cc78814
...
@@ -183,7 +183,7 @@ class Installer:
...
@@ -183,7 +183,7 @@ class Installer:
# We need to filter operations so that packages
# We need to filter operations so that packages
# not compatible with the current system,
# not compatible with the current system,
# or optional and not requested, are dropped
# or optional and not requested, are dropped
self
.
_filter_operations
(
ops
)
self
.
_filter_operations
(
ops
,
local_repo
)
self
.
_io
.
new_line
()
self
.
_io
.
new_line
()
...
@@ -336,12 +336,11 @@ class Installer:
...
@@ -336,12 +336,11 @@ class Installer:
)
->
List
[
Operation
]:
)
->
List
[
Operation
]:
installed_repo
=
InstalledRepository
.
load
(
self
.
_io
.
venv
)
installed_repo
=
InstalledRepository
.
load
(
self
.
_io
.
venv
)
ops
=
[]
ops
=
[]
extras
=
[]
for
extra_name
,
packages
in
self
.
_locker
.
lock_data
.
get
(
'extras'
)
.
items
():
if
extra_name
in
self
.
_extras
:
for
package
in
packages
:
extras
.
append
(
package
.
lower
())
extra_packages
=
[
p
.
name
for
p
in
self
.
_get_extra_packages
(
locked_repository
)
]
for
locked
in
locked_repository
.
packages
:
for
locked
in
locked_repository
.
packages
:
is_installed
=
False
is_installed
=
False
for
installed
in
installed_repo
.
packages
:
for
installed
in
installed_repo
.
packages
:
...
@@ -349,7 +348,7 @@ class Installer:
...
@@ -349,7 +348,7 @@ class Installer:
is_installed
=
True
is_installed
=
True
if
locked
.
category
==
'dev'
and
not
self
.
is_dev_mode
():
if
locked
.
category
==
'dev'
and
not
self
.
is_dev_mode
():
ops
.
append
(
Uninstall
(
locked
))
ops
.
append
(
Uninstall
(
locked
))
elif
locked
.
is_optional
()
and
locked
.
name
not
in
extra
s
:
elif
locked
.
optional
and
locked
.
name
not
in
extra_package
s
:
# Installed but optional and not requested in extras
# Installed but optional and not requested in extras
ops
.
append
(
Uninstall
(
locked
))
ops
.
append
(
Uninstall
(
locked
))
elif
locked
.
version
!=
installed
.
version
:
elif
locked
.
version
!=
installed
.
version
:
...
@@ -360,14 +359,16 @@ class Installer:
...
@@ -360,14 +359,16 @@ class Installer:
if
not
is_installed
:
if
not
is_installed
:
# If it's optional and not in required extras
# If it's optional and not in required extras
# we do not install
# we do not install
if
locked
.
is_optional
()
and
locked
.
name
not
in
extra
s
:
if
locked
.
optional
and
locked
.
name
not
in
extra_package
s
:
continue
continue
ops
.
append
(
Install
(
locked
))
ops
.
append
(
Install
(
locked
))
return
ops
return
ops
def
_filter_operations
(
self
,
ops
:
List
[
Operation
]):
def
_filter_operations
(
self
,
ops
:
List
[
Operation
],
repo
:
Repository
)
->
None
:
extra_packages
=
[
p
.
name
for
p
in
self
.
_get_extra_packages
(
repo
)]
for
op
in
ops
:
for
op
in
ops
:
if
isinstance
(
op
,
Update
):
if
isinstance
(
op
,
Update
):
package
=
op
.
target_package
package
=
op
.
target_package
...
@@ -394,20 +395,49 @@ class Installer:
...
@@ -394,20 +395,49 @@ class Installer:
extras
[
extra
]
=
[
dep
.
name
for
dep
in
deps
]
extras
[
extra
]
=
[
dep
.
name
for
dep
in
deps
]
else
:
else
:
extras
=
{}
extras
=
{}
for
extra
,
deps
in
self
.
_locker
.
lock_data
.
get
(
'extras'
,
{}):
for
extra
,
deps
in
self
.
_locker
.
lock_data
.
get
(
'extras'
,
{})
.
items
()
:
extras
[
extra
]
=
[
dep
.
lower
()
for
dep
in
deps
]
extras
[
extra
]
=
[
dep
.
lower
()
for
dep
in
deps
]
# If a package is optional and not requested
# If a package is optional and not requested
# in any extra we skip it
# in any extra we skip it
if
package
.
optional
:
if
package
.
optional
:
drop
=
True
if
package
.
name
not
in
extra_packages
:
for
extra
in
self
.
_extras
:
if
extra
in
extras
and
package
.
name
in
extras
[
extra
]:
drop
=
False
continue
if
drop
:
op
.
skip
(
'Not required'
)
op
.
skip
(
'Not required'
)
def
_get_extra_packages
(
self
,
repo
):
"""
Returns all packages required by extras.
Maybe we just let the solver handle it?
"""
if
self
.
_update
:
extras
=
{
k
:
[
d
.
name
for
d
in
v
]
for
k
,
v
in
self
.
_package
.
extras
.
items
()
}
else
:
extras
=
self
.
_locker
.
lock_data
.
get
(
'extras'
,
{})
extra_packages
=
[]
for
extra_name
,
packages
in
extras
.
items
():
if
extra_name
not
in
self
.
_extras
:
continue
extra_packages
+=
[
Dependency
(
p
,
'*'
)
for
p
in
packages
]
def
_extra_packages
(
packages
):
pkgs
=
[]
for
package
in
packages
:
for
pkg
in
repo
.
packages
:
if
pkg
.
name
==
package
.
name
:
pkgs
.
append
(
package
)
pkgs
+=
_extra_packages
(
pkg
.
requires
)
break
return
pkgs
return
_extra_packages
(
extra_packages
)
def
_get_installer
(
self
)
->
BaseInstaller
:
def
_get_installer
(
self
)
->
BaseInstaller
:
return
PipInstaller
(
self
.
_io
.
venv
,
self
.
_io
)
return
PipInstaller
(
self
.
_io
.
venv
,
self
.
_io
)
poetry/poetry.py
View file @
2cc78814
from
pathlib
import
Path
from
pathlib
import
Path
from
.__version__
import
__version__
from
.__version__
import
__version__
from
.packages
import
Dependency
from
.packages
import
Locker
from
.packages
import
Locker
from
.packages
import
Package
from
.packages
import
Package
from
.repositories
import
Pool
from
.repositories
import
Pool
...
@@ -102,6 +103,12 @@ class Poetry:
...
@@ -102,6 +103,12 @@ class Poetry:
for
name
,
constraint
in
local_config
[
'dev-dependencies'
]
.
items
():
for
name
,
constraint
in
local_config
[
'dev-dependencies'
]
.
items
():
package
.
add_dependency
(
name
,
constraint
,
category
=
'dev'
)
package
.
add_dependency
(
name
,
constraint
,
category
=
'dev'
)
if
'extras'
in
local_config
:
for
extra_name
,
requirements
in
local_config
[
'extras'
]
.
items
():
package
.
extras
[
extra_name
]
=
[
Dependency
(
req
,
'*'
)
for
req
in
requirements
]
locker
=
Locker
(
poetry_file
.
with_suffix
(
'.lock'
),
local_config
)
locker
=
Locker
(
poetry_file
.
with_suffix
(
'.lock'
),
local_config
)
return
cls
(
poetry_file
,
local_config
,
package
,
locker
)
return
cls
(
poetry_file
,
local_config
,
package
,
locker
)
poetry/puzzle/solver.py
View file @
2cc78814
...
@@ -24,7 +24,7 @@ class Solver:
...
@@ -24,7 +24,7 @@ class Solver:
self
.
_locked
=
locked
self
.
_locked
=
locked
self
.
_io
=
io
self
.
_io
=
io
def
solve
(
self
,
requested
,
fixed
=
None
)
->
List
[
Operation
]:
def
solve
(
self
,
requested
,
fixed
=
None
,
extras
=
None
)
->
List
[
Operation
]:
resolver
=
Resolver
(
Provider
(
self
.
_package
,
self
.
_pool
),
UI
(
self
.
_io
))
resolver
=
Resolver
(
Provider
(
self
.
_package
,
self
.
_pool
),
UI
(
self
.
_io
))
base
=
None
base
=
None
...
@@ -40,7 +40,7 @@ class Solver:
...
@@ -40,7 +40,7 @@ class Solver:
packages
=
[
v
.
payload
for
v
in
graph
.
vertices
.
values
()]
packages
=
[
v
.
payload
for
v
in
graph
.
vertices
.
values
()]
# Setting
categories
# Setting
info
for
vertex
in
graph
.
vertices
.
values
():
for
vertex
in
graph
.
vertices
.
values
():
tags
=
self
.
_get_tags_for_vertex
(
vertex
,
requested
)
tags
=
self
.
_get_tags_for_vertex
(
vertex
,
requested
)
if
'main'
in
tags
[
'category'
]:
if
'main'
in
tags
[
'category'
]:
...
...
tests/fixtures/sample_project/pyproject.toml
View file @
2cc78814
...
@@ -24,6 +24,12 @@ pendulum = { git = "https://github.com/sdispater/pendulum.git", branch = "2.0" }
...
@@ -24,6 +24,12 @@ pendulum = { git = "https://github.com/sdispater/pendulum.git", branch = "2.0" }
requests
=
{
version
=
"^2.18"
,
optional
=
true
,
extras=
[
"security"
]
}
requests
=
{
version
=
"^2.18"
,
optional
=
true
,
extras=
[
"security"
]
}
pathlib2
=
{
version
=
"^2.2"
,
python
=
"~2.7"
}
pathlib2
=
{
version
=
"^2.2"
,
python
=
"~2.7"
}
orator
=
{
version
=
"^0.9"
,
optional
=
true
}
[tool.poetry.extras]
db
=
[
"orator"
]
[tool.poetry.dev-dependencies]
[tool.poetry.dev-dependencies]
pytest
=
"~3.4"
pytest
=
"~3.4"
...
...
tests/installation/fixtures/extras-with-dependencies.test
0 → 100644
View file @
2cc78814
[[
package
]]
name
=
"A"
version
=
"1.0"
description
=
""
category
=
"main"
optional
=
false
python
-
versions
=
"*"
platform
=
"*"
[[
package
]]
name
=
"B"
version
=
"1.0"
description
=
""
category
=
"main"
optional
=
false
python
-
versions
=
"*"
platform
=
"*"
[[
package
]]
name
=
"C"
version
=
"1.0"
description
=
""
category
=
"main"
optional
=
true
python
-
versions
=
"*"
platform
=
"*"
[
package
.
dependencies
]
D
=
"^1.0"
[[
package
]]
name
=
"D"
version
=
"1.1"
description
=
""
category
=
"main"
optional
=
true
python
-
versions
=
"*"
platform
=
"*"
[
extras
]
foo
=
[
"C"
]
[
metadata
]
python
-
versions
=
"*"
platform
=
"*"
content
-
hash
=
"123456789"
[
metadata
.
hashes
]
A
=
[]
B
=
[]
C
=
[]
D
=
[]
tests/installation/test_installer.py
View file @
2cc78814
...
@@ -10,6 +10,7 @@ from poetry.io import NullIO
...
@@ -10,6 +10,7 @@ from poetry.io import NullIO
from
poetry.packages
import
Locker
as
BaseLocker
from
poetry.packages
import
Locker
as
BaseLocker
from
poetry.repositories
import
Pool
from
poetry.repositories
import
Pool
from
poetry.repositories
import
Repository
from
poetry.repositories
import
Repository
from
poetry.repositories.installed_repository
import
InstalledRepository
from
tests.helpers
import
get_dependency
from
tests.helpers
import
get_dependency
from
tests.helpers
import
get_package
from
tests.helpers
import
get_package
...
@@ -43,6 +44,9 @@ class Locker(BaseLocker):
...
@@ -43,6 +44,9 @@ class Locker(BaseLocker):
def
is_locked
(
self
)
->
bool
:
def
is_locked
(
self
)
->
bool
:
return
self
.
_locked
return
self
.
_locked
def
is_fresh
(
self
)
->
bool
:
return
True
def
_get_content_hash
(
self
)
->
str
:
def
_get_content_hash
(
self
)
->
str
:
return
'123456789'
return
'123456789'
...
@@ -87,6 +91,16 @@ def pool(repo):
...
@@ -87,6 +91,16 @@ def pool(repo):
@pytest.fixture
()
@pytest.fixture
()
def
installed
():
original
=
InstalledRepository
.
load
InstalledRepository
.
load
=
lambda
_
:
InstalledRepository
()
yield
InstalledRepository
.
load
=
original
@pytest.fixture
()
def
locker
():
def
locker
():
return
Locker
()
return
Locker
()
...
@@ -373,3 +387,65 @@ def test_run_installs_extras_if_requested(installer, locker, repo, package):
...
@@ -373,3 +387,65 @@ def test_run_installs_extras_if_requested(installer, locker, repo, package):
installer
=
installer
.
installer
installer
=
installer
.
installer
assert
len
(
installer
.
installs
)
==
4
# A, B, C, D
assert
len
(
installer
.
installs
)
==
4
# A, B, C, D
def
test_run_installs_extras_with_deps_if_requested
(
installer
,
locker
,
repo
,
package
):
package
.
extras
[
'foo'
]
=
[
get_dependency
(
'C'
)
]
package_a
=
get_package
(
'A'
,
'1.0'
)
package_b
=
get_package
(
'B'
,
'1.0'
)
package_c
=
get_package
(
'C'
,
'1.0'
)
package_d
=
get_package
(
'D'
,
'1.1'
)
repo
.
add_package
(
package_a
)
repo
.
add_package
(
package_b
)
repo
.
add_package
(
package_c
)
repo
.
add_package
(
package_d
)
package
.
add_dependency
(
'A'
,
'^1.0'
)
package
.
add_dependency
(
'B'
,
'^1.0'
)
package
.
add_dependency
(
'C'
,
{
'version'
:
'^1.0'
,
'optional'
:
True
})
package_c
.
add_dependency
(
'D'
,
'^1.0'
)
installer
.
extras
([
'foo'
])
installer
.
run
()
expected
=
fixture
(
'extras-with-dependencies'
)
# Extras are pinned in lock
assert
locker
.
written_data
==
expected
# But should not be installed
installer
=
installer
.
installer
assert
len
(
installer
.
installs
)
==
4
# A, B, C, D
def
test_run_installs_extras_with_deps_if_requested_locked
(
installer
,
locker
,
repo
,
package
,
installed
):
locker
.
locked
(
True
)
locker
.
mock_lock_data
(
fixture
(
'extras-with-dependencies'
))
package
.
extras
[
'foo'
]
=
[
get_dependency
(
'C'
)
]
package_a
=
get_package
(
'A'
,
'1.0'
)
package_b
=
get_package
(
'B'
,
'1.0'
)
package_c
=
get_package
(
'C'
,
'1.0'
)
package_d
=
get_package
(
'D'
,
'1.1'
)
repo
.
add_package
(
package_a
)
repo
.
add_package
(
package_b
)
repo
.
add_package
(
package_c
)
repo
.
add_package
(
package_d
)
package
.
add_dependency
(
'A'
,
'^1.0'
)
package
.
add_dependency
(
'B'
,
'^1.0'
)
package
.
add_dependency
(
'C'
,
{
'version'
:
'^1.0'
,
'optional'
:
True
})
package_c
.
add_dependency
(
'D'
,
'^1.0'
)
installer
.
extras
([
'foo'
])
installer
.
run
()
# But should not be installed
installer
=
installer
.
installer
assert
len
(
installer
.
installs
)
==
4
# A, B, C, D
tests/test_poetry.py
View file @
2cc78814
...
@@ -50,3 +50,5 @@ def test_poetry():
...
@@ -50,3 +50,5 @@ def test_poetry():
assert
pathlib2
.
pretty_constraint
==
'^2.2'
assert
pathlib2
.
pretty_constraint
==
'^2.2'
assert
pathlib2
.
python_versions
==
'~2.7'
assert
pathlib2
.
python_versions
==
'~2.7'
assert
not
pathlib2
.
is_optional
()
assert
not
pathlib2
.
is_optional
()
assert
'db'
in
package
.
extras
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