Commit 135ef5d5 by Sébastien Eustace

Add compatibility with Python 3.4 and 3.5

parent ac73c538
......@@ -2,6 +2,11 @@
## [Unreleased]
### Added
- Added compatibility with Python 3.4 and 3.5.
### Changed
- Improved dependency resolution to avoid unnecessary operations.
......
......@@ -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 (
......
......@@ -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)
from cleo import Command as BaseCommand
from cleo.inputs import ListInput
from poetry.poetry import Poetry
......
......@@ -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
)
)
......@@ -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
......
......@@ -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]
......
......@@ -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:
......
......@@ -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):
......
......@@ -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}'
)
elif op.job_type == 'uninstall':
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:
......
......@@ -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))
......
......@@ -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)
......
......@@ -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
......
......@@ -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)'
]
......
......@@ -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 self._meta.provides_extra:
fp.write(f'Provides-Extra: {extra}\n')
for extra in sorted(self._meta.provides_extra):
fp.write('Provides-Extra: {}\n'.format(extra))
for dep in self._meta.requires_dist:
fp.write(f'Requires-Dist: {dep}\n')
for dep in sorted(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')
......@@ -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__,
)
......@@ -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))
......@@ -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 ({})\nRequested 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
)
......
......@@ -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):
......
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))
......
......@@ -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]
......
......@@ -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))
......@@ -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
......
......@@ -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
......
......@@ -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)
......
......@@ -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'
......
......@@ -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()
......
......@@ -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 = {
......
......@@ -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'
......
......@@ -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:
......
......@@ -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
......
......@@ -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
......
......@@ -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
......
......@@ -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:
......
......@@ -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:
......
import sys
PY36 = sys.version_info >= (3, 6)
......@@ -17,10 +17,11 @@ class TomlFile:
return self._path
def read(self, raw=False) -> dict:
with self._path.open() as f:
if raw:
return toml.loads(self._path.read_text())
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)
......@@ -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:
......
......@@ -66,4 +66,4 @@ class VersionSelector(object):
else:
return pretty_version
return f'^{version}'
return '^{}'.format(version)
......@@ -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"
......
......@@ -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):
......
......@@ -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 == """\
......
......@@ -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'] == {
......
......@@ -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},
])
......@@ -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)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment