Skip to content

Commit

Permalink
Add new dependency resolver
Browse files Browse the repository at this point in the history
  • Loading branch information
sdispater committed May 17, 2018
1 parent 4217366 commit 04e1f60
Show file tree
Hide file tree
Showing 89 changed files with 4,321 additions and 1,830 deletions.
2 changes: 1 addition & 1 deletion poetry/__version__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '0.9.0'
__version__ = '0.10.0a0'
5 changes: 2 additions & 3 deletions poetry/console/commands/add.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class AddCommand(VenvCommand):

def handle(self):
from poetry.installation import Installer
from poetry.semver.version_parser import VersionParser
from poetry.semver.semver import parse_constraint

packages = self.argument('name')
is_dev = self.option('dev')
Expand Down Expand Up @@ -76,9 +76,8 @@ def handle(self):
requirements = self._format_requirements(requirements)

# validate requirements format
parser = VersionParser()
for constraint in requirements.values():
parser.parse_constraints(constraint)
parse_constraint(constraint)

for name, constraint in requirements.items():
constraint = {
Expand Down
19 changes: 13 additions & 6 deletions poetry/console/commands/debug/resolve.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,39 +19,46 @@ class DebugResolveCommand(Command):

def handle(self):
from poetry.packages import Dependency
from poetry.packages import ProjectPackage
from poetry.puzzle import Solver
from poetry.repositories.repository import Repository
from poetry.semver.version_parser import VersionParser
from poetry.semver.semver import parse_constraint

packages = self.argument('package')

if not packages:
package = self.poetry.package
dependencies = package.requires + package.dev_requires
else:
requirements = self._determine_requirements(packages)
requirements = self._format_requirements(requirements)

# validate requirements format
parser = VersionParser()
for constraint in requirements.values():
parser.parse_constraints(constraint)
parse_constraint(constraint)

dependencies = []
for name, constraint in requirements.items():
dependencies.append(
Dependency(name, constraint)
)

package = ProjectPackage(
self.poetry.package.name,
self.poetry.package.version
)
package.python_versions = self.poetry.package.python_versions
for dep in dependencies:
package.requires.append(dep)

solver = Solver(
self.poetry.package,
package,
self.poetry.pool,
Repository(),
Repository(),
self.output
)

ops = solver.solve(dependencies)
ops = solver.solve()

self.line('')
self.line('Resolution results:')
Expand Down
6 changes: 3 additions & 3 deletions poetry/console/commands/show.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,14 +253,14 @@ def find_latest_package(self, package):
)

def get_update_status(self, latest, package):
from poetry.semver import statisfies
from poetry.semver.semver import parse_constraint

if latest.full_pretty_version == package.full_pretty_version:
return 'up-to-date'

constraint = '^' + package.pretty_version
constraint = parse_constraint('^' + package.pretty_version)

if latest.version and statisfies(latest.version, constraint):
if latest.version and constraint.allows(latest.version):
# It needs an immediate semver-compliant upgrade
return 'semver-safe-update'

Expand Down
3 changes: 2 additions & 1 deletion poetry/console/styles/poetry.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ def __init__(self, i, o):
super(PoetryStyle, self).__init__(i, o)

self.output.get_formatter().add_style('error', 'red')
self.output.get_formatter().add_style('warning', 'black', 'yellow')
self.output.get_formatter().add_style('warning', 'yellow')
self.output.get_formatter().add_style('question', 'blue')
self.output.get_formatter().add_style('comment', 'blue')

def writeln(self, messages,
type=OutputStyle.OUTPUT_NORMAL,
Expand Down
48 changes: 9 additions & 39 deletions poetry/installation/installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@
from poetry.repositories import Pool
from poetry.repositories import Repository
from poetry.repositories.installed_repository import InstalledRepository
from poetry.semver.constraints import Constraint
from poetry.semver.version_parser import VersionParser
from poetry.semver.semver import parse_constraint
from poetry.semver.semver import Version
from poetry.utils.helpers import canonicalize_name

from .base_installer import BaseInstaller
from .pip_installer import PipInstaller
Expand Down Expand Up @@ -112,7 +113,7 @@ def execute_operations(self, execute=True): # type: (bool) -> Installer
return self

def whitelist(self, packages): # type: (dict) -> Installer
self._whitelist = packages
self._whitelist = [canonicalize_name(p) for p in packages]

return self

Expand All @@ -135,33 +136,6 @@ def _do_install(self, local_repo):
)

self._io.writeln('<info>Updating dependencies</>')
fixed = []

# If the whitelist is enabled, packages not in it are fixed
# to the version specified in the lock
if self._whitelist:
# collect packages to fixate from root requirements
candidates = []
for package in locked_repository.packages:
candidates.append(package)

# fix them to the version in lock if they are not updateable
for candidate in candidates:
to_fix = True
for require in self._whitelist.keys():
if require == candidate.name:
to_fix = False

if to_fix:
dependency = Dependency(
candidate.name,
candidate.version,
optional=candidate.optional,
category=candidate.category,
allows_prereleases=candidate.is_prerelease()
)
fixed.append(dependency)

solver = Solver(
self._package,
self._pool,
Expand All @@ -170,10 +144,7 @@ def _do_install(self, local_repo):
self._io
)

request = self._package.requires
request += self._package.dev_requires

ops = solver.solve(request, fixed=fixed)
ops = solver.solve(use_latest=self._whitelist)
else:
self._io.writeln('<info>Installing dependencies from lock file</>')

Expand Down Expand Up @@ -451,18 +422,17 @@ def _filter_operations(self,
if op.job_type == 'uninstall':
continue

parser = VersionParser()
python = '.'.join([str(i) for i in self._venv.version_info[:3]])
python = Version.parse('.'.join([str(i) for i in self._venv.version_info[:3]]))
if 'python' in package.requirements:
python_constraint = parser.parse_constraints(
python_constraint = parse_constraint(
package.requirements['python']
)
if not python_constraint.matches(Constraint('=', python)):
if not python_constraint.allows(python):
# Incompatible python versions
op.skip('Not needed for the current python version')
continue

if not package.python_constraint.matches(Constraint('=', python)):
if not package.python_constraint.allows(python):
op.skip('Not needed for the current python version')
continue

Expand Down
32 changes: 0 additions & 32 deletions poetry/masonry/builders/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@
from collections import defaultdict
from contextlib import contextmanager

from poetry.semver.constraints import Constraint
from poetry.semver.constraints import MultiConstraint
from poetry.semver.version_parser import VersionParser
from poetry.utils._compat import Path
from poetry.vcs import get_vcs

Expand Down Expand Up @@ -156,35 +153,6 @@ def convert_author(cls, author): # type: () -> dict
'email': email
}

def get_classifers(self):
classifiers = []

# Automatically set python classifiers
parser = VersionParser()
if self._package.python_versions == '*':
python_constraint = parser.parse_constraints('~2.7 || ^3.4')
else:
python_constraint = self._package.python_constraint

for version in sorted(self.AVAILABLE_PYTHONS):
if python_constraint.matches(Constraint('=', version)):
classifiers.append(
'Programming Language :: Python :: {}'.format(version)
)

return classifiers

def convert_python_version(self):
constraint = self._package.python_constraint
if isinstance(constraint, MultiConstraint):
python_requires = ','.join(
[str(c).replace(' ', '') for c in constraint.constraints]
)
else:
python_requires = str(constraint).replace(' ', '')

return python_requires

@classmethod
@contextmanager
def temporary_directory(cls, *args, **kwargs):
Expand Down
4 changes: 2 additions & 2 deletions poetry/masonry/builders/sdist.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,15 +64,15 @@ def build(self, target_dir=None): # type: (Path) -> Path
target_dir.mkdir(parents=True)

target = target_dir / '{}-{}.tar.gz'.format(
self._package.pretty_name, self._package.version
self._package.pretty_name, self._meta.version
)
gz = GzipFile(target.as_posix(), mode='wb')
tar = tarfile.TarFile(target.as_posix(), mode='w', fileobj=gz,
format=tarfile.PAX_FORMAT)

try:
tar_dir = '{}-{}'.format(
self._package.pretty_name, self._package.version
self._package.pretty_name, self._meta.version
)

files_to_add = self.find_files_to_add(exclude_build=False)
Expand Down
14 changes: 4 additions & 10 deletions poetry/masonry/builders/wheel.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@
from io import StringIO

from poetry.__version__ import __version__
from poetry.semver.constraints import Constraint
from poetry.semver.constraints import MultiConstraint
from poetry.semver.semver import parse_constraint
from poetry.utils._compat import Path

from ..utils.helpers import normalize_file_permissions
Expand Down Expand Up @@ -181,23 +180,18 @@ def find_excluded_files(self): # type: () -> list

@property
def dist_info(self): # type: () -> str
return self.dist_info_name(self._package.name, self._package.version)
return self.dist_info_name(self._package.name, self._meta.version)

@property
def wheel_filename(self): # type: () -> str
return '{}-{}-{}.whl'.format(
re.sub("[^\w\d.]+", "_", self._package.pretty_name, flags=re.UNICODE),
re.sub("[^\w\d.]+", "_", self._package.version, flags=re.UNICODE),
re.sub("[^\w\d.]+", "_", self._meta.version, flags=re.UNICODE),
self.tag
)

def supports_python2(self):
return self._package.python_constraint.matches(
MultiConstraint([
Constraint('>=', '2.0.0'),
Constraint('<', '3.0.0')
])
)
return self._package.python_constraint.allows_any(parse_constraint('>=2.0.0 <3.0.0'))

def dist_info_name(self, distribution, version): # type: (...) -> str
escaped_name = re.sub("[^\w\d.]+", "_", distribution, flags=re.UNICODE)
Expand Down
3 changes: 2 additions & 1 deletion poetry/masonry/metadata.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from poetry.utils.helpers import canonicalize_name
from poetry.utils.helpers import normalize_version
from poetry.version.helpers import format_python_constraint


Expand Down Expand Up @@ -42,7 +43,7 @@ def from_package(cls, package): # type: (...) -> Metadata
meta = cls()

meta.name = canonicalize_name(package.name)
meta.version = package.version
meta.version = normalize_version(package.version.text)
meta.summary = package.description
if package.readme:
with package.readme.open() as f:
Expand Down
1 change: 1 addition & 0 deletions poetry/packages/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from .file_dependency import FileDependency
from .locker import Locker
from .package import Package
from .project_package import ProjectPackage
from .utils.link import Link
from .utils.utils import convert_markers
from .utils.utils import group_markers
Expand Down

0 comments on commit 04e1f60

Please sign in to comment.