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
135ef5d5
Unverified
Commit
135ef5d5
authored
Mar 29, 2018
by
Sébastien Eustace
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add compatibility with Python 3.4 and 3.5
parent
ac73c538
Hide whitespace changes
Inline
Side-by-side
Showing
47 changed files
with
423 additions
and
242 deletions
+423
-242
.coveragerc
+0
-0
CHANGELOG.md
+5
-0
poetry/console/commands/add.py
+9
-4
poetry/console/commands/build.py
+4
-2
poetry/console/commands/command.py
+0
-1
poetry/console/commands/config.py
+40
-16
poetry/console/commands/debug/resolve.py
+9
-3
poetry/console/commands/remove.py
+1
-1
poetry/console/commands/show.py
+35
-16
poetry/console/commands/venv_command.py
+3
-1
poetry/installation/installer.py
+53
-27
poetry/installation/pip_installer.py
+11
-6
poetry/masonry/builder.py
+1
-1
poetry/masonry/builders/builder.py
+13
-6
poetry/masonry/builders/sdist.py
+9
-6
poetry/masonry/builders/wheel.py
+22
-18
poetry/masonry/publishing/publisher.py
+30
-22
poetry/mixology/possibility_set.py
+1
-1
poetry/mixology/resolution.py
+18
-13
poetry/mixology/state.py
+5
-2
poetry/packages/__init__.py
+5
-7
poetry/packages/constraints/generic_constraint.py
+5
-2
poetry/packages/dependency.py
+11
-7
poetry/packages/package.py
+1
-1
poetry/packages/project_package.py
+0
-0
poetry/packages/vcs_dependency.py
+1
-1
poetry/poetry.py
+8
-4
poetry/puzzle/operations/update.py
+4
-0
poetry/puzzle/provider.py
+6
-2
poetry/puzzle/solver.py
+9
-1
poetry/repositories/legacy_repository.py
+1
-1
poetry/repositories/pool.py
+2
-2
poetry/repositories/pypi_repository.py
+10
-9
poetry/semver/constraints/constraint.py
+10
-4
poetry/semver/constraints/wildcard_constraint.py
+2
-2
poetry/semver/helpers.py
+17
-12
poetry/toml/cascadedict.py
+3
-1
poetry/utils/_compat.py
+3
-0
poetry/utils/toml_file.py
+6
-4
poetry/utils/venv.py
+14
-7
poetry/version/version_selector.py
+1
-1
pyproject.toml
+4
-2
tests/installation/test_installer.py
+3
-2
tests/masonry/builders/test_complete.py
+5
-5
tests/masonry/builders/test_sdist.py
+1
-1
tests/puzzle/test_solver.py
+12
-12
tests/test_poetry.py
+10
-6
No files found.
.coveragerc
0 → 100644
View file @
135ef5d5
CHANGELOG.md
View file @
135ef5d5
...
...
@@ -2,6 +2,11 @@
## [Unreleased]
### Added
-
Added compatibility with Python 3.4 and 3.5.
### Changed
-
Improved dependency resolution to avoid unnecessary operations.
...
...
poetry/console/commands/add.py
View file @
135ef5d5
...
...
@@ -42,7 +42,9 @@ If you do not specify a version constraint, poetry will choose a suitable one ba
for
name
in
packages
:
for
key
in
poetry_content
[
section
]:
if
key
.
lower
()
==
name
.
lower
():
raise
ValueError
(
f
'Package {name} is already present'
)
raise
ValueError
(
'Package {} is already present'
.
format
(
name
)
)
requirements
=
self
.
_determine_requirements
(
packages
)
requirements
=
self
.
_format_requirements
(
requirements
)
...
...
@@ -118,7 +120,8 @@ If you do not specify a version constraint, poetry will choose a suitable one ba
requirement
[
'name'
]
=
name
self
.
line
(
f
'Using version <info>{version}</> for <info>{name}</>'
'Using version <info>{}</> for <info>{}</>'
.
format
(
version
,
name
)
)
else
:
# check that the specified version/constraint exists
...
...
@@ -129,7 +132,9 @@ If you do not specify a version constraint, poetry will choose a suitable one ba
requirement
[
'name'
]
=
name
result
.
append
(
f
'{requirement["name"]} {requirement["version"]}'
)
result
.
append
(
'{} {}'
.
format
(
requirement
[
'name'
],
requirement
[
'version'
])
)
return
result
...
...
@@ -143,7 +148,7 @@ If you do not specify a version constraint, poetry will choose a suitable one ba
if
not
package
:
# TODO: find similar
raise
ValueError
(
f
'Could not find a matching version of package {name}'
'Could not find a matching version of package {}'
.
format
(
name
)
)
return
(
...
...
poetry/console/commands/build.py
View file @
135ef5d5
...
...
@@ -17,8 +17,10 @@ class BuildCommand(VenvCommand):
fmt
=
self
.
option
(
'format'
)
package
=
self
.
poetry
.
package
self
.
line
(
f
'Building <info>{package.pretty_name}</> '
f
'(<comment>{package.version}</>)'
)
self
.
line
(
'Building <info>{}</> (<comment>{}</>)'
.
format
(
package
.
pretty_name
,
package
.
version
)
)
builder
=
Builder
(
self
.
poetry
,
self
.
venv
,
self
.
output
)
builder
.
build
(
fmt
)
poetry/console/commands/command.py
View file @
135ef5d5
from
cleo
import
Command
as
BaseCommand
from
cleo.inputs
import
ListInput
from
poetry.poetry
import
Poetry
...
...
poetry/console/commands/config.py
View file @
135ef5d5
...
...
@@ -77,10 +77,13 @@ To remove a repository (repo is a short alias for repositories):
if
self
.
_config
.
setting
(
'repositories'
)
is
not
None
:
value
=
self
.
_config
.
setting
(
'repositories'
)
else
:
repo
=
self
.
_config
.
setting
(
f
'repositories.{m.group(1)}'
)
repo
=
self
.
_config
.
setting
(
'repositories.{}'
.
format
(
m
.
group
(
1
))
)
if
repo
is
None
:
raise
ValueError
(
f
'There is no {m.group(1)} repository defined'
'There is no {} repository defined'
.
format
(
m
.
group
(
1
))
)
value
=
repo
...
...
@@ -115,18 +118,26 @@ To remove a repository (repo is a short alias for repositories):
raise
ValueError
(
'You cannot remove the [repositories] section'
)
if
self
.
option
(
'unset'
):
repo
=
self
.
_config
.
setting
(
f
'repositories.{m.group(1)}'
)
repo
=
self
.
_config
.
setting
(
'repositories.{}'
.
format
(
m
.
group
(
1
))
)
if
repo
is
None
:
raise
ValueError
(
f
'There is no {m.group(1)} repository defined'
)
raise
ValueError
(
'There is no {} repository defined'
.
format
(
m
.
group
(
1
))
)
self
.
_config
.
remove_property
(
f
'repositories.{m.group(1)}'
)
self
.
_config
.
remove_property
(
'repositories.{}'
.
format
(
m
.
group
(
1
))
)
return
0
if
len
(
values
)
==
1
:
url
=
values
[
0
]
self
.
_config
.
add_property
(
f
'repositories.{m.group(1)}.url'
,
url
)
self
.
_config
.
add_property
(
'repositories.{}.url'
.
format
(
m
.
group
(
1
)),
url
)
return
0
...
...
@@ -139,12 +150,16 @@ To remove a repository (repo is a short alias for repositories):
m
=
re
.
match
(
'^(http-basic)
\
.(.+)'
,
self
.
argument
(
'key'
))
if
m
:
if
self
.
option
(
'unset'
):
if
not
self
.
_auth_config
.
setting
(
f
'{m.group(1)}.{m.group(2)}'
):
if
not
self
.
_auth_config
.
setting
(
'{}.{}'
.
format
(
m
.
group
(
1
),
m
.
group
(
2
))
):
raise
ValueError
(
f
'There is no {m.group(2)} {m.group(1)} defined'
'There is no {} {} defined'
.
format
(
m
.
group
(
2
),
m
.
group
(
1
)
)
)
self
.
_auth_config
.
remove_property
(
f
'{m.group(1)}.{m.group(2)}'
)
self
.
_auth_config
.
remove_property
(
'{}.{}'
.
format
(
m
.
group
(
1
),
m
.
group
(
2
))
)
return
0
...
...
@@ -154,14 +169,17 @@ To remove a repository (repo is a short alias for repositories):
# Only username, so we prompt for password
password
=
self
.
secret
(
'Password:'
)
elif
len
(
values
)
!=
2
:
raise
ValueError
(
f
'Expected one or two arguments '
f
'(username, password), got {len(values)}'
)
raise
ValueError
(
'Expected one or two arguments '
'(username, password), got {}'
.
format
(
len
(
values
))
)
else
:
username
=
values
[
0
]
password
=
values
[
1
]
self
.
_auth_config
.
add_property
(
f
'{m.group(1)}.{m.group(2)}'
,
{
'{}.{}'
.
format
(
m
.
group
(
1
),
m
.
group
(
2
)),
{
'username'
:
username
,
'password'
:
password
}
...
...
@@ -169,7 +187,9 @@ To remove a repository (repo is a short alias for repositories):
return
0
raise
ValueError
(
f
'Setting {self.argument("key")} does not exist'
)
raise
ValueError
(
'Setting {} does not exist'
.
format
(
self
.
argument
(
"key"
))
)
def
_handle_single_value
(
self
,
key
,
callbacks
,
values
):
validator
,
normalizer
=
callbacks
...
...
@@ -180,7 +200,7 @@ To remove a repository (repo is a short alias for repositories):
value
=
values
[
0
]
if
not
validator
(
value
):
raise
RuntimeError
(
f
'"{value}" is an invalid value for {key}'
'"{}" is an invalid value for {}'
.
format
(
value
,
key
)
)
self
.
_config
.
add_property
(
key
,
normalizer
(
value
))
...
...
@@ -215,8 +235,12 @@ To remove a repository (repo is a short alias for repositories):
for
val
in
value
]
value
=
f
'[{", ".join(value)}]'
value
=
'[{}]'
.
format
(
", "
.
join
(
value
))
value
=
json
.
dumps
(
value
)
self
.
line
(
f
'[<comment>{(k or "") + key}</comment>] <info>{value}</info>'
)
self
.
line
(
'[<comment>{}</comment>] <info>{}</info>'
.
format
(
(
k
or
""
)
+
key
,
value
)
)
poetry/console/commands/debug/resolve.py
View file @
135ef5d5
...
...
@@ -55,8 +55,12 @@ class DebugResolveCommand(Command):
for
op
in
ops
:
package
=
op
.
package
self
.
line
(
f
' - <info>{package.name}</info> '
f
'(<comment>{package.version}</comment>)'
)
self
.
line
(
' - <info>{}</info> (<comment>{}</comment>)'
.
format
(
package
.
name
,
package
.
version
)
)
def
_determine_requirements
(
self
,
requires
:
List
[
str
])
->
List
[
str
]:
if
not
requires
:
...
...
@@ -68,7 +72,9 @@ class DebugResolveCommand(Command):
if
'version'
not
in
requirement
:
requirement
[
'version'
]
=
'*'
result
.
append
(
f
'{requirement["name"]} {requirement["version"]}'
)
result
.
append
(
'{} {}'
.
format
(
requirement
[
'name'
],
requirement
[
'version'
])
)
return
result
...
...
poetry/console/commands/remove.py
View file @
135ef5d5
...
...
@@ -41,7 +41,7 @@ list of installed packages
break
if
not
found
:
raise
ValueError
(
f
'Package {name} not found'
)
raise
ValueError
(
'Package {} not found'
.
format
(
name
)
)
for
key
in
requirements
:
del
poetry_content
[
section
][
key
]
...
...
poetry/console/commands/show.py
View file @
135ef5d5
...
...
@@ -62,7 +62,7 @@ lists all packages available."""
break
if
not
pkg
:
raise
ValueError
(
f
'Package {package} not found'
)
raise
ValueError
(
'Package {} not found'
.
format
(
package
)
)
if
self
.
option
(
'tree'
):
self
.
display_package_tree
(
pkg
,
installed_repo
)
...
...
@@ -70,9 +70,9 @@ lists all packages available."""
return
0
rows
=
[
[
'<info>name</>'
,
f
' : <fg=cyan>{pkg.pretty_name}</>'
],
[
'<info>version</>'
,
f
' : <comment>{pkg.pretty_version}</>'
],
[
'<info>description</>'
,
f
' : {pkg.description}'
],
[
'<info>name</>'
,
' : <fg=cyan>{}</>'
.
format
(
pkg
.
pretty_name
)
],
[
'<info>version</>'
,
' : <comment>{}</>'
.
format
(
pkg
.
pretty_version
)
],
[
'<info>description</>'
,
' : {}'
.
format
(
pkg
.
description
)
],
]
table
.
add_rows
(
rows
)
...
...
@@ -82,8 +82,12 @@ lists all packages available."""
self
.
line
(
''
)
self
.
line
(
'<info>dependencies</info>'
)
for
dependency
in
pkg
.
requires
:
self
.
line
(
f
' - {dependency.pretty_name} '
f
'<comment>{dependency.pretty_constraint}</>'
)
self
.
line
(
' - {} <comment>{}</>'
.
format
(
dependency
.
pretty_name
,
dependency
.
pretty_constraint
)
)
return
0
...
...
@@ -109,9 +113,11 @@ lists all packages available."""
write_description
=
name_length
+
version_length
+
latest_length
+
24
<=
width
for
locked
in
locked_packages
:
line
=
f
'<fg=cyan>{locked.pretty_name:{name_length}}</>'
line
=
'<fg=cyan>{:{}}</>'
.
format
(
locked
.
pretty_name
,
name_length
)
if
write_version
:
line
+=
f
' {locked.full_pretty_version:{version_length}}'
line
+=
' {:{}}'
.
format
(
locked
.
full_pretty_version
,
version_length
)
if
show_latest
and
write_latest
:
latest
=
latest_packages
[
locked
.
pretty_name
]
...
...
@@ -122,7 +128,9 @@ lists all packages available."""
elif
update_status
==
'update-possible'
:
color
=
'yellow'
line
+=
f
' <fg={color}>{latest.version:{latest_length}}</>'
line
+=
' <fg={}>{:{}}</>'
.
format
(
color
,
latest
.
version
,
latest_length
)
if
self
.
option
(
'outdated'
)
and
update_status
==
'up-to-date'
:
continue
...
...
@@ -140,8 +148,8 @@ lists all packages available."""
self
.
line
(
line
)
def
display_package_tree
(
self
,
package
,
installed_repo
):
self
.
write
(
f
'<info>{package.pretty_name}</info>'
)
self
.
line
(
f
' {package.pretty_version} {package.description}'
)
self
.
write
(
'<info>{}</info>'
.
format
(
package
.
prett_name
)
)
self
.
line
(
' {} {}'
.
format
(
package
.
pretty_version
,
package
.
description
)
)
dependencies
=
package
.
requires
dependencies
=
sorted
(
dependencies
,
key
=
lambda
x
:
x
.
name
)
...
...
@@ -155,8 +163,12 @@ lists all packages available."""
level
=
1
color
=
self
.
colors
[
level
]
info
=
f
'{tree_bar}── <{color}>{dependency.name}</{color}> '
\
f
'{dependency.pretty_constraint}'
info
=
'{tree_bar}── <{color}>{name}</{color}> {constraint}'
.
format
(
tree_bar
=
tree_bar
,
color
=
color
,
name
=
dependency
.
name
,
constraint
=
dependency
.
pretty_constraint
)
self
.
_write_tree_line
(
info
)
tree_bar
=
tree_bar
.
replace
(
'└'
,
' '
)
...
...
@@ -196,8 +208,13 @@ lists all packages available."""
if
dependency
.
name
in
current_tree
:
circular_warn
=
'(circular dependency aborted here)'
info
=
f
'{tree_bar}── <{color}>{dependency.name}</{color}> '
\
f
'{dependency.pretty_constraint} {circular_warn}'
info
=
'{tree_bar}── <{color}>{name}</{color}> {constraint} {warn}'
.
format
(
tree_bar
=
tree_bar
,
color
=
color
,
name
=
dependency
.
name
,
constraint
=
dependency
.
pretty_constraint
,
warn
=
circular_warn
)
self
.
_write_tree_line
(
info
)
tree_bar
=
tree_bar
.
replace
(
'└'
,
' '
)
...
...
@@ -231,7 +248,9 @@ lists all packages available."""
name
=
package
.
name
selector
=
VersionSelector
(
self
.
poetry
.
pool
)
return
selector
.
find_best_candidate
(
name
,
f
'>={package.version}'
)
return
selector
.
find_best_candidate
(
name
,
'>={}'
.
format
(
package
.
version
)
)
def
get_update_status
(
self
,
latest
,
package
):
if
latest
.
full_pretty_version
==
package
.
full_pretty_version
:
...
...
poetry/console/commands/venv_command.py
View file @
135ef5d5
...
...
@@ -16,7 +16,9 @@ class VenvCommand(Command):
self
.
_venv
=
Venv
.
create
(
o
,
self
.
poetry
.
package
.
name
)
if
self
.
_venv
.
is_venv
()
and
o
.
is_verbose
():
o
.
writeln
(
f
'Using virtualenv: <comment>{self._venv.venv}</>'
)
o
.
writeln
(
'Using virtualenv: <comment>{}</>'
.
format
(
self
.
_venv
.
venv
)
)
@property
def
venv
(
self
):
...
...
poetry/installation/installer.py
View file @
135ef5d5
...
...
@@ -125,7 +125,9 @@ class Installer:
# Checking extras
for
extra
in
self
.
_extras
:
if
extra
not
in
self
.
_package
.
extras
:
raise
ValueError
(
f
'Extra [{extra}] is not specified.'
)
raise
ValueError
(
'Extra [{}] is not specified.'
.
format
(
extra
)
)
self
.
_io
.
writeln
(
'<info>Updating dependencies</>'
)
fixed
=
[]
...
...
@@ -181,7 +183,9 @@ class Installer:
for
extra
in
self
.
_extras
:
if
extra
not
in
self
.
_locker
.
lock_data
.
get
(
'extras'
,
{}):
raise
ValueError
(
f
'Extra [{extra}] is not specified.'
)
raise
ValueError
(
'Extra [{}] is not specified.'
.
format
(
extra
)
)
# If we are installing from lock
# Filter the operations by comparing it with what is
...
...
@@ -213,26 +217,35 @@ class Installer:
if
op
.
job_type
==
'install'
:
installs
.
append
(
f
'{op.package.pretty_name}'
f
':{op.package.full_pretty_version}'
'{}:{}'
.
format
(
op
.
package
.
pretty_name
,
op
.
package
.
full_pretty_version
)
)
elif
op
.
job_type
==
'update'
:
updates
.
append
(
f
'{op.target_package.pretty_name}'
f
':{op.target_package.full_pretty_version}'
'{}:{}'
.
format
(
op
.
target_package
.
pretty_name
,
op
.
target_package
.
full_pretty_version
)
)
elif
op
.
job_type
==
'uninstall'
:
uninstalls
.
append
(
f
'{op.package.pretty_name}'
)
uninstalls
.
append
(
op
.
package
.
pretty_name
)
self
.
_io
.
new_line
()
self
.
_io
.
writeln
(
'Package operations: '
f
'<info>{len(installs)}</> install{"" if len(installs) == 1 else "s"}, '
f
'<info>{len(updates)}</> update{"" if len(updates) == 1 else "s"}, '
f
'<info>{len(uninstalls)}</> removal{"" if len(uninstalls) == 1 else "s"}'
f
'{", <info>{}</> skipped".format(len(skipped)) if skipped and self.is_verbose() else ""}'
'<info>{}</> install{}, '
'<info>{}</> update{}, '
'<info>{}</> removal{}'
'{}'
.
format
(
len
(
installs
),
''
if
len
(
installs
)
==
1
else
's'
,
len
(
updates
),
''
if
len
(
updates
)
==
1
else
's'
,
len
(
uninstalls
),
''
if
len
(
uninstalls
)
==
1
else
's'
,
', <info>{}</> skipped'
.
format
(
len
(
skipped
)
)
if
skipped
and
self
.
is_verbose
()
else
''
)
)
self
.
_io
.
new_line
()
...
...
@@ -256,22 +269,27 @@ class Installer:
"""
method
=
operation
.
job_type
getattr
(
self
,
f
'_execute_{method}'
)(
operation
)
getattr
(
self
,
'_execute_{}'
.
format
(
method
)
)(
operation
)
def
_execute_install
(
self
,
operation
:
Install
)
->
None
:
if
operation
.
skipped
:
if
self
.
is_verbose
()
and
(
self
.
_execute_operations
or
self
.
is_dry_run
()):
self
.
_io
.
writeln
(
f
' - Skipping <info>{operation.package.pretty_name}</> '
f
'(<comment>{operation.package.full_pretty_version}</>) '
f
'{operation.skip_reason}'
)
' - Skipping <info>{}</> (<comment>{}</>) {}'
.
format
(
operation
.
package
.
pretty_name
,
operation
.
package
.
full_pretty_version
,
operation
.
skip_reason
)
)
return
if
self
.
_execute_operations
or
self
.
is_dry_run
():
self
.
_io
.
writeln
(
f
' - Installing <info>{operation.package.pretty_name}</> '
f
'(<comment>{operation.package.full_pretty_version}</>)'
' - Installing <info>{}</> (<comment>{}</>)'
.
format
(
operation
.
package
.
pretty_name
,
operation
.
package
.
full_pretty_version
)
)
if
not
self
.
_execute_operations
:
...
...
@@ -286,17 +304,23 @@ class Installer:
if
operation
.
skipped
:
if
self
.
is_verbose
()
and
(
self
.
_execute_operations
or
self
.
is_dry_run
()):
self
.
_io
.
writeln
(
f
' - Skipping <info>{target.pretty_name}</> '
f
'(<comment>{target.full_pretty_version}</>) '
f
'{operation.skip_reason}'
)
' - Skipping <info>{}</> (<comment>{}</>) {}'
.
format
(
target
.
pretty_name
,
target
.
full_pretty_version
,
operation
.
skip_reason
)
)
return
if
self
.
_execute_operations
or
self
.
is_dry_run
():
self
.
_io
.
writeln
(
f
' - Updating <info>{target.pretty_name}</> '
f
'(<comment>{source.pretty_version}</>'
f
' -> <comment>{target.pretty_version}</>)'
' - Updating <info>{}</> (<comment>{}</> -> <comment>{}</>)'
.
format
(
target
.
pretty_name
,
source
.
pretty_version
,
target
.
pretty_version
)
)
if
not
self
.
_execute_operations
:
...
...
@@ -307,8 +331,10 @@ class Installer:
def
_execute_uninstall
(
self
,
operation
:
Uninstall
)
->
None
:
if
self
.
_execute_operations
or
self
.
is_dry_run
():
self
.
_io
.
writeln
(
f
' - Removing <info>{operation.package.pretty_name}</> '
f
'(<comment>{operation.package.full_pretty_version}</>)'
' - Removing <info>{}</> (<comment>{}</>)'
.
format
(
operation
.
package
.
pretty_name
,
operation
.
package
.
full_pretty_version
)
)
if
not
self
.
_execute_operations
:
...
...
poetry/installation/pip_installer.py
View file @
135ef5d5
...
...
@@ -59,22 +59,27 @@ class PipInstaller(BaseInstaller):
def
requirement
(
self
,
package
,
formatted
=
False
)
->
str
:
if
formatted
and
not
package
.
source_type
==
'git'
:
req
=
f
'{package.name}=={package.version}'
req
=
'{}=={}'
.
format
(
package
.
name
,
package
.
version
)
for
h
in
package
.
hashes
:
req
+=
f
' --hash sha256:{h}'
req
+=
' --hash sha256:{}'
.
format
(
h
)
req
+=
'
\n
'
return
req
if
package
.
source_type
==
'git'
:
return
f
'git+{package.source_url}@{package.source_reference}'
\
f
'#egg={package.name}'
return
'git+{}@{}#egg={}'
.
format
(
package
.
source_url
,
package
.
source_reference
,
package
.
name
)
return
f
'{package.name}=={package.version}'
return
'{}=={}'
.
format
(
package
.
name
,
package
.
version
)
def
create_temporary_requirement
(
self
,
package
):
fd
,
name
=
tempfile
.
mkstemp
(
'reqs.txt'
,
f
'{package.name}-{package.version}'
)
fd
,
name
=
tempfile
.
mkstemp
(
'reqs.txt'
,
'{}-{}'
.
format
(
package
.
name
,
package
.
version
)
)
with
open
(
fd
,
'w'
)
as
f
:
f
.
write
(
self
.
requirement
(
package
,
formatted
=
True
))
...
...
poetry/masonry/builder.py
View file @
135ef5d5
...
...
@@ -18,7 +18,7 @@ class Builder:
def
build
(
self
,
fmt
:
str
):
if
fmt
not
in
self
.
_FORMATS
:
raise
ValueError
(
f
'Invalid format: {fmt}'
)
raise
ValueError
(
'Invalid format: {}'
.
format
(
fmt
)
)
builder
=
self
.
_FORMATS
[
fmt
](
self
.
_poetry
,
self
.
_venv
,
self
.
_io
)
...
...
poetry/masonry/builders/builder.py
View file @
135ef5d5
...
...
@@ -84,14 +84,14 @@ class Builder:
continue
self
.
_io
.
writeln
(
f
' - Adding: <comment>{str(file)}</comment>'
,
' - Adding: <comment>{}</comment>'
.
format
(
str
(
file
))
,
verbosity
=
self
.
_io
.
VERBOSITY_VERY_VERBOSE
)
to_add
.
append
(
file
)
# Include project files
self
.
_io
.
writeln
(
f
' - Adding: <comment>pyproject.toml</comment>'
,
' - Adding: <comment>pyproject.toml</comment>'
,
verbosity
=
self
.
_io
.
VERBOSITY_VERY_VERBOSE
)
to_add
.
append
(
Path
(
'pyproject.toml'
))
...
...
@@ -102,7 +102,9 @@ class Builder:
readme
=
self
.
_path
/
self
.
_poetry
.
config
[
'readme'
]
if
readme
.
exists
():
self
.
_io
.
writeln
(
f
' - Adding: <comment>{readme.relative_to(self._path)}</comment>'
,
' - Adding: <comment>{}</comment>'
.
format
(
readme
.
relative_to
(
self
.
_path
)
),
verbosity
=
self
.
_io
.
VERBOSITY_VERY_VERBOSE
)
to_add
.
append
(
readme
.
relative_to
(
self
.
_path
))
...
...
@@ -119,12 +121,15 @@ class Builder:
# Scripts -> Entry points
for
name
,
ep
in
self
.
_poetry
.
config
.
get
(
'scripts'
,
{})
.
items
():
result
[
'console_scripts'
]
.
append
(
f
'{name} = {ep}'
)
result
[
'console_scripts'
]
.
append
(
'{} = {}'
.
format
(
name
,
ep
)
)
# Plugins -> entry points
for
groupname
,
group
in
self
.
_poetry
.
config
.
get
(
'plugins'
,
{})
.
items
():
for
name
,
ep
in
sorted
(
group
.
items
()):
result
[
groupname
]
.
append
(
f
'{name} = {ep}'
)
result
[
groupname
]
.
append
(
'{} = {}'
.
format
(
name
,
ep
))
for
groupname
in
result
:
result
[
groupname
]
=
sorted
(
result
[
groupname
])
return
dict
(
result
)
...
...
@@ -152,7 +157,9 @@ class Builder:
for
version
in
sorted
(
self
.
AVAILABLE_PYTHONS
):
if
python_constraint
.
matches
(
Constraint
(
'='
,
version
)):
classifiers
.
append
(
f
'Programming Language :: Python :: {version}'
)
classifiers
.
append
(
'Programming Language :: Python :: {}'
.
format
(
version
)
)
return
classifiers
...
...
poetry/masonry/builders/sdist.py
View file @
135ef5d5
...
...
@@ -59,14 +59,17 @@ class SdistBuilder(Builder):
if
not
target_dir
.
exists
():
target_dir
.
mkdir
(
parents
=
True
)
target
=
target_dir
/
f
'{self._package.pretty_name}'
\
f
'-{self._package.version}.tar.gz'
target
=
target_dir
/
'{}-{}.tar.gz'
.
format
(
self
.
_package
.
pretty_name
,
self
.
_package
.
version
)
gz
=
GzipFile
(
target
.
as_posix
(),
mode
=
'wb'
)
tar
=
tarfile
.
TarFile
(
target
.
as_posix
(),
mode
=
'w'
,
fileobj
=
gz
,
format
=
tarfile
.
PAX_FORMAT
)
try
:
tar_dir
=
f
'{self._package.pretty_name}-{self._package.version}'
tar_dir
=
'{}-{}'
.
format
(
self
.
_package
.
pretty_name
,
self
.
_package
.
version
)
files_to_add
=
self
.
find_files_to_add
(
exclude_build
=
False
)
...
...
@@ -74,7 +77,7 @@ class SdistBuilder(Builder):
path
=
self
.
_path
/
relpath
tar_info
=
tar
.
gettarinfo
(
str
(
path
),
arcname
=
pjoin
(
tar_dir
,
relpath
)
arcname
=
pjoin
(
tar_dir
,
str
(
relpath
)
)
)
tar_info
=
self
.
clean_tarinfo
(
tar_info
)
...
...
@@ -105,7 +108,7 @@ class SdistBuilder(Builder):
tar
.
close
()
gz
.
close
()
self
.
_io
.
writeln
(
f
' - Built <fg=cyan>{target.name}</>'
)
self
.
_io
.
writeln
(
' - Built <fg=cyan>{}</>'
.
format
(
target
.
name
)
)
return
target
...
...
@@ -115,7 +118,7 @@ class SdistBuilder(Builder):
# If we have a build script, use it
if
self
.
_package
.
build
:
after
+=
[
f
'from {self._package.build.split(".")[0]} import *'
,
'from {} import *'
.
format
(
self
.
_package
.
build
.
split
(
'.'
)[
0
])
,
'build(setup_kwargs)'
]
...
...
poetry/masonry/builders/wheel.py
View file @
135ef5d5
...
...
@@ -5,7 +5,11 @@ import re
import
tempfile
import
shutil
import
stat
import
zipfile
try
:
import
zipfile36
as
zipfile
except
ImportError
:
import
zipfile
from
base64
import
urlsafe_b64encode
from
io
import
StringIO
...
...
@@ -87,7 +91,7 @@ class WheelBuilder(Builder):
finally
:
self
.
_wheel_zip
.
close
()
self
.
_io
.
writeln
(
f
' - Built <fg=cyan>{self.wheel_filename}</>'
)
self
.
_io
.
writeln
(
' - Built <fg=cyan>{}</>'
.
format
(
self
.
wheel_filename
)
)
def
_build
(
self
)
->
None
:
if
self
.
_package
.
build
:
...
...
@@ -289,37 +293,37 @@ class WheelBuilder(Builder):
Write out metadata in the 2.x format (email like)
"""
fp
.
write
(
'Metadata-Version: 2.1
\n
'
)
fp
.
write
(
f
'Name: {self._meta.name}
\n
'
)
fp
.
write
(
f
'Version: {self._meta.version}
\n
'
)
fp
.
write
(
f
'Summary: {self._meta.summary}
\n
'
)
fp
.
write
(
f
'Home-page: {self._meta.home_page or "UNKNOWN"}
\n
'
)
fp
.
write
(
f
'License: {self._meta.license or "UNKOWN"}
\n
'
)
fp
.
write
(
'Name: {}
\n
'
.
format
(
self
.
_meta
.
name
)
)
fp
.
write
(
'Version: {}
\n
'
.
format
(
self
.
_meta
.
version
)
)
fp
.
write
(
'Summary: {}
\n
'
.
format
(
self
.
_meta
.
summary
)
)
fp
.
write
(
'Home-page: {}
\n
'
.
format
(
self
.
_meta
.
home_page
or
'UNKNOWN'
)
)
fp
.
write
(
'License: {}
\n
'
.
format
(
self
.
_meta
.
license
or
'UNKOWN'
)
)
# Optional fields
if
self
.
_meta
.
keywords
:
fp
.
write
(
f
"Keywords: {self._meta.keywords}
\n
"
)
fp
.
write
(
"Keywords: {}
\n
"
.
format
(
self
.
_meta
.
keywords
)
)
if
self
.
_meta
.
author
:
fp
.
write
(
f
'Author: {self._meta.author}
\n
'
)
fp
.
write
(
'Author: {}
\n
'
.
format
(
self
.
_meta
.
author
)
)
if
self
.
_meta
.
author_email
:
fp
.
write
(
f
'Author-email: {self._meta.author_email}
\n
'
)
fp
.
write
(
'Author-email: {}
\n
'
.
format
(
self
.
_meta
.
author_email
)
)
if
self
.
_meta
.
requires_python
:
fp
.
write
(
f
'Requires-Python: {self._meta.requires_python}
\n
'
)
fp
.
write
(
'Requires-Python: {}
\n
'
.
format
(
self
.
_meta
.
requires_python
)
)
for
classifier
in
self
.
_meta
.
classifiers
:
fp
.
write
(
f
'Classifier: {classifier}
\n
'
)
fp
.
write
(
'Classifier: {}
\n
'
.
format
(
classifier
)
)
for
extra
in
s
elf
.
_meta
.
provides_extra
:
fp
.
write
(
f
'Provides-Extra: {extra}
\n
'
)
for
extra
in
s
orted
(
self
.
_meta
.
provides_extra
)
:
fp
.
write
(
'Provides-Extra: {}
\n
'
.
format
(
extra
)
)
for
dep
in
s
elf
.
_meta
.
requires_dist
:
fp
.
write
(
f
'Requires-Dist: {dep}
\n
'
)
for
dep
in
s
orted
(
self
.
_meta
.
requires_dist
)
:
fp
.
write
(
'Requires-Dist: {}
\n
'
.
format
(
dep
)
)
if
self
.
_meta
.
description_content_type
:
fp
.
write
(
f
'Description-Content-Type: '
f
'{self._meta.description_content_type}
\n
'
)
fp
.
write
(
'Description-Content-Type: '
'{}
\n
'
.
format
(
self
.
_meta
.
description_content_type
)
)
if
self
.
_meta
.
description
is
not
None
:
fp
.
write
(
'
\n
'
+
self
.
_meta
.
description
+
'
\n
'
)
poetry/masonry/publishing/publisher.py
View file @
135ef5d5
...
...
@@ -44,15 +44,20 @@ class Publisher:
def
publish
(
self
,
repository_name
):
if
repository_name
:
self
.
_io
.
writeln
(
f
'Publishing <info>{self._package.pretty_name}</info> '
f
'(<comment>{self._package.pretty_version}</comment>) '
f
'to <fg=cyan>{repository_name}</>'
'Publishing <info>{}</info> (<comment>{}</comment>) '
'to <fg=cyan>{}</>'
.
format
(
self
.
_package
.
pretty_name
,
self
.
_package
.
pretty_version
,
repository_name
)
)
else
:
self
.
_io
.
writeln
(
f
'Publishing <info>{self._package.pretty_name}</info> '
f
'(<comment>{self._package.pretty_version}</comment>) '
f
'to <fg=cyan>PyPI</>'
'Publishing <info>{}</info> (<comment>{}</comment>) '
'to <fg=cyan>PyPI</>'
.
format
(
self
.
_package
.
pretty_name
,
self
.
_package
.
pretty_version
)
)
if
not
repository_name
:
...
...
@@ -76,7 +81,7 @@ class Publisher:
or
repository_name
not
in
config
[
'repositories'
]
):
raise
RuntimeError
(
f
'Repository {repository_name} is not defined'
'Repository {} is not defined'
.
format
(
repository_name
)
)
url
=
config
[
'repositories'
][
repository_name
][
'url'
]
...
...
@@ -119,7 +124,9 @@ class Publisher:
Register a package to a repository.
"""
dist
=
self
.
_poetry
.
file
.
parent
/
'dist'
file
=
dist
/
f
'{self._package.name}-{self._package.version}.tar.gz'
file
=
dist
/
'{}-{}.tar.gz'
.
format
(
self
.
_package
.
name
,
self
.
_package
.
version
)
if
not
file
.
exists
():
raise
RuntimeError
(
...
...
@@ -240,12 +247,22 @@ class Publisher:
def
_upload
(
self
,
session
,
url
):
dist
=
self
.
_poetry
.
file
.
parent
/
'dist'
packages
=
dist
.
glob
(
f
'{self._package.name}-{self._package.version}*'
)
packages
=
dist
.
glob
(
'{}-{}*'
.
format
(
self
.
_package
.
name
,
self
.
_package
.
version
)
)
files
=
(
i
for
i
in
packages
if
(
i
.
match
(
f
'{self._package.name}-{self._package.version}-*.whl'
)
i
.
match
(
'{}-{}-*.whl'
.
format
(
self
.
_package
.
name
,
self
.
_package
.
version
)
)
or
i
.
match
(
f
'{self._package.name}-{self._package.version}.tar.gz'
)
i
.
match
(
'{}-{}.tar.gz'
.
format
(
self
.
_package
.
name
,
self
.
_package
.
version
)
)
)
)
...
...
@@ -254,15 +271,6 @@ class Publisher:
resp
=
self
.
_upload_file
(
session
,
url
,
file
)
# Bug 92. If we get a redirect we should abort because something seems
# funky. The behaviour is not well defined and redirects being issued
# by PyPI should never happen in reality. This should catch malicious
# redirects as well.
if
resp
.
is_redirect
:
raise
RuntimeError
(
(
'"{0}" attempted to redirect to "{1}" during upload.'
' Aborting...'
)
.
format
(
url
,
resp
.
headers
[
"location"
]))
resp
.
raise_for_status
()
def
_upload_file
(
self
,
session
,
url
,
file
):
...
...
@@ -328,7 +336,7 @@ class Publisher:
return
'sdist'
raise
ValueError
(
f
'Unknown distribution format {"".join(exts)}'
'Unknown distribution format {}'
.
format
(
''
.
join
(
exts
))
)
@staticmethod
...
...
@@ -344,5 +352,5 @@ class Publisher:
@staticmethod
def
_make_user_agent_string
():
return
user_agent
(
'
twine
'
,
__version__
,
'
poetry
'
,
__version__
,
)
poetry/mixology/possibility_set.py
View file @
135ef5d5
...
...
@@ -13,4 +13,4 @@ class PossibilitySet:
return
'[{}]'
.
format
(
', '
.
join
([
str
(
p
)
for
p
in
self
.
possibilities
]))
def
__repr__
(
self
):
return
f
'<PossibilitySet {str(self)}>'
return
'<PossibilitySet {}>'
.
format
(
str
(
self
))
poetry/mixology/resolution.py
View file @
135ef5d5
...
...
@@ -77,9 +77,11 @@ class Resolution:
self
.
_indicate_progress
()
if
hasattr
(
self
.
state
,
'pop_possibility_state'
):
self
.
_debug
(
f
'Creating possibility state for '
f
'{str(self.state.requirement)} '
f
'({len(self.state.possibilities)} remaining)'
'Creating possibility state for {} ({} remaining)'
.
format
(
str
(
self
.
state
.
requirement
),
len
(
self
.
state
.
possibilities
)
)
)
s
=
self
.
state
.
pop_possibility_state
()
if
s
:
...
...
@@ -99,9 +101,10 @@ class Resolution:
self
.
_started_at
=
datetime
.
now
()
self
.
_debug
(
f
'Starting resolution ({self._started_at})
\n
'
f
'Requested dependencies: '
f
'{[str(d) for d in self._original_requested]}'
'Starting resolution ({})
\n
Requested dependencies: {}'
.
format
(
self
.
_started_at
,
[
str
(
d
)
for
d
in
self
.
_original_requested
]
)
)
self
.
_ui
.
before_resolution
()
...
...
@@ -138,8 +141,10 @@ class Resolution:
self
.
_ui
.
after_resolution
()
self
.
_debug
(
f
'Finished resolution ({self._iteration_counter} steps) '
f
'in {elapsed:.3f} seconds'
'Finished resolution ({} steps) '
'in {:.3f} seconds'
.
format
(
self
.
_iteration_counter
,
elapsed
)
)
def
_process_topmost_state
(
self
)
->
None
:
...
...
@@ -734,7 +739,7 @@ class Resolution:
def
_attempt_to_activate
(
self
):
self
.
_debug
(
f
'Attempting to activate {str(self.possibility)}'
,
'Attempting to activate {}'
.
format
(
str
(
self
.
possibility
))
,
self
.
state
.
depth
,
)
existing_vertex
=
self
.
activated
.
vertex_named
(
self
.
state
.
name
)
...
...
@@ -778,7 +783,7 @@ class Resolution:
else
:
self
.
_create_conflict
()
self
.
_debug
(
f
'Unsatisfied by existing spec ({str(vertex.payload)})'
,
'Unsatisfied by existing spec ({})'
.
format
(
str
(
vertex
.
payload
))
,
self
.
state
.
depth
)
self
.
_unwind_for_conflict
()
...
...
@@ -805,7 +810,7 @@ class Resolution:
del
self
.
state
.
conflicts
[
self
.
name
]
self
.
_debug
(
f
'Activated {self.state.name} at {str(self.possibility)}'
,
'Activated {} at {}'
.
format
(
self
.
state
.
name
,
str
(
self
.
possibility
))
,
self
.
state
.
depth
)
self
.
activated
.
set_payload
(
self
.
state
.
name
,
self
.
possibility
)
...
...
@@ -816,8 +821,8 @@ class Resolution:
possibility_set
.
latest_version
)
self
.
_debug
(
f
'Requiring nested dependencies '
f
'({", ".join([str(d) for d in nested_dependencies])})'
,
'Requiring nested dependencies '
'({})'
.
format
(
', '
.
join
([
str
(
d
)
for
d
in
nested_dependencies
]))
,
self
.
state
.
depth
)
...
...
poetry/mixology/state.py
View file @
135ef5d5
...
...
@@ -42,8 +42,11 @@ class ResolutionState:
return
cls
(
None
,
[],
DependencyGraph
(),
None
,
None
,
0
,
{},
[])
def
__repr__
(
self
):
return
f
'<{self.__class__.__name__} {self._name} '
\
f
'({str(self.requirement)})>'
return
'<{} {} ({})>'
.
format
(
self
.
__class__
.
__name__
,
self
.
_name
,
str
(
self
.
requirement
)
)
class
PossibilityState
(
ResolutionState
):
...
...
poetry/packages/__init__.py
View file @
135ef5d5
import
os
import
re
from
poetry.semver.version_parser
import
VersionParser
from
poetry.version.markers
import
Marker
from
poetry.version.requirements
import
Requirement
from
.dependency
import
Dependency
...
...
@@ -40,8 +38,8 @@ def dependency_from_pep_508(name):
if
not
is_installable_dir
(
p
):
raise
ValueError
(
"Directory
%
r
is not installable. File 'setup.py' "
"not found."
%
name
"Directory
{!r}
is not installable. File 'setup.py' "
"not found."
.
format
(
name
)
)
link
=
Link
(
path_to_url
(
p
))
elif
is_archive_file
(
p
):
...
...
@@ -61,7 +59,7 @@ def dependency_from_pep_508(name):
link
.
filename
)
if
not
m
:
raise
ValueError
(
f
'Invalid wheel name: {link.filename}'
)
raise
ValueError
(
'Invalid wheel name: {}'
.
format
(
link
.
filename
)
)
name
=
m
.
group
(
'name'
)
version
=
m
.
group
(
'ver'
)
...
...
@@ -101,7 +99,7 @@ def dependency_from_pep_508(name):
elif
op
==
'!='
:
version
+=
'.*'
ands
.
append
(
f
'{op}{version}'
)
ands
.
append
(
'{}{}'
.
format
(
op
,
version
)
)
ors
.
append
(
' '
.
join
(
ands
))
...
...
@@ -115,7 +113,7 @@ def dependency_from_pep_508(name):
if
op
==
'=='
:
op
=
''
ands
.
append
(
f
'{op}{platform}'
)
ands
.
append
(
'{}{}'
.
format
(
op
,
platform
)
)
ors
.
append
(
' '
.
join
(
ands
))
...
...
poetry/packages/constraints/generic_constraint.py
View file @
135ef5d5
...
...
@@ -30,8 +30,11 @@ class GenericConstraint(BaseConstraint):
def
__init__
(
self
,
operator
,
version
):
if
operator
not
in
self
.
_trans_op_str
:
raise
ValueError
(
f
'Invalid operator "{operator}" given, '
f
'expected one of: {", ".join(self.supported_operators)}'
'Invalid operator "{}" given, '
'expected one of: {}'
.
format
(
operator
,
', '
.
join
(
self
.
supported_operators
)
)
)
self
.
_operator
=
self
.
_trans_op_str
[
operator
]
...
...
poetry/packages/dependency.py
View file @
135ef5d5
...
...
@@ -116,7 +116,7 @@ class Dependency:
)
def
to_pep_508
(
self
,
with_extras
=
True
)
->
str
:
requirement
=
f
'{self.pretty_name}'
requirement
=
self
.
pretty_name
if
isinstance
(
self
.
constraint
,
MultiConstraint
):
requirement
+=
' ({})'
.
format
(
','
.
join
(
...
...
@@ -147,9 +147,9 @@ class Dependency:
if
markers
:
if
len
(
markers
)
>
1
:
markers
=
[
'({})'
.
format
(
m
)
for
m
in
markers
]
requirement
+=
f
'; {" and ".join(markers)}'
requirement
+=
'; {}'
.
format
(
' and '
.
join
(
markers
))
else
:
requirement
+=
f
'; {markers[0]}'
requirement
+=
'; {}'
.
format
(
markers
[
0
])
return
requirement
...
...
@@ -166,7 +166,7 @@ class Dependency:
glue
=
' and '
if
constraint
.
is_disjunctive
():
parts
=
[
f
'({part[1]})'
if
part
[
0
]
else
f
'{part[1]}'
'({})'
.
format
(
part
[
1
])
if
part
[
0
]
else
part
[
1
]
for
part
in
parts
]
glue
=
' or '
...
...
@@ -175,7 +175,9 @@ class Dependency:
marker
=
glue
.
join
(
parts
)
else
:
marker
=
f
'{name} {constraint.string_operator} "{constraint.version}"'
marker
=
'{} {} "{}"'
.
format
(
name
,
constraint
.
string_operator
,
constraint
.
version
)
return
marker
...
...
@@ -201,7 +203,9 @@ class Dependency:
return
hash
((
self
.
_name
,
self
.
_pretty_constraint
))
def
__str__
(
self
):
return
f
'{self._pretty_name} ({self._pretty_constraint})'
return
'{} ({})'
.
format
(
self
.
_pretty_name
,
self
.
_pretty_constraint
)
def
__repr__
(
self
):
return
f
'<Dependency {str(self)}>'
return
'<Dependency {}>'
.
format
(
str
(
self
))
poetry/packages/package.py
View file @
135ef5d5
...
...
@@ -207,7 +207,7 @@ class Package:
if
python_constraint
.
matches
(
constraint
):
classifiers
.
append
(
f
'Programming Language :: Python :: {version}'
'Programming Language :: Python :: {}'
.
format
(
version
)
)
return
classifiers
...
...
poetry/packages/project_package.py
0 → 100644
View file @
135ef5d5
poetry/packages/vcs_dependency.py
View file @
135ef5d5
...
...
@@ -60,7 +60,7 @@ class VCSDependency(Dependency):
what
=
'rev'
version
=
self
.
_rev
return
f
'{what} {version}'
return
'{} {}'
.
format
(
what
,
version
)
def
is_vcs
(
self
)
->
bool
:
return
True
...
...
poetry/poetry.py
View file @
135ef5d5
...
...
@@ -62,13 +62,13 @@ class Poetry:
if
not
poetry_file
.
exists
():
raise
RuntimeError
(
f
'Poetry could not find a pyproject.toml file in {cwd}'
'Poetry could not find a pyproject.toml file in {}'
.
format
(
cwd
)
)
local_config
=
TomlFile
(
poetry_file
.
as_posix
())
.
read
(
True
)
if
'tool'
not
in
local_config
or
'poetry'
not
in
local_config
[
'tool'
]:
raise
RuntimeError
(
f
'[tool.poetry] section not found in {poetry_file.name}'
'[tool.poetry] section not found in {}'
.
format
(
poetry_file
.
name
)
)
local_config
=
local_config
[
'tool'
][
'poetry'
]
...
...
@@ -145,7 +145,8 @@ class Poetry:
/
'json'
/
'schemas'
/
'poetry-schema.json'
)
schema
=
json
.
loads
(
schema
.
read_text
())
with
schema
.
open
()
as
f
:
schema
=
json
.
loads
(
f
.
read
())
try
:
jsonschema
.
validate
(
...
...
@@ -155,7 +156,10 @@ class Poetry:
except
jsonschema
.
ValidationError
as
e
:
message
=
e
.
message
if
e
.
path
:
message
=
f
"[{'.'.join(e.path)}] {message}"
message
=
"[{}] {}"
.
format
(
'.'
.
join
(
e
.
path
),
message
)
raise
InvalidProjectFile
(
message
)
...
...
poetry/puzzle/operations/update.py
View file @
135ef5d5
...
...
@@ -18,6 +18,10 @@ class Update(Operation):
return
self
.
_target_package
@property
def
package
(
self
):
return
self
.
_target_package
@property
def
job_type
(
self
):
return
'update'
...
...
poetry/puzzle/provider.py
View file @
135ef5d5
...
...
@@ -93,9 +93,13 @@ class Provider(SpecificationProvider):
and get the information we need by checking out the specified reference.
"""
if
dependency
.
vcs
!=
'git'
:
raise
ValueError
(
f
'Unsupported VCS dependency {dependency.vcs}'
)
raise
ValueError
(
'Unsupported VCS dependency {}'
.
format
(
dependency
.
vcs
)
)
tmp_dir
=
Path
(
mkdtemp
(
prefix
=
f
'pypoetry-git-{dependency.name}'
))
tmp_dir
=
Path
(
mkdtemp
(
prefix
=
'pypoetry-git-{}'
.
format
(
dependency
.
name
))
)
try
:
git
=
Git
()
...
...
poetry/puzzle/solver.py
View file @
135ef5d5
...
...
@@ -107,7 +107,15 @@ class Solver:
break
return
list
(
reversed
(
operations
))
requested_names
=
[
r
.
name
for
r
in
requested
]
return
sorted
(
operations
,
key
=
lambda
o
:
(
1
if
not
o
.
package
.
name
not
in
requested_names
else
0
,
o
.
package
.
name
)
)
def
_get_tags_for_vertex
(
self
,
vertex
,
requested
):
tags
=
{
...
...
poetry/repositories/legacy_repository.py
View file @
135ef5d5
...
...
@@ -38,7 +38,7 @@ class LegacyRepository(PyPiRepository):
'stores'
:
{
'releases'
:
{
'driver'
:
'file'
,
'path'
:
Path
(
CACHE_DIR
)
/
'cache'
/
'repositories'
/
name
'path'
:
str
(
self
.
_cache_dir
)
},
'packages'
:
{
'driver'
:
'dict'
...
...
poetry/repositories/pool.py
View file @
135ef5d5
...
...
@@ -53,7 +53,7 @@ class Pool(BaseRepository):
def
has_package
(
self
,
package
):
raise
NotImplementedError
()
def
package
(
self
,
name
,
version
)
->
Union
[
'poetry.packages.Package'
,
None
]
:
def
package
(
self
,
name
,
version
):
package
=
poetry
.
packages
.
Package
(
name
,
version
,
version
)
if
package
in
self
.
_packages
:
return
self
.
_packages
[
self
.
_packages
.
index
(
package
)]
...
...
@@ -70,7 +70,7 @@ class Pool(BaseRepository):
def
find_packages
(
self
,
name
,
constraint
=
None
,
extras
=
None
)
->
List
[
'poetry.packages.Package'
]
:
extras
=
None
):
for
repository
in
self
.
_repositories
:
packages
=
repository
.
find_packages
(
name
,
constraint
,
extras
=
extras
)
if
packages
:
...
...
poetry/repositories/pypi_repository.py
View file @
135ef5d5
...
...
@@ -21,13 +21,14 @@ class PyPiRepository(Repository):
def
__init__
(
self
,
url
=
'https://pypi.org/'
,
disable_cache
=
False
):
self
.
_url
=
url
self
.
_disable_cache
=
disable_cache
release_cache_dir
=
Path
(
CACHE_DIR
)
/
'cache'
/
'repositories'
/
'pypi'
self
.
_cache
=
CacheManager
({
'default'
:
'releases'
,
'serializer'
:
'json'
,
'stores'
:
{
'releases'
:
{
'driver'
:
'file'
,
'path'
:
Path
(
CACHE_DIR
)
/
'cache'
/
'repositories'
/
'pypi'
'path'
:
str
(
release_cache_dir
)
},
'packages'
:
{
'driver'
:
'dict'
...
...
@@ -155,14 +156,14 @@ class PyPiRepository(Repository):
return
self
.
_get_package_info
(
name
)
return
self
.
_cache
.
store
(
'packages'
)
.
remember_forever
(
f
'{name}'
,
name
,
lambda
:
self
.
_get_package_info
(
name
)
)
def
_get_package_info
(
self
,
name
:
str
)
->
dict
:
data
=
self
.
_get
(
self
.
_url
+
f
'pypi/{name}/json'
)
data
=
self
.
_get
(
'pypi/{}/json'
.
format
(
name
)
)
if
data
is
None
:
raise
ValueError
(
f
'Package [{name}] not found.'
)
raise
ValueError
(
'Package [{}] not found.'
.
format
(
name
)
)
return
data
...
...
@@ -177,14 +178,14 @@ class PyPiRepository(Repository):
return
self
.
_get_release_info
(
name
,
version
)
return
self
.
_cache
.
remember_forever
(
f
'{name}:{version}'
,
'{}:{}'
.
format
(
name
,
version
)
,
lambda
:
self
.
_get_release_info
(
name
,
version
)
)
def
_get_release_info
(
self
,
name
:
str
,
version
:
str
)
->
dict
:
json_data
=
self
.
_get
(
self
.
_url
+
f
'pypi/{name}/{version}/json'
)
json_data
=
self
.
_get
(
'pypi/{}/{}/json'
.
format
(
name
,
version
)
)
if
json_data
is
None
:
raise
ValueError
(
f
'Package [{name}] not found.'
)
raise
ValueError
(
'Package [{}] not found.'
.
format
(
name
)
)
info
=
json_data
[
'info'
]
data
=
{
...
...
@@ -201,8 +202,8 @@ class PyPiRepository(Repository):
return
data
def
_get
(
self
,
url
:
str
)
->
Union
[
dict
,
None
]:
json_response
=
get
(
url
)
def
_get
(
self
,
endpoint
:
str
)
->
Union
[
dict
,
None
]:
json_response
=
get
(
self
.
_url
+
endpoint
)
if
json_response
.
status_code
==
404
:
return
None
...
...
poetry/semver/constraints/constraint.py
View file @
135ef5d5
...
...
@@ -38,8 +38,11 @@ class Constraint(BaseConstraint):
def
__init__
(
self
,
operator
:
str
,
version
:
str
):
if
operator
not
in
self
.
supported_operators
:
raise
ValueError
(
f
'Invalid operator "{operator}" given, '
f
'expected one of: {", ".join(self.supported_operators)}'
'Invalid operator "{}" given, '
'expected one of: {}'
.
format
(
operator
,
', '
.
join
(
self
.
supported_operators
)
)
)
self
.
_operator
=
self
.
_trans_op_str
[
operator
]
...
...
@@ -75,8 +78,11 @@ class Constraint(BaseConstraint):
def
version_compare
(
self
,
a
:
str
,
b
:
str
,
operator
:
str
)
->
bool
:
if
operator
not
in
self
.
_trans_op_str
:
raise
ValueError
(
f
'Invalid operator "{operator}" given, '
f
'expected one of: {", ".join(self.supported_operators)}'
'Invalid operator "{}" given, '
'expected one of: {}'
.
format
(
operator
,
', '
.
join
(
self
.
supported_operators
)
)
)
# If we can't normalize the version
...
...
poetry/semver/constraints/wildcard_constraint.py
View file @
135ef5d5
...
...
@@ -46,14 +46,14 @@ class WilcardConstraint(Constraint):
self
.
_constraint
=
Constraint
(
'>='
,
high_version
)
else
:
self
.
_constraint
=
parser
.
parse_constraints
(
f
'<{low_version} || >={high_version}'
'<{} || >={}'
.
format
(
low_version
,
high_version
)
)
else
:
if
low_version
==
'0.0.0.0'
:
self
.
_constraint
=
Constraint
(
'<'
,
high_version
)
else
:
self
.
_constraint
=
parser
.
parse_constraints
(
f
'>={low_version},<{high_version}'
'>={},<{}'
.
format
(
low_version
,
high_version
)
)
@property
...
...
poetry/semver/helpers.py
View file @
135ef5d5
...
...
@@ -28,10 +28,12 @@ def normalize_version(version):
version
)
if
m
:
version
=
f
'{m.group(1)}'
\
f
'{m.group(2) if m.group(2) else ".0"}'
\
f
'{m.group(3) if m.group(3) else ".0"}'
\
f
'{m.group(4) if m.group(4) else ".0"}'
version
=
'{}{}{}{}'
.
format
(
m
.
group
(
1
),
m
.
group
(
2
)
if
m
.
group
(
2
)
else
'.0'
,
m
.
group
(
3
)
if
m
.
group
(
3
)
else
'.0'
,
m
.
group
(
4
)
if
m
.
group
(
4
)
else
'.0'
,
)
index
=
5
else
:
# Some versions have the form M.m.p-\d+
...
...
@@ -43,10 +45,12 @@ def normalize_version(version):
version
)
if
m
:
version
=
f
'{m.group(1)}'
\
f
'{m.group(2) if m.group(2) else ".0"}'
\
f
'{m.group(3) if m.group(3) else ".0"}'
\
f
'{m.group(4) if m.group(4) else ".0"}'
version
=
'{}{}{}{}'
.
format
(
m
.
group
(
1
),
m
.
group
(
2
)
if
m
.
group
(
2
)
else
'.0'
,
m
.
group
(
3
)
if
m
.
group
(
3
)
else
'.0'
,
m
.
group
(
4
)
if
m
.
group
(
4
)
else
'.0'
,
)
index
=
5
else
:
# Match date(time) based versioning
...
...
@@ -69,15 +73,16 @@ def normalize_version(version):
# stable releases
return
version
version
=
f
'{version}'
\
f
'-{_expand_stability(m.group(index))}'
version
=
'{}-{}'
.
format
(
version
,
_expand_stability
(
m
.
group
(
index
)))
if
m
.
group
(
index
+
1
):
version
=
f
'{version}.{m.group(index + 1).lstrip(".-")}'
version
=
'{}.{}'
.
format
(
version
,
m
.
group
(
index
+
1
)
.
lstrip
(
'.-'
)
)
return
version
raise
ValueError
(
f
'Invalid version string "{version}"'
)
raise
ValueError
(
'Invalid version string "{}"'
.
format
(
version
)
)
def
normalize_stability
(
stability
:
str
)
->
str
:
...
...
poetry/toml/cascadedict.py
View file @
135ef5d5
...
...
@@ -19,7 +19,9 @@ class CascadeDict:
"""
Returns another instance with one more dict cascaded at the end.
"""
return
CascadeDict
(
*
self
.
_internal_dicts
,
one_more_dict
)
dicts
=
self
.
_internal_dicts
+
one_more_dict
return
CascadeDict
(
*
dicts
)
def
__getitem__
(
self
,
item
):
for
d
in
self
.
_internal_dicts
:
...
...
poetry/utils/_compat.py
0 → 100644
View file @
135ef5d5
import
sys
PY36
=
sys
.
version_info
>=
(
3
,
6
)
poetry/utils/toml_file.py
View file @
135ef5d5
...
...
@@ -17,10 +17,11 @@ class TomlFile:
return
self
.
_path
def
read
(
self
,
raw
=
False
)
->
dict
:
if
raw
:
return
toml
.
loads
(
self
.
_path
.
read_text
())
with
self
.
_path
.
open
()
as
f
:
if
raw
:
return
toml
.
loads
(
f
.
read
())
return
loads
(
self
.
_path
.
read_text
())
return
loads
(
f
.
read
())
def
write
(
self
,
data
)
->
None
:
if
not
isinstance
(
data
,
TOMLFile
):
...
...
@@ -28,7 +29,8 @@ class TomlFile:
else
:
data
=
dumps
(
data
)
self
.
_path
.
write_text
(
data
)
with
self
.
_path
.
open
(
'w'
)
as
f
:
f
.
write
(
data
)
def
__getattr__
(
self
,
item
):
return
getattr
(
self
.
_path
,
item
)
poetry/utils/venv.py
View file @
135ef5d5
...
...
@@ -23,8 +23,9 @@ class VenvError(Exception):
class
VenvCommandError
(
VenvError
):
def
__init__
(
self
,
e
:
CalledProcessError
):
message
=
f
'Command {e.cmd} errored with the following output:
\n
'
\
f
'{e.output.decode()}'
message
=
'Command {} errored with the following output:
\n
{}'
.
format
(
e
.
cmd
,
e
.
output
.
decode
()
)
super
()
.
__init__
(
message
)
...
...
@@ -64,7 +65,9 @@ class Venv:
if
not
name
:
name
=
Path
.
cwd
()
.
name
name
=
f
'{name}-py{".".join([str(v) for v in sys.version_info[:2]])}'
name
=
'{}-py{}'
.
format
(
name
,
'.'
.
join
([
str
(
v
)
for
v
in
sys
.
version_info
[:
2
]])
)
venv
=
venv_path
/
name
if
not
venv
.
exists
():
...
...
@@ -79,13 +82,17 @@ class Venv:
return
cls
()
io
.
writeln
(
f
'Creating virtualenv <info>{name}</> in {str(venv_path)}'
'Creating virtualenv <info>{}</> in {}'
.
format
(
name
,
str
(
venv_path
)
)
)
builder
=
EnvBuilder
(
with_pip
=
True
)
builder
.
create
(
str
(
venv
))
else
:
if
io
.
is_very_verbose
():
io
.
writeln
(
f
'Virtualenv <info>{name}</> already exists.'
)
io
.
writeln
(
'Virtualenv <info>{}</> already exists.'
.
format
(
name
)
)
os
.
environ
[
'VIRTUAL_ENV'
]
=
str
(
venv
)
...
...
@@ -177,8 +184,8 @@ class Venv:
try
:
value
=
self
.
run
(
'python'
,
'-c'
,
f
'"import sysconfig; '
f
'print(sysconfig.get_config_var(
\'
{var}
\'
))"'
,
'"import sysconfig; '
'print(sysconfig.get_config_var(
\'
{}
\'
))"'
.
format
(
var
)
,
shell
=
True
)
.
strip
()
except
VenvCommandError
as
e
:
...
...
poetry/version/version_selector.py
View file @
135ef5d5
...
...
@@ -66,4 +66,4 @@ class VersionSelector(object):
else
:
return
pretty_version
return
f
'^{version}'
return
'^{}'
.
format
(
version
)
pyproject.toml
View file @
135ef5d5
...
...
@@ -17,16 +17,18 @@ keywords = ["packaging", "dependency", "poetry"]
# Requirements
[tool.poetry.dependencies]
python
=
"^3.
6
"
python
=
"^3.
4
"
cleo
=
"^0.6"
requests
=
"^2.18"
toml
=
"^0.9"
cachy
=
"^0.1.
0
"
cachy
=
"^0.1.
1
"
pip-tools
=
"^1.11"
requests-toolbelt
=
"^0.8.0"
jsonschema
=
"^2.6"
pyrsistent
=
"^0.14.2"
pyparsing
=
"^2.2"
zipfile36
=
{
version
=
"^0.1"
,
python
=
">=3.4 <3.6"
}
typing
=
{
version
=
"^3.6"
,
python
=
"~3.4"
}
[tool.poetry.dev-dependencies]
pytest
=
"^3.4"
...
...
tests/installation/test_installer.py
View file @
135ef5d5
...
...
@@ -120,9 +120,10 @@ def installer(package, pool, locker, venv, installed):
def
fixture
(
name
):
file
=
Path
(
__file__
)
.
parent
/
'fixtures'
/
f
'{name}.test'
file
=
Path
(
__file__
)
.
parent
/
'fixtures'
/
'{}.test'
.
format
(
name
)
return
toml
.
loads
(
file
.
read_text
())
with
file
.
open
()
as
f
:
return
toml
.
loads
(
f
.
read
())
def
test_run_no_dependencies
(
installer
,
locker
):
...
...
tests/masonry/builders/test_complete.py
View file @
135ef5d5
...
...
@@ -48,7 +48,7 @@ def test_wheel_c_extension():
assert
whl
.
exists
()
zip
=
zipfile
.
ZipFile
(
whl
)
zip
=
zipfile
.
ZipFile
(
str
(
whl
)
)
has_compiled_extension
=
False
for
name
in
zip
.
namelist
():
...
...
@@ -80,7 +80,7 @@ def test_complete():
assert
whl
.
exists
zip
=
zipfile
.
ZipFile
(
whl
)
zip
=
zipfile
.
ZipFile
(
str
(
whl
)
)
try
:
entry_points
=
zip
.
read
(
'my_package-1.2.3.dist-info/entry_points.txt'
)
...
...
@@ -93,12 +93,12 @@ my-script=my_package:main
"""
wheel_data
=
zip
.
read
(
'my_package-1.2.3.dist-info/WHEEL'
)
.
decode
()
assert
wheel_data
==
f
"""
\
assert
wheel_data
==
"""
\
Wheel-Version: 1.0
Generator: poetry {
__version__
}
Generator: poetry {}
Root-Is-Purelib: true
Tag: py3-none-any
"""
"""
.
format
(
__version__
)
wheel_data
=
zip
.
read
(
'my_package-1.2.3.dist-info/METADATA'
)
.
decode
()
assert
wheel_data
==
"""
\
...
...
tests/masonry/builders/test_sdist.py
View file @
135ef5d5
...
...
@@ -99,8 +99,8 @@ def test_make_setup():
]
assert
ns
[
'entry_points'
]
==
{
'console_scripts'
:
[
'my-script = my_package:main'
,
'my-2nd-script = my_package:main2'
,
'my-script = my_package:main'
,
]
}
assert
ns
[
'extras_require'
]
==
{
...
...
tests/puzzle/test_solver.py
View file @
135ef5d5
...
...
@@ -165,9 +165,9 @@ def test_install_with_deps_in_order(solver, repo):
ops
=
solver
.
solve
(
request
)
check_solver_result
(
ops
,
[
{
'job'
:
'install'
,
'package'
:
package_c
},
{
'job'
:
'install'
,
'package'
:
package_b
},
{
'job'
:
'install'
,
'package'
:
package_a
},
{
'job'
:
'install'
,
'package'
:
package_b
},
{
'job'
:
'install'
,
'package'
:
package_c
},
])
...
...
@@ -239,8 +239,8 @@ def test_solver_sets_categories(solver, repo):
check_solver_result
(
ops
,
[
{
'job'
:
'install'
,
'package'
:
package_c
},
{
'job'
:
'install'
,
'package'
:
package_b
},
{
'job'
:
'install'
,
'package'
:
package_a
},
{
'job'
:
'install'
,
'package'
:
package_b
},
])
assert
package_c
.
category
==
'dev'
...
...
@@ -273,8 +273,8 @@ def test_solver_respects_root_package_python_versions(solver, repo, package):
check_solver_result
(
ops
,
[
{
'job'
:
'install'
,
'package'
:
package_c
},
{
'job'
:
'install'
,
'package'
:
package_b
},
{
'job'
:
'install'
,
'package'
:
package_a
},
{
'job'
:
'install'
,
'package'
:
package_b
},
])
...
...
@@ -326,8 +326,8 @@ def test_solver_solves_optional_and_compatible_packages(solver, repo, package):
check_solver_result
(
ops
,
[
{
'job'
:
'install'
,
'package'
:
package_c
},
{
'job'
:
'install'
,
'package'
:
package_b
},
{
'job'
:
'install'
,
'package'
:
package_a
},
{
'job'
:
'install'
,
'package'
:
package_b
},
])
...
...
@@ -356,8 +356,8 @@ def test_solver_solves_while_respecting_root_platforms(solver, repo, package):
check_solver_result
(
ops
,
[
{
'job'
:
'install'
,
'package'
:
package_c10
},
{
'job'
:
'install'
,
'package'
:
package_b
},
{
'job'
:
'install'
,
'package'
:
package_a
},
{
'job'
:
'install'
,
'package'
:
package_b
},
])
...
...
@@ -384,8 +384,8 @@ def test_solver_does_not_return_extras_if_not_requested(solver, repo):
ops
=
solver
.
solve
(
request
)
check_solver_result
(
ops
,
[
{
'job'
:
'install'
,
'package'
:
package_b
},
{
'job'
:
'install'
,
'package'
:
package_a
},
{
'job'
:
'install'
,
'package'
:
package_b
},
])
...
...
@@ -414,8 +414,8 @@ def test_solver_returns_extras_if_requested(solver, repo):
check_solver_result
(
ops
,
[
{
'job'
:
'install'
,
'package'
:
package_c
},
{
'job'
:
'install'
,
'package'
:
package_b
},
{
'job'
:
'install'
,
'package'
:
package_a
},
{
'job'
:
'install'
,
'package'
:
package_b
},
])
...
...
@@ -442,9 +442,9 @@ def test_solver_returns_prereleases_if_requested(solver, repo):
ops
=
solver
.
solve
(
request
)
check_solver_result
(
ops
,
[
{
'job'
:
'install'
,
'package'
:
package_c_dev
},
{
'job'
:
'install'
,
'package'
:
package_b
},
{
'job'
:
'install'
,
'package'
:
package_a
},
{
'job'
:
'install'
,
'package'
:
package_b
},
{
'job'
:
'install'
,
'package'
:
package_c_dev
},
])
...
...
@@ -471,7 +471,7 @@ def test_solver_does_not_return_prereleases_if_not_requested(solver, repo):
ops
=
solver
.
solve
(
request
)
check_solver_result
(
ops
,
[
{
'job'
:
'install'
,
'package'
:
package_c
},
{
'job'
:
'install'
,
'package'
:
package_b
},
{
'job'
:
'install'
,
'package'
:
package_a
},
{
'job'
:
'install'
,
'package'
:
package_b
},
{
'job'
:
'install'
,
'package'
:
package_c
},
])
tests/test_poetry.py
View file @
135ef5d5
...
...
@@ -26,12 +26,15 @@ def test_poetry():
assert
package
.
python_versions
==
'~2.7 || ^3.6'
assert
str
(
package
.
python_constraint
)
==
'>= 2.7.0.0, < 2.8.0.0 || >= 3.6.0.0, < 4.0.0.0'
dependencies
=
package
.
requires
cleo
=
dependencies
[
0
]
dependencies
=
{}
for
dep
in
package
.
requires
:
dependencies
[
dep
.
name
]
=
dep
cleo
=
dependencies
[
'cleo'
]
assert
cleo
.
pretty_constraint
==
'^0.6'
assert
not
cleo
.
is_optional
()
pendulum
=
dependencies
[
1
]
pendulum
=
dependencies
[
'pendulum'
]
assert
pendulum
.
pretty_constraint
==
'branch 2.0'
assert
pendulum
.
is_vcs
()
assert
pendulum
.
vcs
==
'git'
...
...
@@ -39,14 +42,14 @@ def test_poetry():
assert
pendulum
.
source
==
'https://github.com/sdispater/pendulum.git'
assert
pendulum
.
allows_prereleases
()
requests
=
dependencies
[
2
]
requests
=
dependencies
[
'requests'
]
assert
requests
.
pretty_constraint
==
'^2.18'
assert
not
requests
.
is_vcs
()
assert
not
requests
.
allows_prereleases
()
assert
requests
.
is_optional
()
assert
requests
.
extras
==
[
'security'
]
pathlib2
=
dependencies
[
3
]
pathlib2
=
dependencies
[
'pathlib2'
]
assert
pathlib2
.
pretty_constraint
==
'^2.2'
assert
pathlib2
.
python_versions
==
'~2.7'
assert
not
pathlib2
.
is_optional
()
...
...
@@ -56,6 +59,7 @@ def test_poetry():
def
test_check
():
complete
=
fixtures_dir
/
'complete.toml'
content
=
toml
.
loads
(
complete
.
read_text
())[
'tool'
][
'poetry'
]
with
complete
.
open
()
as
f
:
content
=
toml
.
loads
(
f
.
read
())[
'tool'
][
'poetry'
]
assert
Poetry
.
check
(
content
)
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