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