Commit af8f86cd by Sébastien Eustace

Use black coding style

parent da231001
repos:
- repo: https://github.com/ambv/black
rev: stable
hooks:
- id: black
python_version: python3.6
language: python
python:
- "2.7"
- "3.4"
- "3.5"
- "3.6"
stages:
- linting
- test
cache:
pip: true
directories:
- $HOME/.cache/pypoetry
- $HOME/.cache/pre-commit
install:
- pip install poetry --pre
- poetry install -v
script: pytest -q tests/
jobs:
include:
- python: "2.7"
- python: "3.4"
- python: "3.5"
- python: "3.6"
- stage: linting
python: "3.6"
install:
- pip install pre-commit
- pre-commit install-hooks
script:
- pre-commit run --all-files
......@@ -2,7 +2,7 @@ import os
import sys
_ROOT = os.path.dirname(os.path.realpath(__file__))
_VENDOR = os.path.join(_ROOT, '_vendor')
_VENDOR = os.path.join(_ROOT, "_vendor")
# Add vendored dependencies to path.
sys.path.insert(0, _VENDOR)
......
import sys
if __name__ == '__main__':
if __name__ == "__main__":
from .console import main
sys.exit(main())
__version__ = '0.10.1'
__version__ = "0.10.1"
......@@ -7,7 +7,6 @@ from .utils.toml_file import TOMLFile
class Config:
def __init__(self, file): # type: (TomlFile) -> None
self._file = file
if not self._file.exists():
......@@ -16,7 +15,7 @@ class Config:
else:
self._raw_content = file.read(raw=True)
self._content = file.read()
@property
def name(self):
return str(self._file.path)
......@@ -37,7 +36,7 @@ class Config:
"""
Retrieve a setting value.
"""
keys = setting_name.split('.')
keys = setting_name.split(".")
config = self._raw_content
for key in keys:
......@@ -49,7 +48,7 @@ class Config:
return config
def add_property(self, key, value):
keys = key.split('.')
keys = key.split(".")
config = self._content
for i, key in enumerate(keys):
......@@ -65,7 +64,7 @@ class Config:
self.dump()
def remove_property(self, key):
keys = key.split('.')
keys = key.split(".")
config = self._content
for i, key in enumerate(keys):
......
......@@ -41,14 +41,13 @@ from .commands.self import SelfUpdateCommand
class Application(BaseApplication):
def __init__(self):
super(Application, self).__init__('Poetry', __version__)
super(Application, self).__init__("Poetry", __version__)
self._poetry = None
self._skip_io_configuration = False
self._formatter = Formatter(True)
self._formatter.add_style('error', 'red', options=['bold'])
self._formatter.add_style("error", "red", options=["bold"])
@property
def poetry(self):
......@@ -73,7 +72,7 @@ class Application(BaseApplication):
o.set_formatter(self._formatter)
name = i.get_first_argument()
if name in ['run', 'script']:
if name in ["run", "script"]:
self._skip_io_configuration = True
i = RawArgvInput()
......@@ -82,7 +81,7 @@ class Application(BaseApplication):
def do_run(self, i, o):
name = self.get_command_name(i)
if name not in ['run', 'script']:
if name not in ["run", "script"]:
return super(Application, self).do_run(i, o)
command = self.find(name)
......@@ -124,27 +123,20 @@ class Application(BaseApplication):
]
# Cache commands
commands += [
CacheClearCommand(),
]
commands += [CacheClearCommand()]
# Debug commands
commands += [
DebugInfoCommand(),
DebugResolveCommand(),
]
commands += [DebugInfoCommand(), DebugResolveCommand()]
# Self commands
commands += [
SelfUpdateCommand(),
]
commands += [SelfUpdateCommand()]
return commands
def render_exception(self, e, o):
tb = traceback.extract_tb(sys.exc_info()[2])
title = '[<error>%s</error>] ' % e.__class__.__name__
title = "[<error>%s</error>] " % e.__class__.__name__
l = len(title)
width = self._terminal.width
if not width:
......@@ -152,28 +144,29 @@ class Application(BaseApplication):
formatter = o.get_formatter()
lines = []
for line in re.split('\r?\n', str(e)):
for splitline in [line[x:x + (width - 4)]
for x in range(0, len(line), width - 4)]:
line_length = len(
re.sub('\[[^m]*m',
'',
formatter.format(splitline))) + 4
for line in re.split("\r?\n", str(e)):
for splitline in [
line[x : x + (width - 4)] for x in range(0, len(line), width - 4)
]:
line_length = (
len(re.sub("\[[^m]*m", "", formatter.format(splitline))) + 4
)
lines.append((splitline, line_length))
l = max(line_length, l)
messages = []
empty_line = formatter.format('%s' % (' ' * l))
empty_line = formatter.format("%s" % (" " * l))
messages.append(empty_line)
messages.append(formatter.format('%s%s'
% (title,
' ' * max(0, l - len(title)))))
messages.append(
formatter.format("%s%s" % (title, " " * max(0, l - len(title))))
)
for line in lines:
messages.append(
formatter.format('<error>%s %s</error>'
% (line[0], ' ' * (l - line[1])))
formatter.format(
"<error>%s %s</error>" % (line[0], " " * (l - line[1]))
)
)
messages.append(empty_line)
......@@ -181,7 +174,7 @@ class Application(BaseApplication):
o.writeln(messages, Output.OUTPUT_RAW)
if Output.VERBOSITY_VERBOSE <= o.get_verbosity():
o.writeln('<comment>Exception trace:</comment>')
o.writeln("<comment>Exception trace:</comment>")
for exc_info in tb:
file_ = exc_info[0]
......@@ -189,15 +182,15 @@ class Application(BaseApplication):
function = exc_info[2]
line = exc_info[3]
o.writeln(' <info>%s</info> in <fg=cyan>%s()</> '
'at line <info>%s</info>'
% (file_, function, line_number))
o.writeln(' %s' % line)
o.writeln(
" <info>%s</info> in <fg=cyan>%s()</> "
"at line <info>%s</info>" % (file_, function, line_number)
)
o.writeln(" %s" % line)
o.writeln('')
o.writeln("")
if self._running_command is not None:
o.writeln('<info>%s</info>'
% self._running_command.get_synopsis())
o.writeln("<info>%s</info>" % self._running_command.get_synopsis())
o.writeln('')
o.writeln("")
......@@ -9,8 +9,10 @@ class AboutCommand(Command):
"""
def handle(self):
self.line("""<info>Poetry - Package Management for Python</info>
self.line(
"""<info>Poetry - Package Management for Python</info>
<comment>Poetry is a dependency manager tracking local dependencies of your projects and libraries.
See <fg=blue>https://github.com/sdispater/poetry</> for more information.</comment>
""")
"""
)
......@@ -25,51 +25,44 @@ class AddCommand(VenvCommand, InitCommand):
If you do not specify a version constraint, poetry will choose a suitable one based on the available package versions.
"""
_loggers = [
'poetry.repositories.pypi_repository'
]
_loggers = ["poetry.repositories.pypi_repository"]
def handle(self):
from poetry.installation import Installer
from poetry.semver import parse_constraint
packages = self.argument('name')
is_dev = self.option('dev')
packages = self.argument("name")
is_dev = self.option("dev")
if (self.option('git') or self.option('path') or self.option('extras')) and len(packages) > 1:
if (self.option("git") or self.option("path") or self.option("extras")) and len(
packages
) > 1:
raise ValueError(
'You can only specify one package '
'when using the --git or --path options'
"You can only specify one package "
"when using the --git or --path options"
)
if self.option('git') and self.option('path'):
raise RuntimeError(
'--git and --path cannot be used at the same time'
)
if self.option("git") and self.option("path"):
raise RuntimeError("--git and --path cannot be used at the same time")
section = 'dependencies'
section = "dependencies"
if is_dev:
section = 'dev-dependencies'
section = "dev-dependencies"
original_content = self.poetry.file.read()
content = self.poetry.file.read()
poetry_content = content['tool']['poetry']
poetry_content = content["tool"]["poetry"]
for name in packages:
for key in poetry_content[section]:
if key.lower() == name.lower():
raise ValueError(
'Package {} is already present'.format(name)
)
if self.option('git') or self.option('path'):
requirements = {
packages[0]: ''
}
raise ValueError("Package {} is already present".format(name))
if self.option("git") or self.option("path"):
requirements = {packages[0]: ""}
else:
requirements = self._determine_requirements(
packages,
allow_prereleases=self.option('allow-prereleases')
packages, allow_prereleases=self.option("allow-prereleases")
)
requirements = self._format_requirements(requirements)
......@@ -78,43 +71,41 @@ If you do not specify a version constraint, poetry will choose a suitable one ba
parse_constraint(constraint)
for name, constraint in requirements.items():
constraint = {
'version': constraint
}
constraint = {"version": constraint}
if self.option('git'):
del constraint['version']
if self.option("git"):
del constraint["version"]
constraint['git'] = self.option('git')
elif self.option('path'):
del constraint['version']
constraint["git"] = self.option("git")
elif self.option("path"):
del constraint["version"]
constraint['path'] = self.option('path')
constraint["path"] = self.option("path")
if self.option('optional'):
constraint['optional'] = True
if self.option("optional"):
constraint["optional"] = True
if self.option('allow-prereleases'):
constraint['allows-prereleases'] = True
if self.option("allow-prereleases"):
constraint["allows-prereleases"] = True
if self.option('extras'):
if self.option("extras"):
extras = []
for extra in self.option('extras'):
if ' ' in extra:
extras += [e.strip() for e in extra.split(' ')]
for extra in self.option("extras"):
if " " in extra:
extras += [e.strip() for e in extra.split(" ")]
else:
extras.append(extra)
constraint['extras'] = self.option('extras')
constraint["extras"] = self.option("extras")
if self.option('python'):
constraint['python'] = self.option('python')
if self.option("python"):
constraint["python"] = self.option("python")
if self.option('platform'):
constraint['platform'] = self.option('platform')
if self.option("platform"):
constraint["platform"] = self.option("platform")
if len(constraint) == 1 and 'version' in constraint:
constraint = constraint['version']
if len(constraint) == 1 and "version" in constraint:
constraint = constraint["version"]
poetry_content[section][name] = constraint
......@@ -122,7 +113,7 @@ If you do not specify a version constraint, poetry will choose a suitable one ba
self.poetry.file.write(content)
# Cosmetic new line
self.line('')
self.line("")
# Update packages
self.reset_poetry()
......@@ -132,10 +123,10 @@ If you do not specify a version constraint, poetry will choose a suitable one ba
self.venv,
self.poetry.package,
self.poetry.locker,
self.poetry.pool
self.poetry.pool,
)
installer.dry_run(self.option('dry-run'))
installer.dry_run(self.option("dry-run"))
installer.update(True)
installer.whitelist(requirements)
......@@ -146,13 +137,13 @@ If you do not specify a version constraint, poetry will choose a suitable one ba
raise
if status != 0 or self.option('dry-run'):
if status != 0 or self.option("dry-run"):
# Revert changes
if not self.option('dry-run'):
if not self.option("dry-run"):
self.error(
'\n'
'Addition failed, reverting pyproject.toml '
'to its original content.'
"\n"
"Addition failed, reverting pyproject.toml "
"to its original content."
)
self.poetry.file.write(original_content)
......
......@@ -12,14 +12,15 @@ class BuildCommand(VenvCommand):
def handle(self):
from poetry.masonry import Builder
fmt = 'all'
if self.option('format'):
fmt = self.option('format')
fmt = "all"
if self.option("format"):
fmt = self.option("format")
package = self.poetry.package
self.line(
'Building <info>{}</> (<comment>{}</>)'
.format(package.pretty_name, package.version)
"Building <info>{}</> (<comment>{}</>)".format(
package.pretty_name, package.version
)
)
builder = Builder(self.poetry, self.venv, self.output)
......
......@@ -16,30 +16,27 @@ class CacheClearCommand(Command):
from cachy import CacheManager
from poetry.locations import CACHE_DIR
cache = self.argument('cache')
cache = self.argument("cache")
parts = cache.split(':')
cache_dir = os.path.join(CACHE_DIR, 'cache', 'repositories', parts[0])
cache = CacheManager({
'default': parts[0],
'serializer': 'json',
'stores': {
parts[0]: {
'driver': 'file',
'path': cache_dir
}
parts = cache.split(":")
cache_dir = os.path.join(CACHE_DIR, "cache", "repositories", parts[0])
cache = CacheManager(
{
"default": parts[0],
"serializer": "json",
"stores": {parts[0]: {"driver": "file", "path": cache_dir}},
}
})
)
if len(parts) == 1:
if not self.option('all'):
if not self.option("all"):
raise RuntimeError(
'Add the --all option if you want to clear all '
'{} caches'.format(parts[0])
"Add the --all option if you want to clear all "
"{} caches".format(parts[0])
)
if not os.path.exists(cache_dir):
self.line('No cache entries for {}'.format(parts[0]))
self.line("No cache entries for {}".format(parts[0]))
return 0
# Calculate number of entries
......@@ -48,7 +45,7 @@ class CacheClearCommand(Command):
entries_count += len(files)
delete = self.confirm(
'<question>Delete {} entries?</>'.format(entries_count)
"<question>Delete {} entries?</>".format(entries_count)
)
if not delete:
return 0
......@@ -56,25 +53,21 @@ class CacheClearCommand(Command):
cache.flush()
elif len(parts) == 2:
raise RuntimeError(
'Only specifying the package name is not yet supported. '
'Add a specific version to clear'
"Only specifying the package name is not yet supported. "
"Add a specific version to clear"
)
elif len(parts) == 3:
package = parts[1]
version = parts[2]
if not cache.has('{}:{}'.format(package, version)):
self.line(
'No cache entries for {}:{}'.format(package, version)
)
if not cache.has("{}:{}".format(package, version)):
self.line("No cache entries for {}:{}".format(package, version))
return 0
delete = self.confirm(
'Delete cache entry {}:{}'.format(package, version)
)
delete = self.confirm("Delete cache entry {}:{}".format(package, version))
if not delete:
return 0
cache.forget('{}:{}'.format(package, version))
cache.forget("{}:{}".format(package, version))
else:
raise ValueError('Invalid cache key')
raise ValueError("Invalid cache key")
......@@ -12,4 +12,4 @@ class CheckCommand(Command):
# Load poetry and display errors, if any
self.poetry.check(self.poetry.local_config, strict=True)
self.info('All set!')
self.info("All set!")
......@@ -7,11 +7,7 @@ from ..styles.poetry import PoetryStyle
class CommandFormatter(logging.Formatter):
_colors = {
'error': 'fg=red',
'warning': 'fg=yellow',
'debug': 'fg=blue',
}
_colors = {"error": "fg=red", "warning": "fg=yellow", "debug": "fg=blue"}
def format(self, record):
if not record.exc_info:
......@@ -19,7 +15,7 @@ class CommandFormatter(logging.Formatter):
msg = record.msg
if level in self._colors:
msg = '<{}>{}</>'.format(self._colors[level], msg)
msg = "<{}>{}</>".format(self._colors[level], msg)
return msg
......@@ -27,7 +23,6 @@ class CommandFormatter(logging.Formatter):
class CommandHandler(logging.Handler):
def __init__(self, command):
self._command = command
......@@ -44,7 +39,7 @@ class CommandHandler(logging.Handler):
try:
msg = self.format(record)
level = record.levelname.lower()
err = level in ('warning', 'error', 'exception', 'critical')
err = level in ("warning", "error", "exception", "critical")
if err:
self._command.output.write_error(msg, newline=True)
else:
......
......@@ -16,36 +16,42 @@ class DebugInfoCommand(VenvCommand):
package = poetry.package
venv = self.venv
poetry_python_version = '.'.join(str(s) for s in sys.version_info[:3])
self.output.title('Poetry')
self.output.listing([
'<info>Version</info>: <comment>{}</>'.format(poetry.VERSION),
'<info>Python</info>: <comment>{}</>'.format(poetry_python_version)
])
self.line('')
venv_python_version = '.'.join(str(s) for s in venv.version_info[:3])
self.output.title('Virtualenv')
self.output.listing([
'<info>Python</info>: <comment>{}</>'.format(
venv_python_version
),
'<info>Implementation</info>: <comment>{}</>'.format(
venv.python_implementation
),
'<info>Path</info>: <comment>{}</>'.format(
venv.venv if venv.is_venv() else 'NA'
)
])
self.line('')
self.output.title('System')
self.output.listing([
'<info>Platform</info>: <comment>{}</>'.format(sys.platform),
'<info>OS</info>: <comment>{}</>'.format(os.name),
])
self.line('')
poetry_python_version = ".".join(str(s) for s in sys.version_info[:3])
self.output.title("Poetry")
self.output.listing(
[
"<info>Version</info>: <comment>{}</>".format(poetry.VERSION),
"<info>Python</info>: <comment>{}</>".format(poetry_python_version),
]
)
self.line("")
venv_python_version = ".".join(str(s) for s in venv.version_info[:3])
self.output.title("Virtualenv")
self.output.listing(
[
"<info>Python</info>: <comment>{}</>".format(
venv_python_version
),
"<info>Implementation</info>: <comment>{}</>".format(
venv.python_implementation
),
"<info>Path</info>: <comment>{}</>".format(
venv.venv if venv.is_venv() else "NA"
),
]
)
self.line("")
self.output.title("System")
self.output.listing(
[
"<info>Platform</info>: <comment>{}</>".format(sys.platform),
"<info>OS</info>: <comment>{}</>".format(os.name),
]
)
self.line("")
......@@ -15,9 +15,7 @@ class DebugResolveCommand(Command):
{ --python= : Python version(s) to use for resolution. }
"""
_loggers = [
'poetry.repositories.pypi_repository'
]
_loggers = ["poetry.repositories.pypi_repository"]
def handle(self):
from poetry.packages import Dependency
......@@ -26,7 +24,7 @@ class DebugResolveCommand(Command):
from poetry.repositories.repository import Repository
from poetry.semver import parse_constraint
packages = self.argument('package')
packages = self.argument("package")
if not packages:
package = self.poetry.package
......@@ -42,9 +40,9 @@ class DebugResolveCommand(Command):
for name, constraint in requirements.items():
dep = Dependency(name, constraint)
extras = []
for extra in self.option('extras'):
if ' ' in extra:
extras += [e.strip() for e in extra.split(' ')]
for extra in self.option("extras"):
if " " in extra:
extras += [e.strip() for e in extra.split(" ")]
else:
extras.append(extra)
......@@ -54,33 +52,29 @@ class DebugResolveCommand(Command):
dependencies.append(dep)
package = ProjectPackage(
self.poetry.package.name,
self.poetry.package.version
self.poetry.package.name, self.poetry.package.version
)
package.python_versions = self.option('python') or self.poetry.package.python_versions
package.python_versions = (
self.option("python") or self.poetry.package.python_versions
)
for dep in dependencies:
package.requires.append(dep)
solver = Solver(
package,
self.poetry.pool,
Repository(),
Repository(),
self.output
package, self.poetry.pool, Repository(), Repository(), self.output
)
ops = solver.solve()
self.line('')
self.line('Resolution results:')
self.line('')
self.line("")
self.line("Resolution results:")
self.line("")
for op in ops:
package = op.package
self.line(
' - <info>{}</info> (<comment>{}</comment>)'
.format(
" - <info>{}</info> (<comment>{}</comment>)".format(
package.name, package.version
)
)
......@@ -92,12 +86,10 @@ class DebugResolveCommand(Command):
requires = self._parse_name_version_pairs(requires)
result = []
for requirement in requires:
if 'version' not in requirement:
requirement['version'] = '*'
if "version" not in requirement:
requirement["version"] = "*"
result.append(
'{} {}'.format(requirement['name'], requirement['version'])
)
result.append("{} {}".format(requirement["name"], requirement["version"]))
return result
......@@ -105,19 +97,14 @@ class DebugResolveCommand(Command):
result = []
for i in range(len(pairs)):
pair = re.sub('^([^=: ]+)[=: ](.*)$', '\\1 \\2', pairs[i].strip())
pair = re.sub("^([^=: ]+)[=: ](.*)$", "\\1 \\2", pairs[i].strip())
pair = pair.strip()
if ' ' in pair:
name, version = pair.split(' ', 2)
result.append({
'name': name,
'version': version
})
if " " in pair:
name, version = pair.split(" ", 2)
result.append({"name": name, "version": version})
else:
result.append({
'name': pair
})
result.append({"name": pair})
return result
......@@ -125,6 +112,6 @@ class DebugResolveCommand(Command):
requires = {}
requirements = self._parse_name_version_pairs(requirements)
for requirement in requirements:
requires[requirement['name']] = requirement['version']
requires[requirement["name"]] = requirement["version"]
return requires
......@@ -20,15 +20,15 @@ The <info>develop</info> command installs the current project in development mod
from poetry.utils._compat import decode
from poetry.utils.venv import NullVenv
setup = self.poetry.file.parent / 'setup.py'
setup = self.poetry.file.parent / "setup.py"
has_setup = setup.exists()
if has_setup:
self.line('<warning>A setup.py file already exists. Using it.</warning>')
self.line("<warning>A setup.py file already exists. Using it.</warning>")
else:
builder = SdistBuilder(self.poetry, NullVenv(), NullIO())
with setup.open('w') as f:
with setup.open("w") as f:
f.write(decode(builder.build_setup()))
try:
......@@ -38,12 +38,11 @@ The <info>develop</info> command installs the current project in development mod
os.remove(str(setup))
def _install(self, setup):
self.call('install')
self.call("install")
self.line(
'Installing <info>{}</info> (<comment>{}</comment>)'.format(
self.poetry.package.pretty_name,
self.poetry.package.pretty_version
"Installing <info>{}</info> (<comment>{}</comment>)".format(
self.poetry.package.pretty_name, self.poetry.package.pretty_version
)
)
self.venv.run('pip', 'install', '-e', str(setup.parent), '--no-deps')
self.venv.run("pip", "install", "-e", str(setup.parent), "--no-deps")
......@@ -21,9 +21,7 @@ exist it will look for <comment>pyproject.toml</> and do the same.
<info>poetry install</info>
"""
_loggers = [
'poetry.repositories.pypi_repository'
]
_loggers = ["poetry.repositories.pypi_repository"]
def handle(self):
from poetry.installation import Installer
......@@ -33,20 +31,20 @@ exist it will look for <comment>pyproject.toml</> and do the same.
self.venv,
self.poetry.package,
self.poetry.locker,
self.poetry.pool
self.poetry.pool,
)
extras = []
for extra in self.option('extras'):
if ' ' in extra:
extras += [e.strip() for e in extra.split(' ')]
for extra in self.option("extras"):
if " " in extra:
extras += [e.strip() for e in extra.split(" ")]
else:
extras.append(extra)
installer.extras(extras)
installer.dev_mode(not self.option('no-dev'))
installer.develop(self.option('develop'))
installer.dry_run(self.option('dry-run'))
installer.verbose(self.option('verbose'))
installer.dev_mode(not self.option("no-dev"))
installer.develop(self.option("develop"))
installer.dry_run(self.option("dry-run"))
installer.verbose(self.option("verbose"))
return installer.run()
......@@ -14,9 +14,7 @@ the current directory, processes it, and locks the depdencies in the <comment>py
<info>poetry lock</info>
"""
_loggers = [
'poetry.repositories.pypi_repository'
]
_loggers = ["poetry.repositories.pypi_repository"]
def handle(self):
from poetry.installation import Installer
......@@ -26,7 +24,7 @@ the current directory, processes it, and locks the depdencies in the <comment>py
self.venv,
self.poetry.package,
self.poetry.locker,
self.poetry.pool
self.poetry.pool,
)
installer.update(True)
......
......@@ -16,40 +16,39 @@ class NewCommand(Command):
from poetry.utils._compat import Path
from poetry.vcs.git import GitConfig
if self.option('src'):
layout_ = layout('src')
if self.option("src"):
layout_ = layout("src")
else:
layout_ = layout('standard')
layout_ = layout("standard")
path = Path.cwd() / Path(self.argument('path'))
name = self.option('name')
path = Path.cwd() / Path(self.argument("path"))
name = self.option("name")
if not name:
name = path.name
if path.exists():
if list(path.glob('*')):
if list(path.glob("*")):
# Directory is not empty. Aborting.
raise RuntimeError(
'Destination <fg=yellow>{}</> '
'exists and is not empty'.format(
path
)
"Destination <fg=yellow>{}</> "
"exists and is not empty".format(path)
)
readme_format = 'rst'
readme_format = "rst"
config = GitConfig()
author = None
if config.get('user.name'):
author = config['user.name']
author_email = config.get('user.email')
if config.get("user.name"):
author = config["user.name"]
author_email = config.get("user.email")
if author_email:
author += ' <{}>'.format(author_email)
author += " <{}>".format(author_email)
layout_ = layout_(name, '0.1.0', author=author, readme_format=readme_format)
layout_ = layout_(name, "0.1.0", author=author, readme_format=readme_format)
layout_.create(path)
self.line(
'Created package <info>{}</> in <fg=blue>{}</>'
.format(name, path.relative_to(Path.cwd()))
"Created package <info>{}</> in <fg=blue>{}</>".format(
name, path.relative_to(Path.cwd())
)
)
......@@ -27,31 +27,29 @@ the config command.
publisher = Publisher(self.poetry, self.output)
# Building package first, if told
if self.option('build'):
if self.option("build"):
if publisher.files:
if not self.confirm(
'There are <info>{}</info> files ready for publishing. '
'Build anyway?'.format(len(publisher.files))
"There are <info>{}</info> files ready for publishing. "
"Build anyway?".format(len(publisher.files))
):
self.line_error('<error>Aborted!</error>')
self.line_error("<error>Aborted!</error>")
return 1
self.call('build')
self.call("build")
files = publisher.files
if not files:
self.line_error(
'<error>No files to publish. '
'Run poetry build first or use the --build option.</error>'
"<error>No files to publish. "
"Run poetry build first or use the --build option.</error>"
)
return 1
self.line('')
self.line("")
publisher.publish(
self.option('repository'),
self.option('username'),
self.option('password')
self.option("repository"), self.option("username"), self.option("password")
)
......@@ -17,22 +17,20 @@ list of installed packages
<info>poetry remove</info>"""
_loggers = [
'poetry.repositories.pypi_repository'
]
_loggers = ["poetry.repositories.pypi_repository"]
def handle(self):
from poetry.installation import Installer
packages = self.argument('packages')
is_dev = self.option('dev')
packages = self.argument("packages")
is_dev = self.option("dev")
original_content = self.poetry.file.read()
content = self.poetry.file.read()
poetry_content = content['tool']['poetry']
section = 'dependencies'
poetry_content = content["tool"]["poetry"]
section = "dependencies"
if is_dev:
section = 'dev-dependencies'
section = "dev-dependencies"
# Deleting entries
requirements = {}
......@@ -45,7 +43,7 @@ list of installed packages
break
if not found:
raise ValueError('Package {} not found'.format(name))
raise ValueError("Package {} not found".format(name))
for key in requirements:
del poetry_content[section][key]
......@@ -61,10 +59,10 @@ list of installed packages
self.venv,
self.poetry.package,
self.poetry.locker,
self.poetry.pool
self.poetry.pool,
)
installer.dry_run(self.option('dry-run'))
installer.dry_run(self.option("dry-run"))
installer.update(True)
installer.whitelist(requirements)
......@@ -75,13 +73,13 @@ list of installed packages
raise
if status != 0 or self.option('dry-run'):
if status != 0 or self.option("dry-run"):
# Revert changes
if not self.option('dry-run'):
if not self.option("dry-run"):
self.error(
'\n'
'Removal failed, reverting pyproject.toml '
'to its original content.'
"\n"
"Removal failed, reverting pyproject.toml "
"to its original content."
)
self.poetry.file.write(original_content)
......
......@@ -10,9 +10,9 @@ class RunCommand(VenvCommand):
"""
def handle(self):
args = self.argument('args')
args = self.argument("args")
script = args[0]
scripts = self.poetry.local_config.get('scripts')
scripts = self.poetry.local_config.get("scripts")
if scripts and script in scripts:
return self.run_script(scripts[script], args)
......@@ -22,18 +22,17 @@ class RunCommand(VenvCommand):
return venv.execute(*args)
def run_script(self, script, args):
module, callable_ = script.split(':')
module, callable_ = script.split(":")
src_in_sys_path = 'sys.path.append(\'src\'); ' \
if self._module.is_in_src() else ''
src_in_sys_path = "sys.path.append('src'); " if self._module.is_in_src() else ""
cmd = ['python', '-c']
cmd = ["python", "-c"]
cmd += [
'"import sys; '
'from importlib import import_module; '
'sys.argv = {!r}; {}'
'import_module(\'{}\').{}()"'.format(
"from importlib import import_module; "
"sys.argv = {!r}; {}"
"import_module('{}').{}()\"".format(
args, src_in_sys_path, module, callable_
)
]
......@@ -47,20 +46,21 @@ class RunCommand(VenvCommand):
poetry = self.poetry
package = poetry.package
path = poetry.file.parent
module = Module(
package.name, path.as_posix()
)
module = Module(package.name, path.as_posix())
return module
def merge_application_definition(self, merge_args=True):
if self._application is None \
or (self._application_definition_merged
and (self._application_definition_merged_with_args or not merge_args)):
if self._application is None or (
self._application_definition_merged
and (self._application_definition_merged_with_args or not merge_args)
):
return
if merge_args:
current_arguments = self._definition.get_arguments()
self._definition.set_arguments(self._application.get_definition().get_arguments())
self._definition.set_arguments(
self._application.get_definition().get_arguments()
)
self._definition.add_arguments(current_arguments)
self._application_definition_merged = True
......
......@@ -11,32 +11,31 @@ class ScriptCommand(VenvCommand):
"""
def handle(self):
self.line('<warning>script is deprecated use run instead.</warning>')
self.line('')
self.line("<warning>script is deprecated use run instead.</warning>")
self.line("")
script = self.argument('script-name')
argv = [script] + self.argument('args')
script = self.argument("script-name")
argv = [script] + self.argument("args")
scripts = self.poetry.local_config.get('scripts')
scripts = self.poetry.local_config.get("scripts")
if not scripts:
raise RuntimeError('No scripts defined in pyproject.toml')
raise RuntimeError("No scripts defined in pyproject.toml")
if script not in scripts:
raise ValueError('Script {} is not defined'.format(script))
raise ValueError("Script {} is not defined".format(script))
module, callable_ = scripts[script].split(':')
module, callable_ = scripts[script].split(":")
src_in_sys_path = 'sys.path.append(\'src\'); '\
if self._module.is_in_src() else ''
src_in_sys_path = "sys.path.append('src'); " if self._module.is_in_src() else ""
cmd = ['python', '-c']
cmd = ["python", "-c"]
cmd += [
'"import sys; '
'from importlib import import_module; '
'sys.argv = {!r}; {}'
'import_module(\'{}\').{}()"'.format(
argv, src_in_sys_path, module, callable_
"from importlib import import_module; "
"sys.argv = {!r}; {}"
"import_module('{}').{}()\"".format(
argv, src_in_sys_path, module, callable_
)
]
......@@ -49,20 +48,21 @@ class ScriptCommand(VenvCommand):
poetry = self.poetry
package = poetry.package
path = poetry.file.parent
module = Module(
package.name, path.as_posix()
)
module = Module(package.name, path.as_posix())
return module
def merge_application_definition(self, merge_args=True):
if self._application is None \
or (self._application_definition_merged
and (self._application_definition_merged_with_args or not merge_args)):
if self._application is None or (
self._application_definition_merged
and (self._application_definition_merged_with_args or not merge_args)
):
return
if merge_args:
current_arguments = self._definition.get_arguments()
self._definition.set_arguments(self._application.get_definition().get_arguments())
self._definition.set_arguments(
self._application.get_definition().get_arguments()
)
self._definition.add_arguments(current_arguments)
self._application_definition_merged = True
......
......@@ -14,22 +14,18 @@ class SearchCommand(Command):
from poetry.repositories.pypi_repository import PyPiRepository
flags = PyPiRepository.SEARCH_FULLTEXT
if self.option('only-name'):
if self.option("only-name"):
flags = PyPiRepository.SEARCH_FULLTEXT
results = PyPiRepository().search(self.argument('tokens'), flags)
results = PyPiRepository().search(self.argument("tokens"), flags)
for result in results:
self.line('')
name = '<info>{}</>'.format(
result.name
)
self.line("")
name = "<info>{}</>".format(result.name)
name += ' (<comment>{}</>)'.format(result.version)
name += " (<comment>{}</>)".format(result.version)
self.line(name)
if result.description:
self.line(
' {}'.format(result.description)
)
self.line(" {}".format(result.description))
......@@ -23,20 +23,22 @@ class SelfUpdateCommand(Command):
from poetry.__version__ import __version__
from poetry.repositories.pypi_repository import PyPiRepository
version = self.argument('version')
version = self.argument("version")
if not version:
version = '>=' + __version__
version = ">=" + __version__
repo = PyPiRepository(fallback=False)
packages = repo.find_packages('poetry', version, allow_prereleases=self.option('preview'))
packages = repo.find_packages(
"poetry", version, allow_prereleases=self.option("preview")
)
if not packages:
self.line('No release found for the specified version')
self.line("No release found for the specified version")
return
packages.sort(
key=cmp_to_key(
lambda x, y:
0 if x.version == y.version
lambda x, y: 0
if x.version == y.version
else int(x.version < y.version or -1)
)
)
......@@ -44,7 +46,7 @@ class SelfUpdateCommand(Command):
release = None
for package in reversed(packages):
if package.is_prerelease():
if self.option('preview'):
if self.option("preview"):
release = package
break
......@@ -56,22 +58,25 @@ class SelfUpdateCommand(Command):
break
if release is None:
self.line('No new release found')
self.line("No new release found")
return
if release.version == __version__:
self.line('You are using the latest version')
self.line("You are using the latest version")
return
try:
self.update(release)
except subprocess.CalledProcessError as e:
self.line('')
self.output.block([
'[CalledProcessError]',
'An error has occured: {}'.format(str(e)),
e.output
], style='error')
self.line("")
self.output.block(
[
"[CalledProcessError]",
"An error has occured: {}".format(str(e)),
e.output,
],
style="error",
)
return e.returncode
......@@ -80,48 +85,51 @@ class SelfUpdateCommand(Command):
from poetry.utils.helpers import temporary_directory
version = release.version
self.line('Updating to <info>{}</info>'.format(version))
self.line("Updating to <info>{}</info>".format(version))
prefix = sys.prefix
base_prefix = getattr(sys, 'base_prefix', None)
real_prefix = getattr(sys, 'real_prefix', None)
base_prefix = getattr(sys, "base_prefix", None)
real_prefix = getattr(sys, "real_prefix", None)
prefix_poetry = Path(prefix) / 'bin' / 'poetry'
prefix_poetry = Path(prefix) / "bin" / "poetry"
if prefix_poetry.exists():
pip = (prefix_poetry.parent / 'pip').resolve()
pip = (prefix_poetry.parent / "pip").resolve()
elif (
base_prefix
and base_prefix != prefix
and (Path(base_prefix) / 'bin' / 'poetry').exists()
and (Path(base_prefix) / "bin" / "poetry").exists()
):
pip = Path(base_prefix) / 'bin' / 'pip'
pip = Path(base_prefix) / "bin" / "pip"
elif real_prefix:
pip = Path(real_prefix) / 'bin' / 'pip'
pip = Path(real_prefix) / "bin" / "pip"
else:
pip = Path(prefix) / 'bin' / 'pip'
pip = Path(prefix) / "bin" / "pip"
if not pip.exists():
raise RuntimeError('Unable to determine poetry\'s path')
raise RuntimeError("Unable to determine poetry's path")
with temporary_directory(prefix='poetry-update-') as temp_dir:
with temporary_directory(prefix="poetry-update-") as temp_dir:
temp_dir = Path(temp_dir)
dist = temp_dir / 'dist'
self.line(' - Getting dependencies')
dist = temp_dir / "dist"
self.line(" - Getting dependencies")
self.process(
str(pip), 'install', '-U',
'poetry=={}'.format(release.version),
'--target', str(dist)
str(pip),
"install",
"-U",
"poetry=={}".format(release.version),
"--target",
str(dist),
)
self.line(' - Vendorizing dependencies')
self.line(" - Vendorizing dependencies")
poetry_dir = dist / 'poetry'
vendor_dir = poetry_dir / '_vendor'
poetry_dir = dist / "poetry"
vendor_dir = poetry_dir / "_vendor"
# Everything, except poetry itself, should
# be put in the _vendor directory
for file in dist.glob('*'):
if file.name.startswith('poetry'):
for file in dist.glob("*"):
if file.name.startswith("poetry"):
continue
dest = vendor_dir / file.name
......@@ -132,40 +140,38 @@ class SelfUpdateCommand(Command):
shutil.copy(str(file), str(dest))
os.unlink(str(file))
wheel_data = dist / 'poetry-{}.dist-info'.format(version) / 'WHEEL'
wheel_data = dist / "poetry-{}.dist-info".format(version) / "WHEEL"
with wheel_data.open() as f:
wheel_data = Parser().parsestr(f.read())
tag = wheel_data['Tag']
tag = wheel_data["Tag"]
# Repack everything and install
self.line(' - Updating <info>poetry</info>')
self.line(" - Updating <info>poetry</info>")
shutil.make_archive(
str(temp_dir / 'poetry-{}-{}'.format(version, tag)),
format='zip',
root_dir=str(dist)
str(temp_dir / "poetry-{}-{}".format(version, tag)),
format="zip",
root_dir=str(dist),
)
os.rename(
str(temp_dir / 'poetry-{}-{}.zip'.format(version, tag)),
str(temp_dir / 'poetry-{}-{}.whl'.format(version, tag)),
str(temp_dir / "poetry-{}-{}.zip".format(version, tag)),
str(temp_dir / "poetry-{}-{}.whl".format(version, tag)),
)
self.process(
str(pip),
'install',
'--upgrade',
'--no-deps',
str(temp_dir / 'poetry-{}-{}.whl'.format(version, tag))
"install",
"--upgrade",
"--no-deps",
str(temp_dir / "poetry-{}-{}.whl".format(version, tag)),
)
self.line('')
self.line("")
self.line(
'<info>poetry</> (<comment>{}</>) '
'successfully installed!'.format(
version
)
"<info>poetry</> (<comment>{}</>) "
"successfully installed!".format(version)
)
def process(self, *args):
......
......@@ -12,28 +12,26 @@ class UpdateCommand(VenvCommand):
(implicitly enables --verbose). }
"""
_loggers = [
'poetry.repositories.pypi_repository'
]
_loggers = ["poetry.repositories.pypi_repository"]
def handle(self):
from poetry.installation import Installer
packages = self.argument('packages')
packages = self.argument("packages")
installer = Installer(
self.output,
self.venv,
self.poetry.package,
self.poetry.locker,
self.poetry.pool
self.poetry.pool,
)
if packages:
installer.whitelist({name: '*' for name in packages})
installer.whitelist({name: "*" for name in packages})
installer.dev_mode(not self.option('no-dev'))
installer.dry_run(self.option('dry-run'))
installer.dev_mode(not self.option("no-dev"))
installer.dry_run(self.option("dry-run"))
# Force update
installer.update(True)
......
......@@ -2,7 +2,6 @@ from .command import Command
class VenvCommand(Command):
def __init__(self):
self._venv = None
......@@ -14,14 +13,11 @@ class VenvCommand(Command):
super(VenvCommand, self).initialize(i, o)
self._venv = Venv.create(
o, self.poetry.package.name,
cwd=self.poetry.file.parent
o, self.poetry.package.name, cwd=self.poetry.file.parent
)
if self._venv.is_venv() and o.is_verbose():
o.writeln(
'Using virtualenv: <comment>{}</>'.format(self._venv.venv)
)
o.writeln("Using virtualenv: <comment>{}</>".format(self._venv.venv))
@property
def venv(self):
......
......@@ -20,27 +20,29 @@ patch, minor, major, prepatch, preminor, premajor, prerelease.
"""
RESERVED = {
'major', 'minor', 'patch',
'premajor', 'preminor', 'prepatch',
'prerelease'
"major",
"minor",
"patch",
"premajor",
"preminor",
"prepatch",
"prerelease",
}
def handle(self):
version = self.argument('version')
version = self.argument("version")
version = self.increment_version(
self.poetry.package.pretty_version, version
)
version = self.increment_version(self.poetry.package.pretty_version, version)
self.line(
'Bumping version from <comment>{}</> to <info>{}</>'.format(
"Bumping version from <comment>{}</> to <info>{}</>".format(
self.poetry.package.pretty_version, version
)
)
content = self.poetry.file.read()
poetry_content = content['tool']['poetry']
poetry_content['version'] = version.text
poetry_content = content["tool"]["poetry"]
poetry_content["version"] = version.text
self.poetry.file.write(content)
......@@ -50,32 +52,30 @@ patch, minor, major, prepatch, preminor, premajor, prerelease.
try:
version = Version.parse(version)
except ValueError:
raise ValueError(
'The project\'s version doesn\'t seem to follow semver'
)
raise ValueError("The project's version doesn't seem to follow semver")
if rule in {'major', 'premajor'}:
if rule in {"major", "premajor"}:
new = version.next_major
if rule == 'premajor':
if rule == "premajor":
new = new.first_prerelease
elif rule in {'minor', 'preminor'}:
elif rule in {"minor", "preminor"}:
new = version.next_minor
if rule == 'preminor':
if rule == "preminor":
new = new.first_prerelease
elif rule in {'patch', 'prepatch'}:
elif rule in {"patch", "prepatch"}:
new = version.next_patch
if rule == 'prepatch':
if rule == "prepatch":
new = new.first_prerelease
elif rule == 'prerelease':
elif rule == "prerelease":
if version.is_prerelease():
pre = version.prerelease
new_prerelease = int(pre[1]) + 1
new = Version.parse(
'{}.{}.{}-{}'.format(
"{}.{}.{}-{}".format(
version.major,
version.minor,
version.patch,
'.'.join([pre[0], str(new_prerelease)])
".".join([pre[0], str(new_prerelease)]),
)
)
else:
......
......@@ -3,24 +3,29 @@ from cleo.styles import OutputStyle
class PoetryStyle(CleoStyle):
def __init__(self, i, o):
super(PoetryStyle, self).__init__(i, o)
self.output.get_formatter().add_style('error', 'red')
self.output.get_formatter().add_style('warning', 'yellow')
self.output.get_formatter().add_style('question', 'cyan')
self.output.get_formatter().add_style('comment', 'blue')
self.output.get_formatter().add_style("error", "red")
self.output.get_formatter().add_style("warning", "yellow")
self.output.get_formatter().add_style("question", "cyan")
self.output.get_formatter().add_style("comment", "blue")
def writeln(self, messages,
type=OutputStyle.OUTPUT_NORMAL,
verbosity=OutputStyle.VERBOSITY_NORMAL):
def writeln(
self,
messages,
type=OutputStyle.OUTPUT_NORMAL,
verbosity=OutputStyle.VERBOSITY_NORMAL,
):
if self.output.verbosity >= verbosity:
super(PoetryStyle, self).writeln(messages, type=type)
def write(self, messages,
newline=False,
type=OutputStyle.OUTPUT_NORMAL,
verbosity=OutputStyle.VERBOSITY_NORMAL):
def write(
self,
messages,
newline=False,
type=OutputStyle.OUTPUT_NORMAL,
verbosity=OutputStyle.VERBOSITY_NORMAL,
):
if self.output.verbosity >= verbosity:
super(PoetryStyle, self).write(messages, newline=newline, type=type)
class BaseInstaller:
def install(self, package):
raise NotImplementedError
......
......@@ -2,7 +2,6 @@ from .base_installer import BaseInstaller
class NoopInstaller(BaseInstaller):
def __init__(self):
self._installs = []
self._updates = []
......
......@@ -10,19 +10,18 @@ from .base_installer import BaseInstaller
class PipInstaller(BaseInstaller):
def __init__(self, venv, io): # type: (Venv, ...) -> None
self._venv = venv
self._io = io
def install(self, package, update=False):
args = ['install', '--no-deps']
args = ["install", "--no-deps"]
if package.source_type == 'legacy' and package.source_url:
args += ['--index-url', package.source_url]
if package.source_type == "legacy" and package.source_url:
args += ["--index-url", package.source_url]
if update:
args.append('-U')
args.append("-U")
if package.hashes and not package.source_type:
# Format as a requirements.txt
......@@ -32,7 +31,7 @@ class PipInstaller(BaseInstaller):
# other choice since this is the only way for pip
# to verify hashes.
req = self.create_temporary_requirement(package)
args += ['-r', req]
args += ["-r", req]
try:
self.run(*args)
......@@ -52,49 +51,47 @@ class PipInstaller(BaseInstaller):
def remove(self, package):
try:
self.run('uninstall', package.name, '-y')
self.run("uninstall", package.name, "-y")
except CalledProcessError as e:
if 'not installed' in str(e):
if "not installed" in str(e):
return
raise
def run(self, *args, **kwargs): # type: (...) -> str
return self._venv.run('pip', *args, **kwargs)
return self._venv.run("pip", *args, **kwargs)
def requirement(self, package, formatted=False):
if formatted and not package.source_type:
req = '{}=={}'.format(package.name, package.version)
req = "{}=={}".format(package.name, package.version)
for h in package.hashes:
req += ' --hash sha256:{}'.format(h)
req += " --hash sha256:{}".format(h)
req += '\n'
req += "\n"
return req
if package.source_type in ['file', 'directory']:
if package.source_type in ["file", "directory"]:
if package.root_dir:
req = os.path.join(package.root_dir, package.source_url)
else:
req = os.path.realpath(package.source_url)
if package.develop:
req = ['-e', req]
req = ["-e", req]
return req
if package.source_type == 'git':
return 'git+{}@{}#egg={}'.format(
package.source_url,
package.source_reference,
package.name
if package.source_type == "git":
return "git+{}@{}#egg={}".format(
package.source_url, package.source_reference, package.name
)
return '{}=={}'.format(package.name, package.version)
return "{}=={}".format(package.name, package.version)
def create_temporary_requirement(self, package):
fd, name = tempfile.mkstemp(
'reqs.txt', '{}-{}'.format(package.name, package.version)
"reqs.txt", "{}-{}".format(package.name, package.version)
)
try:
......
......@@ -5,7 +5,6 @@ from poetry.console.styles.poetry import PoetryStyle
class NullIO(PoetryStyle):
def __init__(self):
super(NullIO, self).__init__(ListInput([]), NullOutput())
......
......@@ -4,7 +4,6 @@ from cleo.inputs import ArgvInput
class RawArgvInput(ArgvInput):
def parse(self):
self._parsed = self._tokens
while True:
......
......@@ -5,14 +5,11 @@ from .src import SrcLayout
from .standard import StandardLayout
_LAYOUTS = {
'src': SrcLayout,
'standard': StandardLayout,
}
_LAYOUTS = {"src": SrcLayout, "standard": StandardLayout}
def layout(name): # type: (str) -> Type[Layout]
if name not in _LAYOUTS:
raise ValueError('Invalid layout')
raise ValueError("Invalid layout")
return _LAYOUTS[name]
......@@ -38,17 +38,18 @@ license = ""
class Layout(object):
def __init__(self,
project,
version='0.1.0',
description='',
readme_format='md',
author=None,
license=None,
python='*',
dependencies=None,
dev_dependencies=None):
def __init__(
self,
project,
version="0.1.0",
description="",
readme_format="md",
author=None,
license=None,
python="*",
dependencies=None,
dev_dependencies=None,
):
self._project = project
self._package_name = module_name(project)
self._version = version
......@@ -57,10 +58,10 @@ class Layout(object):
self._license = license
self._python = python
self._dependencies = dependencies or {}
self._dev_dependencies = dev_dependencies or {'pytest': '^3.5'}
self._dev_dependencies = dev_dependencies or {"pytest": "^3.5"}
if not author:
author = 'Your Name <you@example.com>'
author = "Your Name <you@example.com>"
self._author = author
......@@ -81,21 +82,21 @@ class Layout(object):
template = POETRY_WITH_LICENSE
content = loads(template)
poetry_content = content['tool']['poetry']
poetry_content['name'] = self._project
poetry_content['version'] = self._version
poetry_content['description'] = self._description
poetry_content['authors'].append(self._author)
poetry_content = content["tool"]["poetry"]
poetry_content["name"] = self._project
poetry_content["version"] = self._version
poetry_content["description"] = self._description
poetry_content["authors"].append(self._author)
if self._license:
poetry_content['license'] = self._license
poetry_content["license"] = self._license
poetry_content['dependencies']['python'] = self._python
poetry_content["dependencies"]["python"] = self._python
for dep_name, dep_constraint in self._dependencies.items():
poetry_content['dependencies'][dep_name] = dep_constraint
poetry_content["dependencies"][dep_name] = dep_constraint
for dep_name, dep_constraint in self._dev_dependencies.items():
poetry_content['dev-dependencies'][dep_name] = dep_constraint
poetry_content["dev-dependencies"][dep_name] = dep_constraint
return dumps(content)
......@@ -103,35 +104,34 @@ class Layout(object):
raise NotImplementedError()
def _create_readme(self, path):
if self._readme_format == 'rst':
readme_file = path / 'README.rst'
if self._readme_format == "rst":
readme_file = path / "README.rst"
else:
readme_file = path / 'README.md'
readme_file = path / "README.md"
readme_file.touch()
def _create_tests(self, path):
self._dev_dependencies['pytest'] = '^3.0'
self._dev_dependencies["pytest"] = "^3.0"
tests = path / 'tests'
tests_init = tests / '__init__.py'
tests_default = tests / 'test_{}.py'.format(self._package_name)
tests = path / "tests"
tests_init = tests / "__init__.py"
tests_default = tests / "test_{}.py".format(self._package_name)
tests.mkdir()
tests_init.touch(exist_ok=False)
with tests_default.open('w') as f:
with tests_default.open("w") as f:
f.write(
TESTS_DEFAULT.format(
package_name=self._package_name,
version=self._version
package_name=self._package_name, version=self._version
)
)
def _write_poetry(self, path):
content = self.generate_poetry_content()
poetry = path / 'pyproject.toml'
poetry = path / "pyproject.toml"
with poetry.open('w') as f:
with poetry.open("w") as f:
f.write(content)
......@@ -7,13 +7,12 @@ DEFAULT = u"""__version__ = '{version}'
class SrcLayout(Layout):
def _create_default(self, path):
package_path = path / 'src' / self._package_name
package_path = path / "src" / self._package_name
package_init = package_path / '__init__.py'
package_init = package_path / "__init__.py"
package_path.mkdir(parents=True)
with package_init.open('w') as f:
with package_init.open("w") as f:
f.write(DEFAULT.format(version=self._version))
......@@ -7,13 +7,12 @@ DEFAULT = u"""__version__ = '{version}'
class StandardLayout(Layout):
def _create_default(self, path):
package_path = path / self._package_name
package_init = package_path / '__init__.py'
package_init = package_path / "__init__.py"
package_path.mkdir()
with package_init.open('w') as f:
with package_init.open("w") as f:
f.write(DEFAULT.format(version=self._version))
......@@ -2,5 +2,5 @@ from .utils.appdirs import user_cache_dir
from .utils.appdirs import user_config_dir
CACHE_DIR = user_cache_dir('pypoetry')
CONFIG_DIR = user_config_dir('pypoetry')
CACHE_DIR = user_cache_dir("pypoetry")
CONFIG_DIR = user_config_dir("pypoetry")
......@@ -14,7 +14,7 @@ from .builders import WheelBuilder
log = logging.getLogger(__name__)
# PEP 517 specifies that the CWD will always be the source tree
poetry = Poetry.create('.')
poetry = Poetry.create(".")
def get_requires_for_build_wheel(config_settings=None):
......
......@@ -5,11 +5,7 @@ from .builders import WheelBuilder
class Builder:
_FORMATS = {
'sdist': SdistBuilder,
'wheel': WheelBuilder,
'all': CompleteBuilder
}
_FORMATS = {"sdist": SdistBuilder, "wheel": WheelBuilder, "all": CompleteBuilder}
def __init__(self, poetry, venv, io):
self._poetry = poetry
......@@ -18,7 +14,7 @@ class Builder:
def build(self, fmt):
if fmt not in self._FORMATS:
raise ValueError('Invalid format: {}'.format(fmt))
raise ValueError("Invalid format: {}".format(fmt))
builder = self._FORMATS[fmt](self._poetry, self._venv, self._io)
......
......@@ -14,17 +14,12 @@ from ..metadata import Metadata
from ..utils.module import Module
AUTHOR_REGEX = re.compile('(?u)^(?P<name>[- .,\w\d\'’"()]+) <(?P<email>.+?)>$')
AUTHOR_REGEX = re.compile("(?u)^(?P<name>[- .,\w\d'’\"()]+) <(?P<email>.+?)>$")
class Builder(object):
AVAILABLE_PYTHONS = {
'2',
'2.7',
'3',
'3.4', '3.5', '3.6', '3.7'
}
AVAILABLE_PYTHONS = {"2", "2.7", "3", "3.4", "3.5", "3.6", "3.7"}
def __init__(self, poetry, venv, io):
self._poetry = poetry
......@@ -32,9 +27,7 @@ class Builder(object):
self._io = io
self._package = poetry.package
self._path = poetry.file.parent
self._module = Module(
self._package.name, self._path.as_posix()
)
self._module = Module(self._package.name, self._path.as_posix())
self._meta = Metadata.from_package(self._package)
def build(self):
......@@ -77,7 +70,7 @@ class Builder(object):
else:
for root, dirs, files in os.walk(src.as_posix()):
root = Path(root)
if root.name == '__pycache__':
if root.name == "__pycache__":
continue
for file in files:
......@@ -87,42 +80,42 @@ class Builder(object):
if file in excluded:
continue
if file.suffix == '.pyc':
if file.suffix == ".pyc":
continue
self._io.writeln(
' - Adding: <comment>{}</comment>'.format(str(file)),
verbosity=self._io.VERBOSITY_VERY_VERBOSE
" - Adding: <comment>{}</comment>".format(str(file)),
verbosity=self._io.VERBOSITY_VERY_VERBOSE,
)
to_add.append(file)
# Include project files
self._io.writeln(
' - Adding: <comment>pyproject.toml</comment>',
verbosity=self._io.VERBOSITY_VERY_VERBOSE
" - Adding: <comment>pyproject.toml</comment>",
verbosity=self._io.VERBOSITY_VERY_VERBOSE,
)
to_add.append(Path('pyproject.toml'))
to_add.append(Path("pyproject.toml"))
# If a license file exists, add it
for license_file in self._path.glob('LICENSE*'):
for license_file in self._path.glob("LICENSE*"):
self._io.writeln(
' - Adding: <comment>{}</comment>'.format(
" - Adding: <comment>{}</comment>".format(
license_file.relative_to(self._path)
),
verbosity=self._io.VERBOSITY_VERY_VERBOSE
verbosity=self._io.VERBOSITY_VERY_VERBOSE,
)
to_add.append(license_file.relative_to(self._path))
# If a README is specificed we need to include it
# to avoid errors
if 'readme' in self._poetry.local_config:
readme = self._path / self._poetry.local_config['readme']
if "readme" in self._poetry.local_config:
readme = self._path / self._poetry.local_config["readme"]
if readme.exists():
self._io.writeln(
' - Adding: <comment>{}</comment>'.format(
" - Adding: <comment>{}</comment>".format(
readme.relative_to(self._path)
),
verbosity=self._io.VERBOSITY_VERY_VERBOSE
verbosity=self._io.VERBOSITY_VERY_VERBOSE,
)
to_add.append(readme.relative_to(self._path))
......@@ -137,14 +130,14 @@ class Builder(object):
result = defaultdict(list)
# Scripts -> Entry points
for name, ep in self._poetry.local_config.get('scripts', {}).items():
result['console_scripts'].append('{} = {}'.format(name, ep))
for name, ep in self._poetry.local_config.get("scripts", {}).items():
result["console_scripts"].append("{} = {}".format(name, ep))
# Plugins -> entry points
plugins = self._poetry.local_config.get('plugins', {})
plugins = self._poetry.local_config.get("plugins", {})
for groupname, group in plugins.items():
for name, ep in sorted(group.items()):
result[groupname].append('{} = {}'.format(name, ep))
result[groupname].append("{} = {}".format(name, ep))
for groupname in result:
result[groupname] = sorted(result[groupname])
......@@ -155,13 +148,10 @@ class Builder(object):
def convert_author(cls, author): # type: () -> dict
m = AUTHOR_REGEX.match(author)
name = m.group('name')
email = m.group('email')
name = m.group("name")
email = m.group("email")
return {
'name': name,
'email': email
}
return {"name": name, "email": email}
@classmethod
@contextmanager
......
......@@ -11,20 +11,22 @@ from .wheel import WheelBuilder
class CompleteBuilder(Builder):
def build(self):
# We start by building the tarball
# We will use it to build the wheel
sdist_builder = SdistBuilder(self._poetry, self._venv, self._io)
sdist_file = sdist_builder.build()
self._io.writeln('')
self._io.writeln("")
dist_dir = self._path / 'dist'
dist_dir = self._path / "dist"
with self.unpacked_tarball(sdist_file) as tmpdir:
WheelBuilder.make_in(
poetry.poetry.Poetry.create(tmpdir), self._venv, self._io, dist_dir,
original=self._poetry
poetry.poetry.Poetry.create(tmpdir),
self._venv,
self._io,
dist_dir,
original=self._poetry,
)
@classmethod
......
......@@ -5,7 +5,7 @@ from poetry.version.helpers import format_python_constraint
class Metadata:
metadata_version = '2.1'
metadata_version = "2.1"
# version 1.0
name = None
version = None
......@@ -49,7 +49,7 @@ class Metadata:
with package.readme.open() as f:
meta.description = f.read()
meta.keywords = ','.join(package.keywords)
meta.keywords = ",".join(package.keywords)
meta.home_page = package.homepage or package.repository_url
meta.author = package.author_name
meta.author_email = package.author_email
......@@ -71,12 +71,12 @@ class Metadata:
# Version 2.1
if package.readme:
if package.readme.suffix == '.rst':
meta.description_content_type = 'text/x-rst'
elif package.readme.suffix in ['.md', '.markdown']:
meta.description_content_type = 'text/markdown'
if package.readme.suffix == ".rst":
meta.description_content_type = "text/x-rst"
elif package.readme.suffix in [".md", ".markdown"]:
meta.description_content_type = "text/markdown"
else:
meta.description_content_type = 'text/plain'
meta.description_content_type = "text/plain"
meta.provides_extra = [e for e in package.extras]
......
......@@ -24,66 +24,68 @@ class Publisher:
def publish(self, repository_name, username, password):
if repository_name:
self._io.writeln(
'Publishing <info>{}</info> (<comment>{}</comment>) '
'to <fg=cyan>{}</>'.format(
"Publishing <info>{}</info> (<comment>{}</comment>) "
"to <fg=cyan>{}</>".format(
self._package.pretty_name,
self._package.pretty_version,
repository_name
repository_name,
)
)
else:
self._io.writeln(
'Publishing <info>{}</info> (<comment>{}</comment>) '
'to <fg=cyan>PyPI</>'.format(
self._package.pretty_name,
self._package.pretty_version
"Publishing <info>{}</info> (<comment>{}</comment>) "
"to <fg=cyan>PyPI</>".format(
self._package.pretty_name, self._package.pretty_version
)
)
if not repository_name:
url = 'https://upload.pypi.org/legacy/'
repository_name = 'pypi'
url = "https://upload.pypi.org/legacy/"
repository_name = "pypi"
else:
# Retrieving config information
config_file = Path(CONFIG_DIR) / 'config.toml'
config_file = Path(CONFIG_DIR) / "config.toml"
if not config_file.exists():
raise RuntimeError(
'Config file does not exist. '
'Unable to get repository information'
"Config file does not exist. "
"Unable to get repository information"
)
with config_file.open() as f:
config = toml.loads(f.read())
if (
'repositories' not in config
or repository_name not in config['repositories']
"repositories" not in config
or repository_name not in config["repositories"]
):
raise RuntimeError(
'Repository {} is not defined'.format(repository_name)
"Repository {} is not defined".format(repository_name)
)
url = config['repositories'][repository_name]['url']
url = config["repositories"][repository_name]["url"]
if not (username and password):
auth_file = Path(CONFIG_DIR) / 'auth.toml'
auth_file = Path(CONFIG_DIR) / "auth.toml"
if auth_file.exists():
with auth_file.open() as f:
auth_config = toml.loads(f.read())
if 'http-basic' in auth_config and repository_name in auth_config['http-basic']:
config = auth_config['http-basic'][repository_name]
if (
"http-basic" in auth_config
and repository_name in auth_config["http-basic"]
):
config = auth_config["http-basic"][repository_name]
username = config.get('username')
password = config.get('password')
username = config.get("username")
password = config.get("password")
# Requesting missing credentials
if not username:
username = self._io.ask('Username:')
username = self._io.ask("Username:")
if not password:
password = self._io.ask_hidden('Password:')
password = self._io.ask_hidden("Password:")
# TODO: handle certificates
......
......@@ -10,9 +10,7 @@ from requests import adapters
from requests.exceptions import HTTPError
from requests.packages.urllib3 import util
from requests_toolbelt import user_agent
from requests_toolbelt.multipart import (
MultipartEncoder, MultipartEncoderMonitor
)
from requests_toolbelt.multipart import MultipartEncoder, MultipartEncoderMonitor
from poetry.__version__ import __version__
from poetry.utils.helpers import normalize_version
......@@ -24,14 +22,13 @@ wheel_file_re = re.compile(
r"""^(?P<namever>(?P<name>.+?)(-(?P<ver>\d.+?))?)
((-(?P<build>\d.*?))?-(?P<pyver>.+?)-(?P<abi>.+?)-(?P<plat>.+?)
\.whl|\.dist-info)$""",
re.VERBOSE
re.VERBOSE,
)
_has_blake2 = hasattr(hashlib, 'blake2b')
_has_blake2 = hasattr(hashlib, "blake2b")
class Uploader:
def __init__(self, poetry, io):
self._poetry = poetry
self._package = poetry.package
......@@ -41,14 +38,14 @@ class Uploader:
@property
def user_agent(self):
return user_agent('poetry', __version__)
return user_agent("poetry", __version__)
@property
def adapter(self):
retry = util.Retry(
connect=5,
total=10,
method_whitelist=['GET'],
method_whitelist=["GET"],
status_forcelist=[500, 501, 502, 503],
)
......@@ -56,18 +53,22 @@ class Uploader:
@property
def files(self): # type: () -> List[str]
dist = self._poetry.file.parent / 'dist'
dist = self._poetry.file.parent / "dist"
version = normalize_version(self._package.version.text)
wheels = list(dist.glob(
'{}-{}-*.whl'.format(
re.sub("[^\w\d.]+", "_", self._package.pretty_name, flags=re.UNICODE),
re.sub("[^\w\d.]+", "_", version, flags=re.UNICODE),
wheels = list(
dist.glob(
"{}-{}-*.whl".format(
re.sub(
"[^\w\d.]+", "_", self._package.pretty_name, flags=re.UNICODE
),
re.sub("[^\w\d.]+", "_", version, flags=re.UNICODE),
)
)
))
tars = list(dist.glob(
'{}-{}.tar.gz'.format(self._package.pretty_name, version)
))
)
tars = list(
dist.glob("{}-{}.tar.gz".format(self._package.pretty_name, version))
)
return sorted(wheels + tars)
......@@ -80,8 +81,8 @@ class Uploader:
if self.is_authenticated():
session.auth = (self._username, self._password)
session.headers['User-Agent'] = self.user_agent
for scheme in ('http://', 'https://'):
session.headers["User-Agent"] = self.user_agent
for scheme in ("http://", "https://"):
session.mount(scheme, self.adapter)
return session
......@@ -107,8 +108,8 @@ class Uploader:
md5_hash = hashlib.md5()
sha256_hash = hashlib.sha256()
with file.open('rb') as fp:
for content in iter(lambda: fp.read(io.DEFAULT_BUFFER_SIZE), b''):
with file.open("rb") as fp:
for content in iter(lambda: fp.read(io.DEFAULT_BUFFER_SIZE), b""):
md5_hash.update(content)
sha256_hash.update(content)
......@@ -122,7 +123,7 @@ class Uploader:
else:
blake2_256_digest = None
if file_type == 'bdist_wheel':
if file_type == "bdist_wheel":
wheel_info = wheel_file_re.match(file.name)
py_version = wheel_info.group("pyver")
else:
......@@ -132,11 +133,9 @@ class Uploader:
# identify release
"name": meta.name,
"version": meta.version,
# file content
"filetype": file_type,
"pyversion": py_version,
# additional meta-data
"metadata_version": meta.metadata_version,
"summary": meta.summary,
......@@ -156,12 +155,10 @@ class Uploader:
"md5_digest": md5_digest,
"sha256_digest": sha2_digest,
"blake2_256_digest": blake2_256_digest,
# PEP 314
"provides": meta.provides,
"requires": meta.requires,
"obsoletes": meta.obsoletes,
# Metadata 1.2
"project_urls": meta.project_urls,
"provides_dist": meta.provides_dist,
......@@ -173,7 +170,7 @@ class Uploader:
# Metadata 2.1
if meta.description_content_type:
data['description_content_type'] = meta.description_content_type
data["description_content_type"] = meta.description_content_type
# TODO: Provides extra
......@@ -185,7 +182,8 @@ class Uploader:
except HTTPError as e:
if (
e.response.status_code not in (403, 400)
or e.response.status_code == 400 and 'was ever registered' not in e.response.text
or e.response.status_code == 400
and "was ever registered" not in e.response.text
):
raise
......@@ -206,25 +204,24 @@ class Uploader:
def _upload_file(self, session, url, file):
data = self.post_data(file)
data.update({
# action
":action": "file_upload",
"protocol_version": "1",
})
data.update(
{
# action
":action": "file_upload",
"protocol_version": "1",
}
)
data_to_send = self._prepare_data(data)
with file.open('rb') as fp:
data_to_send.append((
"content",
(file.name, fp, "application/octet-stream"),
))
with file.open("rb") as fp:
data_to_send.append(
("content", (file.name, fp, "application/octet-stream"))
)
encoder = MultipartEncoder(data_to_send)
bar = self._io.create_progress_bar(encoder.len)
bar.set_format(
" - Uploading <info>{0}</> <comment>%percent%%</>".format(
file.name
)
" - Uploading <info>{0}</> <comment>%percent%%</>".format(file.name)
)
monitor = MultipartEncoderMonitor(
encoder, lambda monitor: bar.set_progress(monitor.bytes_read)
......@@ -236,15 +233,15 @@ class Uploader:
url,
data=monitor,
allow_redirects=False,
headers={'Content-Type': monitor.content_type}
headers={"Content-Type": monitor.content_type},
)
if resp.ok:
bar.finish()
self._io.writeln('')
self._io.writeln("")
else:
self._io.overwrite('')
self._io.overwrite("")
return resp
......@@ -252,21 +249,14 @@ class Uploader:
"""
Register a package to a repository.
"""
dist = self._poetry.file.parent / 'dist'
file = dist / '{}-{}.tar.gz'.format(
self._package.name, self._package.version
)
dist = self._poetry.file.parent / "dist"
file = dist / "{}-{}.tar.gz".format(self._package.name, self._package.version)
if not file.exists():
raise RuntimeError(
'"{0}" does not exist.'.format(file.name)
)
raise RuntimeError('"{0}" does not exist.'.format(file.name))
data = self.post_data(file)
data.update({
":action": "submit",
"protocol_version": "1",
})
data.update({":action": "submit", "protocol_version": "1"})
data_to_send = self._prepare_data(data)
encoder = MultipartEncoder(data_to_send)
......@@ -274,7 +264,7 @@ class Uploader:
url,
data=encoder,
allow_redirects=False,
headers={'Content-Type': encoder.content_type},
headers={"Content-Type": encoder.content_type},
)
return resp
......@@ -292,11 +282,9 @@ class Uploader:
def _get_type(self, file):
exts = file.suffixes
if exts[-1] == '.whl':
return 'bdist_wheel'
elif len(exts) >= 2 and ''.join(exts[-2:]) == '.tar.gz':
return 'sdist'
if exts[-1] == ".whl":
return "bdist_wheel"
elif len(exts) >= 2 and "".join(exts[-2:]) == ".tar.gz":
return "sdist"
raise ValueError(
'Unknown distribution format {}'.format(''.join(exts))
)
raise ValueError("Unknown distribution format {}".format("".join(exts)))
......@@ -3,14 +3,13 @@ from poetry.utils.helpers import module_name
class Module:
def __init__(self, name, directory='.'):
def __init__(self, name, directory="."):
self._name = module_name(name)
self._in_src = False
# It must exist either as a .py file or a directory, but not both
pkg_dir = Path(directory, self._name)
py_file = Path(directory, self._name + '.py')
py_file = Path(directory, self._name + ".py")
if pkg_dir.is_dir() and py_file.is_file():
raise ValueError("Both {} and {} exist".format(pkg_dir, py_file))
elif pkg_dir.is_dir():
......@@ -21,12 +20,11 @@ class Module:
self._is_package = False
else:
# Searching for a src module
src_pkg_dir = Path(directory, 'src', self._name)
src_py_file = Path(directory, 'src', self._name + '.py')
src_pkg_dir = Path(directory, "src", self._name)
src_py_file = Path(directory, "src", self._name + ".py")
if src_pkg_dir.is_dir() and src_py_file.is_file():
raise ValueError(
"Both {} and {} exist".format(pkg_dir, py_file))
raise ValueError("Both {} and {} exist".format(pkg_dir, py_file))
elif src_pkg_dir.is_dir():
self._in_src = True
self._path = src_pkg_dir
......@@ -49,7 +47,7 @@ class Module:
@property
def file(self): # type: () -> Path
if self._is_package:
return self._path / '__init__.py'
return self._path / "__init__.py"
else:
return self._path
......
......@@ -16,23 +16,23 @@ def get_abbr_impl(venv):
"""Return abbreviated implementation name."""
impl = venv.python_implementation
if impl == 'PyPy':
return 'pp'
elif impl == 'Jython':
return 'jy'
elif impl == 'IronPython':
return 'ip'
elif impl == 'CPython':
return 'cp'
if impl == "PyPy":
return "pp"
elif impl == "Jython":
return "jy"
elif impl == "IronPython":
return "ip"
elif impl == "CPython":
return "cp"
raise LookupError('Unknown Python implementation: ' + impl)
raise LookupError("Unknown Python implementation: " + impl)
def get_impl_ver(venv):
"""Return implementation version."""
impl_ver = venv.config_var("py_version_nodot")
if not impl_ver or get_abbr_impl(venv) == 'pp':
impl_ver = ''.join(map(str, get_impl_version_info(venv)))
if not impl_ver or get_abbr_impl(venv) == "pp":
impl_ver = "".join(map(str, get_impl_version_info(venv)))
return impl_ver
......@@ -40,7 +40,7 @@ def get_impl_ver(venv):
def get_impl_version_info(venv):
"""Return sys.version_info-like tuple for use in decrementing the minor
version."""
if get_abbr_impl(venv) == 'pp':
if get_abbr_impl(venv) == "pp":
# as per https://github.com/pypa/pip/issues/2882
return venv.version_info[:3]
else:
......@@ -53,8 +53,12 @@ def get_flag(venv, var, fallback, expected=True, warn=True):
val = venv.config_var(var)
if val is None:
if warn:
warnings.warn("Config variable '{0}' is unset, Python ABI tag may "
"be incorrect".format(var), RuntimeWarning, 2)
warnings.warn(
"Config variable '{0}' is unset, Python ABI tag may "
"be incorrect".format(var),
RuntimeWarning,
2,
)
return fallback()
return val == expected
......@@ -62,35 +66,34 @@ def get_flag(venv, var, fallback, expected=True, warn=True):
def get_abi_tag(venv):
"""Return the ABI tag based on SOABI (if available) or emulate SOABI
(CPython 2, PyPy)."""
soabi = venv.config_var('SOABI')
soabi = venv.config_var("SOABI")
impl = get_abbr_impl(venv)
if not soabi and impl in ('cp', 'pp') and hasattr(sys, 'maxunicode'):
d = ''
m = ''
u = ''
if get_flag(venv,
'Py_DEBUG',
lambda: hasattr(sys, 'gettotalrefcount'),
warn=(impl == 'cp')):
d = 'd'
if get_flag(venv,
'WITH_PYMALLOC',
lambda: impl == 'cp',
warn=(impl == 'cp')):
m = 'm'
if get_flag(venv,
'Py_UNICODE_SIZE',
lambda: sys.maxunicode == 0x10ffff,
expected=4,
warn=(impl == 'cp' and
venv.version_info < (3, 3))) \
and venv.version_info < (3, 3):
u = 'u'
abi = '%s%s%s%s%s' % (impl, get_impl_ver(venv), d, m, u)
elif soabi and soabi.startswith('cpython-'):
abi = 'cp' + soabi.split('-')[1]
if not soabi and impl in ("cp", "pp") and hasattr(sys, "maxunicode"):
d = ""
m = ""
u = ""
if get_flag(
venv,
"Py_DEBUG",
lambda: hasattr(sys, "gettotalrefcount"),
warn=(impl == "cp"),
):
d = "d"
if get_flag(venv, "WITH_PYMALLOC", lambda: impl == "cp", warn=(impl == "cp")):
m = "m"
if get_flag(
venv,
"Py_UNICODE_SIZE",
lambda: sys.maxunicode == 0x10ffff,
expected=4,
warn=(impl == "cp" and venv.version_info < (3, 3)),
) and venv.version_info < (3, 3):
u = "u"
abi = "%s%s%s%s%s" % (impl, get_impl_ver(venv), d, m, u)
elif soabi and soabi.startswith("cpython-"):
abi = "cp" + soabi.split("-")[1]
elif soabi:
abi = soabi.replace('.', '_').replace('-', '_')
abi = soabi.replace(".", "_").replace("-", "_")
else:
abi = None
return abi
......@@ -99,7 +102,7 @@ def get_abi_tag(venv):
def get_platform():
"""Return our platform name 'win32', 'linux_x86_64'"""
# XXX remove distutils dependency
result = distutils.util.get_platform().replace('.', '_').replace('-', '_')
result = distutils.util.get_platform().replace(".", "_").replace("-", "_")
if result == "linux_x86_64" and sys.maxsize == 2147483647:
# pip pull request #3497
result = "linux_i686"
......@@ -121,7 +124,7 @@ def get_supported(venv, versions=None, supplied_platform=None):
major = version_info[:-1]
# Support all previous minor Python versions.
for minor in range(version_info[-1], -1, -1):
versions.append(''.join(map(str, major + (minor,))))
versions.append("".join(map(str, major + (minor,))))
impl = get_abbr_impl(venv)
......@@ -133,13 +136,14 @@ def get_supported(venv, versions=None, supplied_platform=None):
abi3s = set()
import imp
for suffix in imp.get_suffixes():
if suffix[0].startswith('.abi'):
abi3s.add(suffix[0].split('.', 2)[1])
if suffix[0].startswith(".abi"):
abi3s.add(suffix[0].split(".", 2)[1])
abis.extend(sorted(list(abi3s)))
abis.append('none')
abis.append("none")
platforms = []
if supplied_platform:
......@@ -149,32 +153,32 @@ def get_supported(venv, versions=None, supplied_platform=None):
# Current version, current API (built specifically for our Python):
for abi in abis:
for arch in platforms:
supported.append(('%s%s' % (impl, versions[0]), abi, arch))
supported.append(("%s%s" % (impl, versions[0]), abi, arch))
# abi3 modules compatible with older version of Python
for version in versions[1:]:
# abi3 was introduced in Python 3.2
if version in ('31', '30'):
if version in ("31", "30"):
break
for abi in abi3s: # empty set if not Python 3
for abi in abi3s: # empty set if not Python 3
for arch in platforms:
supported.append(("%s%s" % (impl, version), abi, arch))
# No abi / arch, but requires our implementation:
for i, version in enumerate(versions):
supported.append(('%s%s' % (impl, version), 'none', 'any'))
supported.append(("%s%s" % (impl, version), "none", "any"))
if i == 0:
# Tagged specifically as being cross-version compatible
# (with just the major version specified)
supported.append(('%s%s' % (impl, versions[0][0]), 'none', 'any'))
supported.append(("%s%s" % (impl, versions[0][0]), "none", "any"))
# Major Python version + platform; e.g. binaries not using the Python API
supported.append(('py%s' % (versions[0][0]), 'none', arch))
supported.append(("py%s" % (versions[0][0]), "none", arch))
# No abi / arch, generic Python
for i, version in enumerate(versions):
supported.append(('py%s' % (version,), 'none', 'any'))
supported.append(("py%s" % (version,), "none", "any"))
if i == 0:
supported.append(('py%s' % (version[0]), 'none', 'any'))
supported.append(("py%s" % (version[0]), "none", "any"))
return supported
......@@ -9,9 +9,7 @@ class Assignment(Term):
A term in a PartialSolution that tracks some additional metadata.
"""
def __init__(self, dependency, is_positive,
decision_level, index,
cause=None):
def __init__(self, dependency, is_positive, decision_level, index, cause=None):
super(Assignment, self).__init__(dependency, is_positive)
self._decision_level = decision_level
......@@ -31,15 +29,16 @@ class Assignment(Term):
return self._cause
@classmethod
def decision(cls, package, decision_level, index
): # type: (Any, int, int) -> Assignment
def decision(
cls, package, decision_level, index
): # type: (Any, int, int) -> Assignment
return cls(package.to_dependency(), True, decision_level, index)
@classmethod
def derivation(cls, dependency, is_positive, cause, decision_level, index
): # type: (Any, bool, Incompatibility, int, int) -> Assignment
def derivation(
cls, dependency, is_positive, cause, decision_level, index
): # type: (Any, bool, Incompatibility, int, int) -> Assignment
return cls(dependency, is_positive, decision_level, index, cause)
def is_decision(self): # type: () -> bool
return self._cause is None
......@@ -85,17 +85,23 @@ class PartialSolution:
self._backtracking = False
self._decisions[package.name] = package
self._assign(Assignment.decision(package, self.decision_level, len(self._assignments)))
self._assign(
Assignment.decision(package, self.decision_level, len(self._assignments))
)
def derive(self, dependency, is_positive, cause
): # type: (Dependency, bool, Incompatibility) -> None
def derive(
self, dependency, is_positive, cause
): # type: (Dependency, bool, Incompatibility) -> None
"""
Adds an assignment of package as a derivation.
"""
self._assign(
Assignment.derivation(
dependency, is_positive, cause,
self.decision_level, len(self._assignments)
dependency,
is_positive,
cause,
self.decision_level,
len(self._assignments),
)
)
......@@ -193,7 +199,7 @@ class PartialSolution:
if assigned_term.satisfies(term):
return assignment
raise RuntimeError('[BUG] {} is not satisfied.'.format(term))
raise RuntimeError("[BUG] {} is not satisfied.".format(term))
def satisfies(self, term): # type: (Term) -> bool
return self.relation(term) == SetRelation.SUBSET
......
class SolverResult:
def __init__(self, root, packages, attempted_solutions):
self._root = root
self._packages = packages
......
......@@ -3,8 +3,8 @@ class SetRelation:
An enum of possible relationships between two sets.
"""
SUBSET = 'subset'
SUBSET = "subset"
DISJOINT = 'disjoint'
DISJOINT = "disjoint"
OVERLAPPING = 'overlapping'
OVERLAPPING = "overlapping"
......@@ -14,10 +14,7 @@ class Term(object):
See https://github.com/dart-lang/pub/tree/master/doc/solver.md#term.
"""
def __init__(self,
dependency, # type: Dependency
is_positive # type: bool
):
def __init__(self, dependency, is_positive): # type: Dependency # type: bool
self._dependency = dependency
self._positive = is_positive
......@@ -51,7 +48,9 @@ class Term(object):
allowed by this term and another.
"""
if self.dependency.name != other.dependency.name:
raise ValueError('{} should refer to {}'.format(other, self.dependency.name))
raise ValueError(
"{} should refer to {}".format(other, self.dependency.name)
)
other_constraint = other.constraint
......@@ -113,7 +112,9 @@ class Term(object):
allowed by both this term and another
"""
if self.dependency.name != other.dependency.name:
raise ValueError('{} should refer to {}'.format(other, self.dependency.name))
raise ValueError(
"{} should refer to {}".format(other, self.dependency.name)
)
if self._compatible_dependency(other.dependency):
if self.is_positive() != other.is_positive():
......@@ -122,20 +123,17 @@ class Term(object):
negative = other if self.is_positive() else self
return self._non_empty_term(
positive.constraint.difference(negative.constraint),
True
positive.constraint.difference(negative.constraint), True
)
elif self.is_positive():
# foo ^1.0.0 ∩ foo >=1.5.0 <3.0.0 → foo ^1.5.0
return self._non_empty_term(
self.constraint.intersect(other.constraint),
True
self.constraint.intersect(other.constraint), True
)
else:
# not foo ^1.0.0 ∩ not foo >=1.5.0 <3.0.0 → not foo >=1.0.0 <3.0.0
return self._non_empty_term(
self.constraint.union(other.constraint),
False
self.constraint.union(other.constraint), False
)
elif self.is_positive() != other.is_positive():
return self if self.is_positive() else other
......@@ -153,9 +151,7 @@ class Term(object):
return (
self.dependency.is_root
or other.is_root
or (
other.name == self.dependency.name
)
or (other.name == self.dependency.name)
)
def _non_empty_term(self, constraint, is_positive):
......@@ -165,10 +161,7 @@ class Term(object):
return Term(Dependency(self.dependency.name, constraint), is_positive)
def __str__(self):
return '{}{}'.format(
'not ' if not self.is_positive() else '',
self._dependency
)
return "{}{}".format("not " if not self.is_positive() else "", self._dependency)
def __repr__(self):
return '<Term {}>'.format(str(self))
return "<Term {}>".format(str(self))
......@@ -36,12 +36,13 @@ class VersionSolver:
on how this solver works.
"""
def __init__(self,
root, # type: ProjectPackage
provider, # type: Provider
locked=None, # type: Dict[str, Package]
use_latest=None # type: List[str]
):
def __init__(
self,
root, # type: ProjectPackage
provider, # type: Provider
locked=None, # type: Dict[str, Package]
use_latest=None, # type: List[str]
):
self._root = root
self._provider = provider
self._locked = locked or {}
......@@ -68,10 +69,7 @@ class VersionSolver:
root_dependency.is_root = True
self._add_incompatibility(
Incompatibility(
[Term(root_dependency, False)],
RootCause()
)
Incompatibility([Term(root_dependency, False)], RootCause())
)
try:
......@@ -85,11 +83,9 @@ class VersionSolver:
raise
finally:
self._log(
'Version solving took {:.3f} seconds.\n'
'Tried {} solutions.'
.format(
time.time() - start,
self._solution.attempted_solutions
"Version solving took {:.3f} seconds.\n"
"Tried {} solutions.".format(
time.time() - start, self._solution.attempted_solutions
)
)
......@@ -130,8 +126,9 @@ class VersionSolver:
elif result is not None:
changed.add(result)
def _propagate_incompatibility(self, incompatibility
): # type: (Incompatibility) -> Union[str, _conflict, None]
def _propagate_incompatibility(
self, incompatibility
): # type: (Incompatibility) -> Union[str, _conflict, None]
"""
If incompatibility is almost satisfied by _solution, adds the
negation of the unsatisfied term to _solution.
......@@ -172,22 +169,20 @@ class VersionSolver:
return _conflict
self._log(
'<fg=blue>derived</>: {}{}'.format(
'not ' if unsatisfied.is_positive() else '',
unsatisfied.dependency
"<fg=blue>derived</>: {}{}".format(
"not " if unsatisfied.is_positive() else "", unsatisfied.dependency
)
)
self._solution.derive(
unsatisfied.dependency,
not unsatisfied.is_positive(),
incompatibility
unsatisfied.dependency, not unsatisfied.is_positive(), incompatibility
)
return unsatisfied.dependency.name
def _resolve_conflict(self, incompatibility
): # type: (Incompatibility) -> Incompatibility
def _resolve_conflict(
self, incompatibility
): # type: (Incompatibility) -> Incompatibility
"""
Given an incompatibility that's satisfied by _solution,
The `conflict resolution`_ constructs a new incompatibility that encapsulates the root
......@@ -198,7 +193,7 @@ class VersionSolver:
.. _conflict resolution: https://github.com/dart-lang/pub/tree/master/doc/solver.md#conflict-resolution
"""
self._log('<fg=red;options=bold>conflict</>: {}'.format(incompatibility))
self._log("<fg=red;options=bold>conflict</>: {}".format(incompatibility))
new_incompatibility = False
while not incompatibility.is_failure():
......@@ -232,11 +227,10 @@ class VersionSolver:
if most_recent_satisfier is None:
most_recent_term = term
most_recent_satisfier= satisfier
most_recent_satisfier = satisfier
elif most_recent_satisfier.index < satisfier.index:
previous_satisfier_level = max(
previous_satisfier_level,
most_recent_satisfier.decision_level
previous_satisfier_level, most_recent_satisfier.decision_level
)
most_recent_term = term
most_recent_satisfier = satisfier
......@@ -254,7 +248,7 @@ class VersionSolver:
if difference is not None:
previous_satisfier_level = max(
previous_satisfier_level,
self._solution.satisfier(difference.inverse).decision_level
self._solution.satisfier(difference.inverse).decision_level,
)
# If most_recent_identifier is the only satisfier left at its decision
......@@ -307,13 +301,17 @@ class VersionSolver:
)
new_incompatibility = True
partially = '' if difference is None else ' partially'
bang = '<fg=red>!</>'
self._log('{} {} is{} satisfied by {}'.format(
bang, most_recent_term, partially, most_recent_satisfier)
partially = "" if difference is None else " partially"
bang = "<fg=red>!</>"
self._log(
"{} {} is{} satisfied by {}".format(
bang, most_recent_term, partially, most_recent_satisfier
)
)
self._log(
'{} which is caused by "{}"'.format(bang, most_recent_satisfier.cause)
)
self._log('{} which is caused by "{}"'.format(bang, most_recent_satisfier.cause))
self._log('{} thus: {}'.format(bang, incompatibility))
self._log("{} thus: {}".format(bang, incompatibility))
raise SolveFailure(incompatibility)
......@@ -385,14 +383,21 @@ class VersionSolver:
#
# We'll continue adding its dependencies, then go back to
# unit propagation which will guide us to choose a better version.
conflict = conflict or all([
term.dependency.name == dependency.name or self._solution.satisfies(term)
for term in incompatibility.terms
])
conflict = conflict or all(
[
term.dependency.name == dependency.name
or self._solution.satisfies(term)
for term in incompatibility.terms
]
)
if not conflict:
self._solution.decide(version)
self._log('<fg=blue>selecting</> {} ({})'.format(version.name, version.full_pretty_version))
self._log(
"<fg=blue>selecting</> {} ({})".format(
version.name, version.full_pretty_version
)
)
return dependency.name
......@@ -408,7 +413,7 @@ class VersionSolver:
return SolverResult(
self._root,
[p for p in decisions if not p.is_root()],
self._solution.attempted_solutions
self._solution.attempted_solutions,
)
def _add_incompatibility(self, incompatibility): # type: (Incompatibility) -> None
......
......@@ -22,12 +22,12 @@ from .vcs_dependency import VCSDependency
def dependency_from_pep_508(name):
# Removing comments
parts = name.split('#', 1)
parts = name.split("#", 1)
name = parts[0].strip()
if len(parts) > 1:
rest = parts[1]
if ';' in rest:
name += ';' + rest.split(';', 1)[1]
if ";" in rest:
name += ";" + rest.split(";", 1)[1]
req = Requirement(name)
......@@ -44,8 +44,7 @@ def dependency_from_pep_508(name):
link = Link(name)
else:
p, extras = strip_extras(path)
if (os.path.isdir(p) and
(os.path.sep in name or name.startswith('.'))):
if os.path.isdir(p) and (os.path.sep in name or name.startswith(".")):
if not is_installable_dir(p):
raise ValueError(
......@@ -59,101 +58,96 @@ def dependency_from_pep_508(name):
# it's a local file, dir, or url
if link:
# Handle relative file URLs
if link.scheme == 'file' and re.search(r'\.\./', link.url):
link = Link(
path_to_url(os.path.normpath(os.path.abspath(link.path)))
)
if link.scheme == "file" and re.search(r"\.\./", link.url):
link = Link(path_to_url(os.path.normpath(os.path.abspath(link.path))))
# wheel file
if link.is_wheel:
m = re.match(
'^(?P<namever>(?P<name>.+?)-(?P<ver>\d.*?))',
link.filename
)
m = re.match("^(?P<namever>(?P<name>.+?)-(?P<ver>\d.*?))", link.filename)
if not m:
raise ValueError('Invalid wheel name: {}'.format(link.filename))
raise ValueError("Invalid wheel name: {}".format(link.filename))
name = m.group('name')
version = m.group('ver')
name = m.group("name")
version = m.group("ver")
dep = Dependency(name, version)
else:
name = link.egg_fragment
if link.scheme == 'git':
dep = VCSDependency(name, 'git', link.url_without_fragment)
if link.scheme == "git":
dep = VCSDependency(name, "git", link.url_without_fragment)
else:
dep = Dependency(name, '*')
dep = Dependency(name, "*")
else:
if req.pretty_constraint:
constraint = req.constraint
else:
constraint = '*'
constraint = "*"
dep = Dependency(name, constraint)
if 'extra' in markers:
if "extra" in markers:
# If we have extras, the dependency is optional
dep.deactivate()
for or_ in markers['extra']:
for or_ in markers["extra"]:
for _, extra in or_:
dep.extras.append(extra)
if 'python_version' in markers:
if "python_version" in markers:
ors = []
for or_ in markers['python_version']:
for or_ in markers["python_version"]:
ands = []
for op, version in or_:
# Expand python version
if op == '==':
version = '~' + version
op = ''
elif op == '!=':
version += '.*'
elif op == 'in':
if op == "==":
version = "~" + version
op = ""
elif op == "!=":
version += ".*"
elif op == "in":
versions = []
for v in re.split('[ ,]+', version):
split = v.split('.')
for v in re.split("[ ,]+", version):
split = v.split(".")
if len(split) in [1, 2]:
split.append('*')
op = ''
split.append("*")
op = ""
else:
op = '=='
op = "=="
versions.append(op + '.'.join(split))
versions.append(op + ".".join(split))
if versions:
ands.append(' || '.join(versions))
ands.append(" || ".join(versions))
continue
ands.append('{}{}'.format(op, version))
ands.append("{}{}".format(op, version))
ors.append(' '.join(ands))
ors.append(" ".join(ands))
dep.python_versions = ' || '.join(ors)
dep.python_versions = " || ".join(ors)
if 'sys_platform' in markers:
if "sys_platform" in markers:
ors = []
for or_ in markers['sys_platform']:
for or_ in markers["sys_platform"]:
ands = []
for op, platform in or_:
if op == '==':
op = ''
elif op == 'in':
if op == "==":
op = ""
elif op == "in":
platforms = []
for v in re.split('[ ,]+', platform):
for v in re.split("[ ,]+", platform):
platforms.append(v)
if platforms:
ands.append(' || '.join(platforms))
ands.append(" || ".join(platforms))
continue
ands.append('{}{}'.format(op, platform))
ands.append("{}{}".format(op, platform))
ors.append(' '.join(ands))
ors.append(" ".join(ands))
dep.platform = ' || '.join(ors)
dep.platform = " || ".join(ors)
# Extras
for extra in req.extras:
......
class BaseConstraint(object):
def matches(self, provider):
raise NotImplementedError()
......
......@@ -24,4 +24,4 @@ class EmptyConstraint(BaseConstraint):
return
def __str__(self):
return '*'
return "*"
......@@ -16,24 +16,16 @@ class GenericConstraint(BaseConstraint):
OP_EQ = operator.eq
OP_NE = operator.ne
_trans_op_str = {
'=': OP_EQ,
'==': OP_EQ,
'!=': OP_NE
}
_trans_op_str = {"=": OP_EQ, "==": OP_EQ, "!=": OP_NE}
_trans_op_int = {
OP_EQ: '==',
OP_NE: '!='
}
_trans_op_int = {OP_EQ: "==", OP_NE: "!="}
def __init__(self, operator, version):
if operator not in self._trans_op_str:
raise ValueError(
'Invalid operator "{}" given, '
'expected one of: {}'
.format(
operator, ', '.join(self.supported_operators)
"expected one of: {}".format(
operator, ", ".join(self.supported_operators)
)
)
......@@ -67,14 +59,18 @@ class GenericConstraint(BaseConstraint):
is_provider_non_equal_op = self.OP_NE is provider.operator
if (
is_equal_op and is_provider_equal_op
or is_non_equal_op and is_provider_non_equal_op
is_equal_op
and is_provider_equal_op
or is_non_equal_op
and is_provider_non_equal_op
):
return self._version == provider.version
if (
is_equal_op and is_provider_non_equal_op
or is_non_equal_op and is_provider_equal_op
is_equal_op
and is_provider_non_equal_op
or is_non_equal_op
and is_provider_equal_op
):
return self._version != provider.version
......@@ -88,12 +84,11 @@ class GenericConstraint(BaseConstraint):
"""
pretty_constraint = constraints
or_constraints = re.split('\s*\|\|?\s*', constraints.strip())
or_constraints = re.split("\s*\|\|?\s*", constraints.strip())
or_groups = []
for constraints in or_constraints:
and_constraints = re.split(
'(?<!^)(?<![ ,]) *(?<!-)[, ](?!-) *(?!,|$)',
constraints
"(?<!^)(?<![ ,]) *(?<!-)[, ](?!-) *(?!,|$)", constraints
)
if len(and_constraints) > 1:
constraint_objects = []
......@@ -121,30 +116,25 @@ class GenericConstraint(BaseConstraint):
@classmethod
def _parse_constraint(cls, constraint):
m = re.match('(?i)^v?[xX*](\.[xX*])*$', constraint)
m = re.match("(?i)^v?[xX*](\.[xX*])*$", constraint)
if m:
return EmptyConstraint(),
return (EmptyConstraint(),)
# Basic Comparators
m = re.match('^(!=|==?)?\s*(.*)', constraint)
m = re.match("^(!=|==?)?\s*(.*)", constraint)
if m:
return GenericConstraint(m.group(1) or '=', m.group(2)),
return (GenericConstraint(m.group(1) or "=", m.group(2)),)
raise ValueError(
'Could not parse generic constraint: {}'.format(constraint)
)
raise ValueError("Could not parse generic constraint: {}".format(constraint))
def __str__(self):
op = self._trans_op_int[self._operator]
if op == '==':
op = ''
if op == "==":
op = ""
else:
op = op + ' '
op = op + " "
return '{}{}'.format(
op,
self._version
)
return "{}{}".format(op, self._version)
def __repr__(self):
return '<GenericConstraint \'{}\'>'.format(str(self))
return "<GenericConstraint '{}'>".format(str(self))
......@@ -2,7 +2,6 @@ from .base_constraint import BaseConstraint
class MultiConstraint(BaseConstraint):
def __init__(self, constraints, conjunctive=True):
self._constraints = tuple(constraints)
self._conjunctive = conjunctive
......@@ -36,6 +35,4 @@ class MultiConstraint(BaseConstraint):
for constraint in self._constraints:
constraints.append(str(constraint))
return '{}'.format(
(', ' if self._conjunctive else ' || ').join(constraints)
)
return "{}".format((", " if self._conjunctive else " || ").join(constraints))
......@@ -4,23 +4,20 @@ from .constraint import Constraint
class WilcardConstraint(Constraint):
def __init__(self, constraint): # type: (str) -> None
m = re.match(
'^(!= ?|==)?v?(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:\.[xX*])+$',
constraint
"^(!= ?|==)?v?(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:\.[xX*])+$", constraint
)
if not m:
raise ValueError('Invalid value for wildcard constraint')
raise ValueError("Invalid value for wildcard constraint")
if not m.group(1):
operator = '=='
operator = "=="
else:
operator = m.group(1).strip()
super(WilcardConstraint, self).__init__(
operator,
'.'.join([g if g else '*' for g in m.groups()[1:]])
operator, ".".join([g if g else "*" for g in m.groups()[1:]])
)
if m.group(4):
......@@ -34,31 +31,27 @@ class WilcardConstraint(Constraint):
parser = VersionParser()
groups = m.groups()[1:]
low_version = parser._manipulate_version_string(
groups, position
)
high_version = parser._manipulate_version_string(
groups, position, 1
)
low_version = parser._manipulate_version_string(groups, position)
high_version = parser._manipulate_version_string(groups, position, 1)
if operator == '!=':
if low_version == '0.0.0.0':
self._constraint = Constraint('>=', high_version)
if operator == "!=":
if low_version == "0.0.0.0":
self._constraint = Constraint(">=", high_version)
else:
self._constraint = parser.parse_constraints(
'<{} || >={}'.format(low_version, high_version)
"<{} || >={}".format(low_version, high_version)
)
else:
if low_version == '0.0.0.0':
self._constraint = Constraint('<', high_version)
if low_version == "0.0.0.0":
self._constraint = Constraint("<", high_version)
else:
self._constraint = parser.parse_constraints(
'>={},<{}'.format(low_version, high_version)
">={},<{}".format(low_version, high_version)
)
@property
def supported_operators(self):
return ['!=', '==']
return ["!=", "=="]
@property
def constraint(self):
......@@ -71,11 +64,8 @@ class WilcardConstraint(Constraint):
return provider.matches(self._constraint)
def __str__(self):
op = ''
if self.string_operator == '!=':
op = '!= '
op = ""
if self.string_operator == "!=":
op = "!= "
return '{}{}'.format(
op,
self._version
)
return "{}{}".format(op, self._version)
......@@ -12,14 +12,14 @@ from .constraints.multi_constraint import MultiConstraint
class Dependency(object):
def __init__(self,
name, # type: str
constraint, # type: str
optional=False, # type: bool
category='main', # type: str
allows_prereleases=False # type: bool
):
def __init__(
self,
name, # type: str
constraint, # type: str
optional=False, # type: bool
category="main", # type: str
allows_prereleases=False, # type: bool
):
self._name = canonicalize_name(name)
self._pretty_name = name
......@@ -29,16 +29,16 @@ class Dependency(object):
else:
self._constraint = constraint
except ValueError:
self._constraint = parse_constraint('*')
self._constraint = parse_constraint("*")
self._pretty_constraint = str(constraint)
self._optional = optional
self._category = category
self._allows_prereleases = allows_prereleases
self._python_versions = '*'
self._python_constraint = parse_constraint('*')
self._platform = '*'
self._python_versions = "*"
self._python_constraint = parse_constraint("*")
self._platform = "*"
self._platform_constraint = EmptyConstraint()
self._extras = []
......@@ -53,7 +53,7 @@ class Dependency(object):
@property
def constraint(self):
return self._constraint
@property
def pretty_constraint(self):
return self._pretty_constraint
......@@ -129,49 +129,47 @@ class Dependency(object):
requirement = self.pretty_name
if self.extras:
requirement += '[{}]'.format(','.join(self.extras))
requirement += "[{}]".format(",".join(self.extras))
if isinstance(self.constraint, VersionUnion):
requirement += ' ({})'.format(','.join(
[str(c).replace(' ', '') for c in self.constraint.ranges]
))
requirement += " ({})".format(
",".join([str(c).replace(" ", "") for c in self.constraint.ranges])
)
elif isinstance(self.constraint, Version):
requirement += ' (=={})'.format(self.constraint.text)
requirement += " (=={})".format(self.constraint.text)
elif not self.constraint.is_any():
requirement += ' ({})'.format(str(self.constraint).replace(' ', ''))
requirement += " ({})".format(str(self.constraint).replace(" ", ""))
# Markers
markers = []
# Python marker
if self.python_versions != '*':
if self.python_versions != "*":
python_constraint = self.python_constraint
markers.append(
self._create_nested_marker('python_version', python_constraint)
self._create_nested_marker("python_version", python_constraint)
)
if self.platform != '*':
if self.platform != "*":
platform_constraint = self.platform_constraint
markers.append(
self._create_nested_marker('sys_platform', platform_constraint)
self._create_nested_marker("sys_platform", platform_constraint)
)
in_extras = ' || '.join(self._in_extras)
in_extras = " || ".join(self._in_extras)
if in_extras and with_extras:
markers.append(
self._create_nested_marker(
'extra', GenericConstraint.parse(in_extras)
)
self._create_nested_marker("extra", GenericConstraint.parse(in_extras))
)
if markers:
if len(markers) > 1:
markers = ['({})'.format(m) for m in markers]
requirement += '; {}'.format(' and '.join(markers))
markers = ["({})".format(m) for m in markers]
requirement += "; {}".format(" and ".join(markers))
else:
requirement += '; {}'.format(markers[0])
requirement += "; {}".format(markers[0])
return requirement
......@@ -185,13 +183,12 @@ class Dependency(object):
parts.append((multi, self._create_nested_marker(name, c)))
glue = ' and '
glue = " and "
if constraint.is_disjunctive():
parts = [
'({})'.format(part[1]) if part[0] else part[1]
for part in parts
"({})".format(part[1]) if part[0] else part[1] for part in parts
]
glue = ' or '
glue = " or "
else:
parts = [part[1] for part in parts]
......@@ -205,30 +202,25 @@ class Dependency(object):
for c in constraint.ranges:
parts.append(self._create_nested_marker(name, c))
glue = ' or '
parts = [
'({})'.format(part)
for part in parts
]
glue = " or "
parts = ["({})".format(part) for part in parts]
marker = glue.join(parts)
elif isinstance(constraint, Version):
marker = '{} == "{}"'.format(
name, constraint.text
)
marker = '{} == "{}"'.format(name, constraint.text)
else:
if constraint.min is not None:
op = '>='
op = ">="
if not constraint.include_min:
op = '>'
op = ">"
version = constraint.min.text
if constraint.max is not None:
text = '{} {} "{}"'.format(name, op, version)
op = '<='
op = "<="
if not constraint.include_max:
op = '<'
op = "<"
version = constraint.max
......@@ -236,17 +228,15 @@ class Dependency(object):
return text
elif constraint.max is not None:
op = '<='
op = "<="
if not constraint.include_max:
op = '<'
op = "<"
version = constraint.max
else:
return ''
return ""
marker = '{} {} "{}"'.format(
name, op, version
)
marker = '{} {} "{}"'.format(name, op, version)
return marker
......@@ -268,7 +258,7 @@ class Dependency(object):
constraint,
optional=self.is_optional(),
category=self.category,
allows_prereleases=self.allows_prereleases()
allows_prereleases=self.allows_prereleases(),
)
new.is_root = self.is_root
......@@ -299,9 +289,7 @@ class Dependency(object):
if self.is_root:
return self._pretty_name
return '{} ({})'.format(
self._pretty_name, self._pretty_constraint
)
return "{} ({})".format(self._pretty_name, self._pretty_constraint)
def __repr__(self):
return '<{} {}>'.format(self.__class__.__name__, str(self))
return "<{} {}>".format(self.__class__.__name__, str(self))
......@@ -16,23 +16,19 @@ from .dependency import Dependency
# Patching pkginfo to support Metadata version 2.1 (PEP 566)
HEADER_ATTRS.update(
{
'2.1': HEADER_ATTRS_2_0 + (
('Provides-Extra', 'provides_extra', True),
)
}
{"2.1": HEADER_ATTRS_2_0 + (("Provides-Extra", "provides_extra", True),)}
)
class DirectoryDependency(Dependency):
def __init__(self,
path, # type: Path
category='main', # type: str
optional=False, # type: bool
base=None, # type: Path
develop=False # type: bool
):
def __init__(
self,
path, # type: Path
category="main", # type: str
optional=False, # type: bool
base=None, # type: Path
develop=False, # type: bool
):
from . import dependency_from_pep_508
from .package import Package
......@@ -45,27 +41,24 @@ class DirectoryDependency(Dependency):
self._full_path = self._base / self._path
if not self._full_path.exists():
raise ValueError('Directory {} does not exist'.format(self._path))
raise ValueError("Directory {} does not exist".format(self._path))
if self._full_path.is_file():
raise ValueError(
'{} is a file, expected a directory'.format(self._path)
)
raise ValueError("{} is a file, expected a directory".format(self._path))
# Checking content to dertermine actions
setup = self._full_path / 'setup.py'
pyproject = TomlFile(self._full_path / 'pyproject.toml')
setup = self._full_path / "setup.py"
pyproject = TomlFile(self._full_path / "pyproject.toml")
has_poetry = False
if pyproject.exists():
pyproject_content = pyproject.read(True)
has_poetry = (
'tool' in pyproject_content
and 'poetry' in pyproject_content['tool']
"tool" in pyproject_content and "poetry" in pyproject_content["tool"]
)
if not setup.exists() and not has_poetry:
raise ValueError(
'Directory {} does not seem to be a Python package'.format(
"Directory {} does not seem to be a Python package".format(
self._full_path
)
)
......@@ -77,7 +70,7 @@ class DirectoryDependency(Dependency):
poetry = Poetry.create(self._full_path)
builder = SdistBuilder(poetry, NullVenv(), NullIO())
with setup.open('w') as f:
with setup.open("w") as f:
f.write(decode(builder.build_setup()))
package = poetry.package
......@@ -94,13 +87,11 @@ class DirectoryDependency(Dependency):
try:
cwd = base
venv = Venv.create(NullIO(), cwd=cwd)
venv.run(
'python', 'setup.py', 'egg_info'
)
venv.run("python", "setup.py", "egg_info")
finally:
os.chdir(current_dir)
egg_info = list(self._full_path.glob('*.egg-info'))[0]
egg_info = list(self._full_path.glob("*.egg-info"))[0]
meta = pkginfo.UnpackedSDist(str(egg_info))
......@@ -108,7 +99,7 @@ class DirectoryDependency(Dependency):
reqs = list(meta.requires_dist)
else:
reqs = []
requires = egg_info / 'requires.txt'
requires = egg_info / "requires.txt"
if requires.exists():
with requires.open() as f:
reqs = parse_requires(f.read())
......@@ -123,17 +114,13 @@ class DirectoryDependency(Dependency):
package.python_versions = meta.requires_python
if meta.platforms:
platforms = [
p
for p in meta.platforms
if p.lower() != 'unknown'
]
platforms = [p for p in meta.platforms if p.lower() != "unknown"]
if platforms:
package.platform = ' || '.join(platforms)
package.platform = " || ".join(platforms)
self._package = package
self._package.source_type = 'directory'
self._package.source_type = "directory"
self._package.source_url = str(self._path)
super(DirectoryDependency, self).__init__(
......@@ -141,7 +128,7 @@ class DirectoryDependency(Dependency):
self._package.version,
category=category,
optional=optional,
allows_prereleases=True
allows_prereleases=True,
)
@property
......
......@@ -12,22 +12,18 @@ from .dependency import Dependency
# Patching pkginfo to support Metadata version 2.1 (PEP 566)
HEADER_ATTRS.update(
{
'2.1': HEADER_ATTRS_2_0 + (
('Provides-Extra', 'provides_extra', True),
)
}
{"2.1": HEADER_ATTRS_2_0 + (("Provides-Extra", "provides_extra", True),)}
)
class FileDependency(Dependency):
def __init__(self,
path, # type: Path
category='main', # type: str
optional=False, # type: bool
base=None # type: Path
):
def __init__(
self,
path, # type: Path
category="main", # type: str
optional=False, # type: bool
base=None, # type: Path
):
self._path = path
self._base = base
self._full_path = path
......@@ -36,14 +32,12 @@ class FileDependency(Dependency):
self._full_path = self._base / self._path
if not self._full_path.exists():
raise ValueError('File {} does not exist'.format(self._path))
raise ValueError("File {} does not exist".format(self._path))
if self._full_path.is_dir():
raise ValueError(
'{} is a directory, expected a file'.format(self._path)
)
raise ValueError("{} is a directory, expected a file".format(self._path))
if self._path.suffix == '.whl':
if self._path.suffix == ".whl":
self._meta = pkginfo.Wheel(str(self._full_path))
else:
# Assume sdist
......@@ -54,7 +48,7 @@ class FileDependency(Dependency):
self._meta.version,
category=category,
optional=optional,
allows_prereleases=True
allows_prereleases=True,
)
@property
......@@ -74,8 +68,8 @@ class FileDependency(Dependency):
def hash(self):
h = hashlib.sha256()
with self._full_path.open('rb') as fp:
for content in iter(lambda: fp.read(io.DEFAULT_BUFFER_SIZE), b''):
with self._full_path.open("rb") as fp:
for content in iter(lambda: fp.read(io.DEFAULT_BUFFER_SIZE), b""):
h.update(content)
return h.hexdigest()
......@@ -12,11 +12,7 @@ from poetry.utils.toml_file import TomlFile
class Locker:
_relevant_keys = [
'dependencies',
'dev-dependencies',
'source',
]
_relevant_keys = ["dependencies", "dev-dependencies", "source"]
def __init__(self, lock, local_config): # type: (Path, dict) -> None
self._lock = TomlFile(lock)
......@@ -42,22 +38,23 @@ class Locker:
if not self._lock.exists():
return False
return 'package' in self.lock_data
return "package" in self.lock_data
def is_fresh(self): # type: () -> bool
"""
Checks whether the lock file is still up to date with the current hash.
"""
lock = self._lock.read(True)
metadata = lock.get('metadata', {})
metadata = lock.get("metadata", {})
if 'content-hash' in metadata:
return self._content_hash == lock['metadata']['content-hash']
if "content-hash" in metadata:
return self._content_hash == lock["metadata"]["content-hash"]
return False
def locked_repository(self, with_dev_reqs=False
): # type: (bool) -> poetry.repositories.Repository
def locked_repository(
self, with_dev_reqs=False
): # type: (bool) -> poetry.repositories.Repository
"""
Searches and returns a repository of locked packages.
"""
......@@ -68,10 +65,10 @@ class Locker:
packages = poetry.repositories.Repository()
if with_dev_reqs:
locked_packages = lock_data['package']
locked_packages = lock_data["package"]
else:
locked_packages = [
p for p in lock_data['package'] if p['category'] == 'main'
p for p in lock_data["package"] if p["category"] == "main"
]
if not locked_packages:
......@@ -79,52 +76,49 @@ class Locker:
for info in locked_packages:
package = poetry.packages.Package(
info['name'],
info['version'],
info['version']
info["name"], info["version"], info["version"]
)
package.description = info.get('description', '')
package.category = info['category']
package.optional = info['optional']
package.hashes = lock_data['metadata']['hashes'][info['name']]
package.python_versions = info['python-versions']
package.description = info.get("description", "")
package.category = info["category"]
package.optional = info["optional"]
package.hashes = lock_data["metadata"]["hashes"][info["name"]]
package.python_versions = info["python-versions"]
for dep_name, constraint in info.get('dependencies', {}).items():
for dep_name, constraint in info.get("dependencies", {}).items():
package.add_dependency(dep_name, constraint)
if 'requirements' in info:
package.requirements = info['requirements']
if "requirements" in info:
package.requirements = info["requirements"]
if 'source' in info:
package.source_type = info['source']['type']
package.source_url = info['source']['url']
package.source_reference = info['source']['reference']
if "source" in info:
package.source_type = info["source"]["type"]
package.source_url = info["source"]["url"]
package.source_reference = info["source"]["reference"]
packages.add_package(package)
return packages
def set_lock_data(self,
root, packages): # type: () -> bool
def set_lock_data(self, root, packages): # type: () -> bool
hashes = {}
packages = self._lock_packages(packages)
# Retrieving hashes
for package in packages:
hashes[package['name']] = package['hashes']
del package['hashes']
hashes[package["name"]] = package["hashes"]
del package["hashes"]
lock = {
'package': packages,
'metadata': {
'python-versions': root.python_versions,
'platform': root.platform,
'content-hash': self._content_hash,
'hashes': hashes,
}
"package": packages,
"metadata": {
"python-versions": root.python_versions,
"platform": root.platform,
"content-hash": self._content_hash,
"hashes": hashes,
},
}
if root.extras:
lock['extras'] = {
lock["extras"] = {
extra: [dep.pretty_name for dep in deps]
for extra, deps in root.extras.items()
}
......@@ -158,15 +152,13 @@ class Locker:
def _get_lock_data(self): # type: () -> dict
if not self._lock.exists():
raise RuntimeError(
'No lockfile found. Unable to read locked packages'
)
raise RuntimeError("No lockfile found. Unable to read locked packages")
return self._lock.read(True)
def _lock_packages(self,
packages
): # type: (List['poetry.packages.Package']) -> list
def _lock_packages(
self, packages
): # type: (List['poetry.packages.Package']) -> list
locked = []
for package in sorted(packages, key=lambda x: x.name):
......@@ -176,8 +168,7 @@ class Locker:
return locked
def _dump_package(self, package
): # type: (poetry.packages.Package) -> dict
def _dump_package(self, package): # type: (poetry.packages.Package) -> dict
dependencies = {}
for dependency in package.requires:
if dependency.is_optional():
......@@ -186,26 +177,25 @@ class Locker:
dependencies[dependency.pretty_name] = str(dependency.pretty_constraint)
data = {
'name': package.pretty_name,
'version': package.pretty_version,
'description': package.description,
'category': package.category,
'optional': package.optional,
'python-versions': package.python_versions,
'platform': package.platform,
'hashes': package.hashes,
'dependencies': dependencies
"name": package.pretty_name,
"version": package.pretty_version,
"description": package.description,
"category": package.category,
"optional": package.optional,
"python-versions": package.python_versions,
"platform": package.platform,
"hashes": package.hashes,
"dependencies": dependencies,
}
if package.source_type:
data['source'] = {
'type': package.source_type,
'url': package.source_url,
'reference': package.source_reference
data["source"] = {
"type": package.source_type,
"url": package.source_url,
"reference": package.source_reference,
}
if package.requirements:
data['requirements'] = package.requirements
data["requirements"] = package.requirements
return data
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