Commit 10db97d8 by Sébastien Eustace

Add support for Python 2.7

parent 9b96d6db
...@@ -2,6 +2,11 @@ ...@@ -2,6 +2,11 @@
## [Unreleased] ## [Unreleased]
### Added
- Added support for Python 2.7.
### Changes ### Changes
- Improved dependency resolution time by using cache control. - Improved dependency resolution time by using cache control.
......
__version__ = '0.7.1' __version__ = '0.8.0a0'
from pathlib import Path
from typing import Any from typing import Any
from .locations import CONFIG_DIR from .locations import CONFIG_DIR
from .utils._compat import Path
from .utils.toml_file import TomlFile from .utils.toml_file import TomlFile
from .utils.toml_file import TOMLFile from .utils.toml_file import TOMLFile
class Config: class Config:
def __init__(self, file: TomlFile): def __init__(self, file): # type: (TomlFile) -> None
self._file = file self._file = file
if not self._file.exists(): if not self._file.exists():
self._raw_content = {} self._raw_content = {}
...@@ -33,7 +33,7 @@ class Config: ...@@ -33,7 +33,7 @@ class Config:
def content(self): def content(self):
return self._content return self._content
def setting(self, setting_name: str) -> Any: def setting(self, setting_name): # type: (str) -> Any
""" """
Retrieve a setting value. Retrieve a setting value.
""" """
...@@ -84,7 +84,7 @@ class Config: ...@@ -84,7 +84,7 @@ class Config:
self._file.write(self._content) self._file.write(self._content)
@classmethod @classmethod
def create(cls, file, base_dir=None) -> 'Config': def create(cls, file, base_dir=None): # type: (...) -> Config
if base_dir is None: if base_dir is None:
base_dir = CONFIG_DIR base_dir = CONFIG_DIR
......
...@@ -31,7 +31,7 @@ from .commands.debug import DebugResolveCommand ...@@ -31,7 +31,7 @@ from .commands.debug import DebugResolveCommand
class Application(BaseApplication): class Application(BaseApplication):
def __init__(self): def __init__(self):
super().__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
...@@ -47,10 +47,10 @@ class Application(BaseApplication): ...@@ -47,10 +47,10 @@ class Application(BaseApplication):
return self._poetry return self._poetry
def reset_poetry(self) -> None: def reset_poetry(self): # type: () -> None
self._poetry = None self._poetry = None
def run(self, i=None, o=None) -> int: def run(self, i=None, o=None): # type: (...) -> int
if i is None: if i is None:
i = ArgvInput() i = ArgvInput()
...@@ -62,13 +62,13 @@ class Application(BaseApplication): ...@@ -62,13 +62,13 @@ class Application(BaseApplication):
self._skip_io_configuration = True self._skip_io_configuration = True
i = RawArgvInput() i = RawArgvInput()
return super().run(i, o) return super(Application, self).run(i, o)
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().do_run(i, o) return super(Application, self).do_run(i, o)
command = self.find(name) command = self.find(name)
...@@ -82,9 +82,9 @@ class Application(BaseApplication): ...@@ -82,9 +82,9 @@ class Application(BaseApplication):
if self._skip_io_configuration: if self._skip_io_configuration:
return return
super().configure_io(i, o) super(Application, self).configure_io(i, o)
def get_default_commands(self) -> list: def get_default_commands(self): # type: () -> list
commands = super(Application, self).get_default_commands() commands = super(Application, self).get_default_commands()
commands += [ commands += [
......
...@@ -103,7 +103,9 @@ If you do not specify a version constraint, poetry will choose a suitable one ba ...@@ -103,7 +103,9 @@ If you do not specify a version constraint, poetry will choose a suitable one ba
return status return status
def _determine_requirements(self, requires: List[str]) -> List[str]: def _determine_requirements(self,
requires # type: List[str]
): # type: (...) -> List[str]
if not requires: if not requires:
return [] return []
...@@ -140,7 +142,7 @@ If you do not specify a version constraint, poetry will choose a suitable one ba ...@@ -140,7 +142,7 @@ If you do not specify a version constraint, poetry will choose a suitable one ba
def _find_best_version_for_package(self, def _find_best_version_for_package(self,
name, name,
required_version=None required_version=None
) -> Tuple[str, str]: ): # type: (...) -> Tuple[str, str]
from poetry.version.version_selector import VersionSelector from poetry.version.version_selector import VersionSelector
selector = VersionSelector(self.poetry.pool) selector = VersionSelector(self.poetry.pool)
...@@ -157,7 +159,7 @@ If you do not specify a version constraint, poetry will choose a suitable one ba ...@@ -157,7 +159,7 @@ If you do not specify a version constraint, poetry will choose a suitable one ba
selector.find_recommended_require_version(package) selector.find_recommended_require_version(package)
) )
def _parse_name_version_pairs(self, pairs: list) -> list: def _parse_name_version_pairs(self, pairs): # type: (list) -> list
result = [] result = []
for i in range(len(pairs)): for i in range(len(pairs)):
...@@ -177,7 +179,7 @@ If you do not specify a version constraint, poetry will choose a suitable one ba ...@@ -177,7 +179,7 @@ If you do not specify a version constraint, poetry will choose a suitable one ba
return result return result
def _format_requirements(self, requirements: List[str]) -> dict: def _format_requirements(self, requirements): # type: (List[str]) -> dict
requires = {} requires = {}
requirements = self._parse_name_version_pairs(requirements) requirements = self._parse_name_version_pairs(requirements)
for requirement in requirements: for requirement in requirements:
......
...@@ -9,10 +9,10 @@ class Command(BaseCommand): ...@@ -9,10 +9,10 @@ class Command(BaseCommand):
def poetry(self): def poetry(self):
return self.get_application().poetry return self.get_application().poetry
def reset_poetry(self) -> None: def reset_poetry(self): # type: () -> None
self.get_application().reset_poetry() self.get_application().reset_poetry()
def run(self, i, o) -> int: def run(self, i, o): # type: () -> int
""" """
Initialize command. Initialize command.
""" """
......
...@@ -38,13 +38,13 @@ To remove a repository (repo is a short alias for repositories): ...@@ -38,13 +38,13 @@ To remove a repository (repo is a short alias for repositories):
def __init__(self): def __init__(self):
from poetry.config import Config from poetry.config import Config
super().__init__() super(ConfigCommand, self).__init__()
self._config = Config.create('config.toml') self._config = Config.create('config.toml')
self._auth_config = Config.create('auth.toml') self._auth_config = Config.create('auth.toml')
def initialize(self, i, o): def initialize(self, i, o):
super().initialize(i, o) super(ConfigCommand, self).initialize(i, o)
# Create config file if it does not exist # Create config file if it does not exist
if not self._config.file.exists(): if not self._config.file.exists():
......
...@@ -62,7 +62,7 @@ class DebugResolveCommand(Command): ...@@ -62,7 +62,7 @@ class DebugResolveCommand(Command):
) )
) )
def _determine_requirements(self, requires: List[str]) -> List[str]: def _determine_requirements(self, requires): # type: (List[str]) -> List[str]
if not requires: if not requires:
return [] return []
...@@ -78,7 +78,7 @@ class DebugResolveCommand(Command): ...@@ -78,7 +78,7 @@ class DebugResolveCommand(Command):
return result return result
def _parse_name_version_pairs(self, pairs: list) -> list: def _parse_name_version_pairs(self, pairs): # type: (list) -> list
result = [] result = []
for i in range(len(pairs)): for i in range(len(pairs)):
...@@ -98,7 +98,7 @@ class DebugResolveCommand(Command): ...@@ -98,7 +98,7 @@ class DebugResolveCommand(Command):
return result return result
def _format_requirements(self, requirements: List[str]) -> dict: def _format_requirements(self, requirements): # type: (List[str]) -> dict
requires = {} requires = {}
requirements = self._parse_name_version_pairs(requirements) requirements = self._parse_name_version_pairs(requirements)
for requirement in requirements: for requirement in requirements:
......
from pathlib import Path from poetry.utils._compat import Path
from .command import Command from .command import Command
......
...@@ -14,7 +14,7 @@ class RunCommand(VenvCommand): ...@@ -14,7 +14,7 @@ class RunCommand(VenvCommand):
venv = self.venv venv = self.venv
return venv.exec(*args) return venv.execute(*args)
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 \
......
# -*- coding: utf-8 -*-
from .venv_command import VenvCommand from .venv_command import VenvCommand
......
...@@ -6,12 +6,12 @@ class VenvCommand(Command): ...@@ -6,12 +6,12 @@ class VenvCommand(Command):
def __init__(self, name=None): def __init__(self, name=None):
self._venv = None self._venv = None
super().__init__(name) super(VenvCommand, self).__init__(name)
def initialize(self, i, o): def initialize(self, i, o):
from poetry.utils.venv import Venv from poetry.utils.venv import Venv
super().initialize(i, o) super(VenvCommand, self).initialize(i, o)
self._venv = Venv.create(o, self.poetry.package.name) self._venv = Venv.create(o, self.poetry.package.name)
......
...@@ -5,7 +5,7 @@ from cleo.styles import OutputStyle ...@@ -5,7 +5,7 @@ from cleo.styles import OutputStyle
class PoetryStyle(CleoStyle): class PoetryStyle(CleoStyle):
def __init__(self, i, o): def __init__(self, i, o):
super().__init__(i, o) super(PoetryStyle, self).__init__(i, o)
self.output.get_formatter().add_style('warning', 'black', 'yellow') self.output.get_formatter().add_style('warning', 'black', 'yellow')
self.output.get_formatter().add_style('question', 'blue') self.output.get_formatter().add_style('question', 'blue')
...@@ -14,11 +14,11 @@ class PoetryStyle(CleoStyle): ...@@ -14,11 +14,11 @@ class PoetryStyle(CleoStyle):
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().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().write(messages, newline=newline, type=type) super(PoetryStyle, self).write(messages, newline=newline, type=type)
import sys import sys
from typing import List from typing import List
from typing import Union
from poetry.packages import Dependency from poetry.packages import Dependency
from poetry.packages import Locker from poetry.packages import Locker
...@@ -26,10 +27,11 @@ class Installer: ...@@ -26,10 +27,11 @@ class Installer:
def __init__(self, def __init__(self,
io, io,
venv, venv,
package: Package, package, # type: Package
locker: Locker, locker, # type: Locker
pool: Pool, pool, # type: Pool
installed: InstalledRepository = None): installed=None # type: (Union[InstalledRepository, None])
):
self._io = io self._io = io
self._venv = venv self._venv = venv
self._package = package self._package = package
...@@ -48,7 +50,10 @@ class Installer: ...@@ -48,7 +50,10 @@ class Installer:
self._extras = [] self._extras = []
self._installer = self._get_installer() self._installer = self._get_installer()
self._installed_repository = installed or self._get_installed() if installed is None:
installed = self._get_installed()
self._installed_repository = installed
@property @property
def installer(self): def installer(self):
...@@ -69,49 +74,49 @@ class Installer: ...@@ -69,49 +74,49 @@ class Installer:
return 0 return 0
def dry_run(self, dry_run=True) -> 'Installer': def dry_run(self, dry_run=True): # type: (bool) -> Installer
self._dry_run = dry_run self._dry_run = dry_run
return self return self
def is_dry_run(self) -> bool: def is_dry_run(self): # type: () -> bool
return self._dry_run return self._dry_run
def verbose(self, verbose=True) -> 'Installer': def verbose(self, verbose=True): # type: (bool) -> Installer
self._verbose = verbose self._verbose = verbose
return self return self
def is_verbose(self) -> bool: def is_verbose(self): # type: () -> bool
return self._verbose return self._verbose
def dev_mode(self, dev_mode=True) -> 'Installer': def dev_mode(self, dev_mode=True): # type: (bool) -> Installer
self._dev_mode = dev_mode self._dev_mode = dev_mode
return self return self
def is_dev_mode(self) -> bool: def is_dev_mode(self): # type: () -> bool
return self._dev_mode return self._dev_mode
def update(self, update=True) -> 'Installer': def update(self, update=True): # type: (bool) -> Installer
self._update = update self._update = update
return self return self
def is_updating(self) -> bool: def is_updating(self): # type: () -> bool
return self._update return self._update
def execute_operations(self, execute=True) -> 'Installer': def execute_operations(self, execute=True): # type: (bool) -> Installer
self._execute_operations = execute self._execute_operations = execute
return self return self
def whitelist(self, packages: dict) -> 'Installer': def whitelist(self, packages): # type: (dict) -> Installer
self._whitelist = packages self._whitelist = packages
return self return self
def extras(self, extras: list) -> 'Installer': def extras(self, extras): # type: (list) -> Installer
self._extras = extras self._extras = extras
return self return self
...@@ -262,7 +267,7 @@ class Installer: ...@@ -262,7 +267,7 @@ class Installer:
for op in ops: for op in ops:
self._execute(op) self._execute(op)
def _execute(self, operation: Operation) -> None: def _execute(self, operation): # type: (Operation) -> None
""" """
Execute a given operation. Execute a given operation.
""" """
...@@ -270,7 +275,7 @@ class Installer: ...@@ -270,7 +275,7 @@ class Installer:
getattr(self, '_execute_{}'.format(method))(operation) getattr(self, '_execute_{}'.format(method))(operation)
def _execute_install(self, operation: Install) -> None: def _execute_install(self, operation): # type: (Install) -> None
if operation.skipped: if operation.skipped:
if self.is_verbose() and (self._execute_operations or self.is_dry_run()): if self.is_verbose() and (self._execute_operations or self.is_dry_run()):
self._io.writeln( self._io.writeln(
...@@ -296,7 +301,7 @@ class Installer: ...@@ -296,7 +301,7 @@ class Installer:
self._installer.install(operation.package) self._installer.install(operation.package)
def _execute_update(self, operation: Update) -> None: def _execute_update(self, operation): # type: (Update) -> None
source = operation.initial_package source = operation.initial_package
target = operation.target_package target = operation.target_package
...@@ -327,7 +332,7 @@ class Installer: ...@@ -327,7 +332,7 @@ class Installer:
self._installer.update(source, target) self._installer.update(source, target)
def _execute_uninstall(self, operation: Uninstall) -> None: def _execute_uninstall(self, operation): # type: (Uninstall) -> None
if operation.skipped: if operation.skipped:
if self.is_verbose() and (self._execute_operations or self.is_dry_run()): if self.is_verbose() and (self._execute_operations or self.is_dry_run()):
self._io.writeln( self._io.writeln(
...@@ -390,8 +395,8 @@ class Installer: ...@@ -390,8 +395,8 @@ class Installer:
local_repo.add_package(package) local_repo.add_package(package)
def _get_operations_from_lock(self, def _get_operations_from_lock(self,
locked_repository: Repository locked_repository # type: Repository
) -> List[Operation]: ): # type: (...) -> List[Operation]
installed_repo = self._installed_repository installed_repo = self._installed_repository
ops = [] ops = []
...@@ -424,7 +429,10 @@ class Installer: ...@@ -424,7 +429,10 @@ class Installer:
return ops return ops
def _filter_operations(self, ops: List[Operation], repo: Repository) -> None: def _filter_operations(self,
ops,
repo
): # type: (List[Operation], Repository) -> None
extra_packages = [p.name for p in extra_packages = [p.name for p in
self._get_extra_packages(repo)] self._get_extra_packages(repo)]
for op in ops: for op in ops:
...@@ -513,8 +521,8 @@ class Installer: ...@@ -513,8 +521,8 @@ class Installer:
return _extra_packages(extra_packages) return _extra_packages(extra_packages)
def _get_installer(self) -> BaseInstaller: def _get_installer(self): # type: () -> BaseInstaller
return PipInstaller(self._venv, self._io) return PipInstaller(self._venv, self._io)
def _get_installed(self) -> InstalledRepository: def _get_installed(self): # type: () -> InstalledRepository
return InstalledRepository.load(self._venv) return InstalledRepository.load(self._venv)
...@@ -20,11 +20,11 @@ class NoopInstaller(BaseInstaller): ...@@ -20,11 +20,11 @@ class NoopInstaller(BaseInstaller):
def removals(self): def removals(self):
return self._removals return self._removals
def install(self, package) -> None: def install(self, package):
self._installs.append(package) self._installs.append(package)
def update(self, source, target) -> None: def update(self, source, target):
self._updates.append((source, target)) self._updates.append((source, target))
def remove(self, package) -> None: def remove(self, package):
self._removals.append(package) self._removals.append(package)
...@@ -10,7 +10,7 @@ from .base_installer import BaseInstaller ...@@ -10,7 +10,7 @@ from .base_installer import BaseInstaller
class PipInstaller(BaseInstaller): class PipInstaller(BaseInstaller):
def __init__(self, venv: Venv, io): def __init__(self, venv, io): # type: (Venv, ...) -> None
self._venv = venv self._venv = venv
self._io = io self._io = io
...@@ -54,10 +54,10 @@ class PipInstaller(BaseInstaller): ...@@ -54,10 +54,10 @@ class PipInstaller(BaseInstaller):
raise raise
def run(self, *args, **kwargs) -> 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) -> str: def requirement(self, package, formatted=False):
if formatted and not package.source_type == 'git': if formatted and not package.source_type == 'git':
req = '{}=={}'.format(package.name, package.version) req = '{}=={}'.format(package.name, package.version)
for h in package.hashes: for h in package.hashes:
...@@ -81,7 +81,9 @@ class PipInstaller(BaseInstaller): ...@@ -81,7 +81,9 @@ class PipInstaller(BaseInstaller):
'reqs.txt', '{}-{}'.format(package.name, package.version) 'reqs.txt', '{}-{}'.format(package.name, package.version)
) )
with open(fd, 'w') as f: try:
f.write(self.requirement(package, formatted=True)) os.write(fd, self.requirement(package, formatted=True))
finally:
os.close(fd)
return name return name
...@@ -7,18 +7,18 @@ from poetry.console.styles.poetry import PoetryStyle ...@@ -7,18 +7,18 @@ from poetry.console.styles.poetry import PoetryStyle
class NullIO(PoetryStyle): class NullIO(PoetryStyle):
def __init__(self): def __init__(self):
super().__init__(ListInput([]), NullOutput()) super(NullIO, self).__init__(ListInput([]), NullOutput())
def is_quiet(self) -> bool: def is_quiet(self): # type: () -> bool
return False return False
def is_verbose(self) -> bool: def is_verbose(self): # type: () -> bool
return False return False
def is_very_verbose(self) -> bool: def is_very_verbose(self): # type: () -> bool
return False return False
def is_debug(self) -> bool: def is_debug(self): # type: () -> bool
return False return False
def writeln(self, *args, **kwargs): def writeln(self, *args, **kwargs):
......
...@@ -9,7 +9,7 @@ _LAYOUTS = { ...@@ -9,7 +9,7 @@ _LAYOUTS = {
} }
def layout(name: 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')
......
...@@ -4,7 +4,7 @@ from poetry.utils.helpers import module_name ...@@ -4,7 +4,7 @@ from poetry.utils.helpers import module_name
from poetry.vcs.git import Git from poetry.vcs.git import Git
TESTS_DEFAULT = """from {package_name} import __version__ TESTS_DEFAULT = u"""from {package_name} import __version__
def test_version(): def test_version():
...@@ -45,7 +45,7 @@ class Layout(object): ...@@ -45,7 +45,7 @@ class Layout(object):
git_config.get('user.name') git_config.get('user.name')
and git_config.get('user.email') and git_config.get('user.email')
): ):
author = '{} <{}>'.format( author = u'{} <{}>'.format(
git_config['user.name'], git_config['user.name'],
git_config['user.email'] git_config['user.email']
) )
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
from .layout import Layout from .layout import Layout
DEFAULT = """__version__ = '{version}' DEFAULT = u"""__version__ = '{version}'
""" """
......
...@@ -4,8 +4,9 @@ PEP-517 compliant buildsystem API ...@@ -4,8 +4,9 @@ PEP-517 compliant buildsystem API
import logging import logging
from pathlib import Path from pathlib import Path
from poetry import Poetry from poetry.poetry import Poetry
from poetry.io import NullIO from poetry.io import NullIO
from poetry.utils.venv import Venv
from .builders import SdistBuilder from .builders import SdistBuilder
from .builders import WheelBuilder from .builders import WheelBuilder
...@@ -38,6 +39,6 @@ def build_wheel(wheel_directory, config_settings=None, metadata_directory=None): ...@@ -38,6 +39,6 @@ def build_wheel(wheel_directory, config_settings=None, metadata_directory=None):
def build_sdist(sdist_directory, config_settings=None): def build_sdist(sdist_directory, config_settings=None):
"""Builds an sdist, places it in sdist_directory""" """Builds an sdist, places it in sdist_directory"""
path = SdistBuilder(poetry, NullIO()).build(Path(sdist_directory)) path = SdistBuilder(poetry, Venv(), NullIO()).build(Path(sdist_directory))
return path.name return path.name
...@@ -16,7 +16,7 @@ class Builder: ...@@ -16,7 +16,7 @@ class Builder:
self._venv = venv self._venv = venv
self._io = io self._io = io
def build(self, fmt: str): 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))
......
# -*- coding: utf-8 -*-
import os import os
import re import re
import shutil
import tempfile
from collections import defaultdict from collections import defaultdict
from pathlib import Path from contextlib import contextmanager
from poetry.semver.constraints import Constraint from poetry.semver.constraints import Constraint
from poetry.semver.constraints import MultiConstraint from poetry.semver.constraints import MultiConstraint
from poetry.semver.version_parser import VersionParser from poetry.semver.version_parser import VersionParser
from poetry.utils._compat import Path
from poetry.vcs import get_vcs from poetry.vcs import get_vcs
from ..metadata import Metadata from ..metadata import Metadata
...@@ -16,7 +20,7 @@ from ..utils.module import Module ...@@ -16,7 +20,7 @@ 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: class Builder(object):
AVAILABLE_PYTHONS = { AVAILABLE_PYTHONS = {
'2', '2',
...@@ -39,7 +43,7 @@ class Builder: ...@@ -39,7 +43,7 @@ class Builder:
def build(self): def build(self):
raise NotImplementedError() raise NotImplementedError()
def find_excluded_files(self) -> list: def find_excluded_files(self): # type: () -> list
# Checking VCS # Checking VCS
vcs = get_vcs(self._path) vcs = get_vcs(self._path)
if not vcs: if not vcs:
...@@ -58,7 +62,7 @@ class Builder: ...@@ -58,7 +62,7 @@ class Builder:
return result return result
def find_files_to_add(self, exclude_build=True) -> list: def find_files_to_add(self, exclude_build=True): # type: () -> list
""" """
Finds all files to add to the tarball Finds all files to add to the tarball
...@@ -116,7 +120,7 @@ class Builder: ...@@ -116,7 +120,7 @@ class Builder:
return sorted(to_add) return sorted(to_add)
def convert_entry_points(self) -> dict: def convert_entry_points(self): # type: () -> dict
result = defaultdict(list) result = defaultdict(list)
# Scripts -> Entry points # Scripts -> Entry points
...@@ -134,7 +138,7 @@ class Builder: ...@@ -134,7 +138,7 @@ class Builder:
return dict(result) return dict(result)
@classmethod @classmethod
def convert_author(cls, author) -> 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')
...@@ -173,3 +177,18 @@ class Builder: ...@@ -173,3 +177,18 @@ class Builder:
python_requires = str(constraint).replace(' ', '') python_requires = str(constraint).replace(' ', '')
return python_requires return python_requires
@classmethod
@contextmanager
def temporary_directory(cls, *args, **kwargs):
try:
from tempfile import TemporaryDirectory
with TemporaryDirectory(*args, **kwargs) as name:
yield name
except ImportError:
name = tempfile.mkdtemp(*args, **kwargs)
yield name
shutil.rmtree(name)
...@@ -4,8 +4,6 @@ import tarfile ...@@ -4,8 +4,6 @@ import tarfile
import poetry.poetry import poetry.poetry
from contextlib import contextmanager from contextlib import contextmanager
from tempfile import TemporaryDirectory
from types import SimpleNamespace
from .builder import Builder from .builder import Builder
from .sdist import SdistBuilder from .sdist import SdistBuilder
...@@ -19,25 +17,22 @@ class CompleteBuilder(Builder): ...@@ -19,25 +17,22 @@ class CompleteBuilder(Builder):
# 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()
sdist_info = SimpleNamespace(builder=sdist_builder, file=sdist_file)
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:
wheel_info = WheelBuilder.make_in( WheelBuilder.make_in(
poetry.poetry.Poetry.create(tmpdir), self._venv, self._io, dist_dir, poetry.poetry.Poetry.create(tmpdir), self._venv, self._io, dist_dir,
original=self._poetry original=self._poetry
) )
return SimpleNamespace(wheel=wheel_info, sdist=sdist_info)
@classmethod @classmethod
@contextmanager @contextmanager
def unpacked_tarball(cls, path): def unpacked_tarball(cls, path):
tf = tarfile.open(str(path)) tf = tarfile.open(str(path))
with TemporaryDirectory() as tmpdir: with cls.temporary_directory() as tmpdir:
tf.extractall(tmpdir) tf.extractall(tmpdir)
files = os.listdir(tmpdir) files = os.listdir(tmpdir)
......
from __future__ import unicode_literals
import os import os
import tarfile import tarfile
...@@ -5,12 +7,13 @@ from collections import defaultdict ...@@ -5,12 +7,13 @@ from collections import defaultdict
from copy import copy from copy import copy
from gzip import GzipFile from gzip import GzipFile
from io import BytesIO from io import BytesIO
from pathlib import Path
from posixpath import join as pjoin from posixpath import join as pjoin
from pprint import pformat from pprint import pformat
from typing import List from typing import List
from poetry.packages import Dependency from poetry.packages import Dependency
from poetry.utils._compat import Path
from poetry.utils._compat import encode
from ..utils.helpers import normalize_file_permissions from ..utils.helpers import normalize_file_permissions
...@@ -51,7 +54,7 @@ Author-email: {author_email} ...@@ -51,7 +54,7 @@ Author-email: {author_email}
class SdistBuilder(Builder): class SdistBuilder(Builder):
def build(self, target_dir: Path = None) -> Path: def build(self, target_dir=None): # type: (Path) -> Path
self._io.writeln(' - Building <info>sdist</info>') self._io.writeln(' - Building <info>sdist</info>')
if target_dir is None: if target_dir is None:
target_dir = self._path / 'dist' target_dir = self._path / 'dist'
...@@ -92,14 +95,14 @@ class SdistBuilder(Builder): ...@@ -92,14 +95,14 @@ class SdistBuilder(Builder):
tar_info.size = len(setup) tar_info.size = len(setup)
tar.addfile(tar_info, BytesIO(setup)) tar.addfile(tar_info, BytesIO(setup))
pkg_info = PKG_INFO.format( pkg_info = encode(PKG_INFO.format(
name=self._meta.name, name=self._meta.name,
version=self._meta.version, version=self._meta.version,
summary=self._meta.summary, summary=self._meta.summary,
home_page=self._meta.home_page, home_page=self._meta.home_page,
author=self._meta.author, author=self._meta.author,
author_email=self._meta.author_email, author_email=self._meta.author_email,
).encode('utf-8') ))
tar_info = tarfile.TarInfo(pjoin(tar_dir, 'PKG-INFO')) tar_info = tarfile.TarInfo(pjoin(tar_dir, 'PKG-INFO'))
tar_info.size = len(pkg_info) tar_info.size = len(pkg_info)
...@@ -112,7 +115,7 @@ class SdistBuilder(Builder): ...@@ -112,7 +115,7 @@ class SdistBuilder(Builder):
return target return target
def build_setup(self) -> bytes: def build_setup(self): # type: () -> bytes
before, extra, after = [], [], [] before, extra, after = [], [], []
# If we have a build script, use it # If we have a build script, use it
...@@ -155,7 +158,7 @@ class SdistBuilder(Builder): ...@@ -155,7 +158,7 @@ class SdistBuilder(Builder):
extra.append("'python_requires': {!r},".format(python_requires)) extra.append("'python_requires': {!r},".format(python_requires))
return SETUP.format( return encode(SETUP.format(
before='\n'.join(before), before='\n'.join(before),
name=self._meta.name, name=self._meta.name,
version=self._meta.version, version=self._meta.version,
...@@ -166,10 +169,10 @@ class SdistBuilder(Builder): ...@@ -166,10 +169,10 @@ class SdistBuilder(Builder):
url=self._meta.home_page, url=self._meta.home_page,
extra='\n '.join(extra), extra='\n '.join(extra),
after='\n'.join(after) after='\n'.join(after)
).encode('utf-8') ))
@classmethod @classmethod
def find_packages(cls, path: str): def find_packages(cls, path):
""" """
Discover subpackages and data. Discover subpackages and data.
...@@ -219,8 +222,9 @@ class SdistBuilder(Builder): ...@@ -219,8 +222,9 @@ class SdistBuilder(Builder):
@classmethod @classmethod
def convert_dependencies(cls, def convert_dependencies(cls,
package, package, # type: Package
dependencies: List[Dependency]): dependencies # type: List[Dependency]
):
main = [] main = []
extras = defaultdict(list) extras = defaultdict(list)
......
from __future__ import unicode_literals
import contextlib import contextlib
import hashlib import hashlib
import os import os
...@@ -13,12 +15,11 @@ except ImportError: ...@@ -13,12 +15,11 @@ except ImportError:
from base64 import urlsafe_b64encode from base64 import urlsafe_b64encode
from io import StringIO from io import StringIO
from pathlib import Path
from types import SimpleNamespace
from poetry.__version__ import __version__ from poetry.__version__ import __version__
from poetry.semver.constraints import Constraint from poetry.semver.constraints import Constraint
from poetry.semver.constraints import MultiConstraint from poetry.semver.constraints import MultiConstraint
from poetry.utils._compat import Path
from ..utils.helpers import normalize_file_permissions from ..utils.helpers import normalize_file_permissions
from ..utils.tags import get_abbr_impl from ..utils.tags import get_abbr_impl
...@@ -39,7 +40,7 @@ Tag: {tag} ...@@ -39,7 +40,7 @@ Tag: {tag}
class WheelBuilder(Builder): class WheelBuilder(Builder):
def __init__(self, poetry, venv, io, target_fp, original=None): def __init__(self, poetry, venv, io, target_fp, original=None):
super().__init__(poetry, venv, io) super(WheelBuilder, self).__init__(poetry, venv, io)
self._records = [] self._records = []
self._original_path = self._path self._original_path = self._path
...@@ -51,26 +52,29 @@ class WheelBuilder(Builder): ...@@ -51,26 +52,29 @@ class WheelBuilder(Builder):
compression=zipfile.ZIP_DEFLATED) compression=zipfile.ZIP_DEFLATED)
@classmethod @classmethod
def make_in(cls, poetry, venv, io, directory, original=None) -> SimpleNamespace: def make_in(cls, poetry, venv, io, directory, original=None):
# We don't know the final filename until metadata is loaded, so write to # We don't know the final filename until metadata is loaded, so write to
# a temporary_file, and rename it afterwards. # a temporary_file, and rename it afterwards.
(fd, temp_path) = tempfile.mkstemp(suffix='.whl', (fd, temp_path) = tempfile.mkstemp(suffix='.whl',
dir=str(directory)) dir=str(directory))
os.close(fd)
try: try:
with open(fd, 'w+b') as fp: with open(temp_path, 'w+b') as fp:
wb = WheelBuilder(poetry, venv, io, fp, original=original) wb = WheelBuilder(poetry, venv, io, fp, original=original)
wb.build() wb.build()
wheel_path = directory / wb.wheel_filename wheel_path = directory / wb.wheel_filename
os.replace(temp_path, str(wheel_path)) if wheel_path.exists():
os.unlink(str(wheel_path))
os.rename(temp_path, str(wheel_path))
except: except:
os.unlink(temp_path) os.unlink(temp_path)
raise raise
return SimpleNamespace(builder=wb, file=wheel_path)
@classmethod @classmethod
def make(cls, poetry, venv, io) -> SimpleNamespace: def make(cls, poetry, venv, io):
"""Build a wheel in the dist/ directory, and optionally upload it. """Build a wheel in the dist/ directory, and optionally upload it.
""" """
dist_dir = poetry.file.parent / 'dist' dist_dir = poetry.file.parent / 'dist'
...@@ -79,9 +83,9 @@ class WheelBuilder(Builder): ...@@ -79,9 +83,9 @@ class WheelBuilder(Builder):
except FileExistsError: except FileExistsError:
pass pass
return cls.make_in(poetry, venv, io, dist_dir) cls.make_in(poetry, venv, io, dist_dir)
def build(self) -> None: def build(self):
self._io.writeln(' - Building <info>wheel</info>') self._io.writeln(' - Building <info>wheel</info>')
try: try:
self._build() self._build()
...@@ -93,7 +97,7 @@ class WheelBuilder(Builder): ...@@ -93,7 +97,7 @@ class WheelBuilder(Builder):
self._io.writeln(' - Built <fg=cyan>{}</>'.format(self.wheel_filename)) self._io.writeln(' - Built <fg=cyan>{}</>'.format(self.wheel_filename))
def _build(self) -> None: def _build(self):
if self._package.build: if self._package.build:
setup = self._path / 'setup.py' setup = self._path / 'setup.py'
...@@ -124,7 +128,7 @@ class WheelBuilder(Builder): ...@@ -124,7 +128,7 @@ class WheelBuilder(Builder):
shutil.rmtree(str(self._path / pkg.name)) shutil.rmtree(str(self._path / pkg.name))
shutil.copytree(str(pkg), str(self._path / pkg.name)) shutil.copytree(str(pkg), str(self._path / pkg.name))
def copy_module(self) -> None: def copy_module(self):
if self._module.is_package(): if self._module.is_package():
files = self.find_files_to_add() files = self.find_files_to_add()
...@@ -164,16 +168,16 @@ class WheelBuilder(Builder): ...@@ -164,16 +168,16 @@ class WheelBuilder(Builder):
# RECORD itself is recorded with no hash or size # RECORD itself is recorded with no hash or size
f.write(self.dist_info + '/RECORD,,\n') f.write(self.dist_info + '/RECORD,,\n')
def find_excluded_files(self) -> list: def find_excluded_files(self): # type: () -> list
# Checking VCS # Checking VCS
return [] return []
@property @property
def dist_info(self) -> str: 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._package.version)
@property @property
def wheel_filename(self) -> str: def wheel_filename(self): # type: () -> str
return '{}-{}-{}.whl'.format( return '{}-{}-{}.whl'.format(
re.sub("[^\w\d.]+", "_", self._package.pretty_name, flags=re.UNICODE), 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._package.version, flags=re.UNICODE),
...@@ -188,7 +192,7 @@ class WheelBuilder(Builder): ...@@ -188,7 +192,7 @@ class WheelBuilder(Builder):
]) ])
) )
def dist_info_name(self, distribution, version) -> str: def dist_info_name(self, distribution, version): # type: (...) -> str
escaped_name = re.sub("[^\w\d.]+", "_", distribution, flags=re.UNICODE) escaped_name = re.sub("[^\w\d.]+", "_", distribution, flags=re.UNICODE)
escaped_version = re.sub("[^\w\d.]+", "_", version, flags=re.UNICODE) escaped_version = re.sub("[^\w\d.]+", "_", version, flags=re.UNICODE)
...@@ -221,7 +225,7 @@ class WheelBuilder(Builder): ...@@ -221,7 +225,7 @@ class WheelBuilder(Builder):
# RECORD # RECORD
rel_path = rel_path.replace(os.sep, '/') rel_path = rel_path.replace(os.sep, '/')
zinfo = zipfile.ZipInfo.from_file(full_path, rel_path) zinfo = zipfile.ZipInfo(rel_path)
# Normalize permission bits to either 755 (executable) or 644 # Normalize permission bits to either 755 (executable) or 644
st_mode = os.stat(full_path).st_mode st_mode = os.stat(full_path).st_mode
...@@ -232,18 +236,20 @@ class WheelBuilder(Builder): ...@@ -232,18 +236,20 @@ class WheelBuilder(Builder):
zinfo.external_attr |= 0x10 # MS-DOS directory flag zinfo.external_attr |= 0x10 # MS-DOS directory flag
hashsum = hashlib.sha256() hashsum = hashlib.sha256()
with open(full_path, 'rb') as src, self._wheel_zip.open(zinfo, with open(full_path, 'rb') as src:
'w') as dst:
while True: while True:
buf = src.read(1024 * 8) buf = src.read(1024 * 8)
if not buf: if not buf:
break break
hashsum.update(buf) hashsum.update(buf)
dst.write(buf)
src.seek(0)
self._wheel_zip.writestr(zinfo, src.read())
size = os.stat(full_path).st_size size = os.stat(full_path).st_size
hash_digest = urlsafe_b64encode(hashsum.digest()).decode( hash_digest = urlsafe_b64encode(
'ascii').rstrip('=') hashsum.digest()
).decode('ascii').rstrip('=')
self._records.append((rel_path, hash_digest, size)) self._records.append((rel_path, hash_digest, size))
......
...@@ -38,7 +38,7 @@ class Metadata: ...@@ -38,7 +38,7 @@ class Metadata:
provides_extra = [] provides_extra = []
@classmethod @classmethod
def from_package(cls, package) -> 'Metadata': def from_package(cls, package): # type: (...) -> Metadata
meta = cls() meta = cls()
meta.name = canonicalize_name(package.name) meta.name = canonicalize_name(package.name)
......
from pathlib import Path from poetry.utils._compat import Path
from poetry.utils.helpers import module_name from poetry.utils.helpers import module_name
...@@ -23,19 +22,19 @@ class Module: ...@@ -23,19 +22,19 @@ class Module:
raise ValueError("No file/folder found for package {}".format(name)) raise ValueError("No file/folder found for package {}".format(name))
@property @property
def name(self) -> str: def name(self): # type: () -> str
return self._name return self._name
@property @property
def path(self) -> Path: def path(self): # type: () -> Path
return self._path return self._path
@property @property
def file(self) -> 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
def is_package(self) -> bool: def is_package(self): # type: () -> bool
return self._is_package return self._is_package
...@@ -5,6 +5,7 @@ Base implementation taken from ...@@ -5,6 +5,7 @@ Base implementation taken from
https://github.com/pypa/wheel/blob/master/wheel/pep425tags.py https://github.com/pypa/wheel/blob/master/wheel/pep425tags.py
and adapted to work with poetry's venv util. and adapted to work with poetry's venv util.
""" """
from __future__ import unicode_literals
import distutils.util import distutils.util
import sys import sys
......
...@@ -6,7 +6,7 @@ from ..conflict import Conflict ...@@ -6,7 +6,7 @@ from ..conflict import Conflict
from ..dependency_graph import DependencyGraph from ..dependency_graph import DependencyGraph
class SpecificationProvider: class SpecificationProvider(object):
""" """
Provides information about specifcations and dependencies to the resolver, Provides information about specifcations and dependencies to the resolver,
allowing the Resolver class to remain generic while still providing power allowing the Resolver class to remain generic while still providing power
...@@ -18,14 +18,14 @@ class SpecificationProvider: ...@@ -18,14 +18,14 @@ class SpecificationProvider:
""" """
@property @property
def name_for_explicit_dependency_source(self) -> str: def name_for_explicit_dependency_source(self): # type: () -> str
return 'user-specified dependency' return 'user-specified dependency'
@property @property
def name_for_locking_dependency_source(self) -> str: def name_for_locking_dependency_source(self): # type: () -> str
return 'Lockfile' return 'Lockfile'
def search_for(self, dependency: Any) -> List[Any]: def search_for(self, dependency): # type: (Any) -> List[Any]
""" """
Search for the specifications that match the given dependency. Search for the specifications that match the given dependency.
...@@ -34,32 +34,34 @@ class SpecificationProvider: ...@@ -34,32 +34,34 @@ class SpecificationProvider:
""" """
return [] return []
def dependencies_for(self, specification: Any) -> List[Any]: def dependencies_for(self, specification): # type: (Any) -> List[Any]
""" """
Returns the dependencies of specification. Returns the dependencies of specification.
""" """
return [] return []
def is_requirement_satisfied_by(self, def is_requirement_satisfied_by(self,
requirement: Any, requirement, # type: Any
activated: DependencyGraph, activated, # type: DependencyGraph
spec: Any) -> bool: spec # type: Any
): # type: (...) -> Any
""" """
Determines whether the given requirement is satisfied by the given Determines whether the given requirement is satisfied by the given
spec, in the context of the current activated dependency graph. spec, in the context of the current activated dependency graph.
""" """
return True return True
def name_for(self, dependency: Any) -> str: def name_for(self, dependency): # type: (Any) -> str
""" """
Returns the name for the given dependency. Returns the name for the given dependency.
""" """
return str(dependency) return str(dependency)
def sort_dependencies(self, def sort_dependencies(self,
dependencies: List[Any], dependencies, # type: List[Any]
activated: DependencyGraph, activated, # type: DependencyGraph
conflicts: Dict[str, List[Conflict]]) -> List[Any]: conflicts # type: Dict[str, List[Conflict]]
): # type: (...) -> List[Any]
""" """
Sort dependencies so that the ones Sort dependencies so that the ones
that are easiest to resolve are first. that are easiest to resolve are first.
...@@ -78,7 +80,7 @@ class SpecificationProvider: ...@@ -78,7 +80,7 @@ class SpecificationProvider:
) )
) )
def allow_missing(self, dependency) -> bool: def allow_missing(self, dependency): # type: (Any) -> bool
""" """
Returns whether this dependency, which has no possible matching Returns whether this dependency, which has no possible matching
specifications, can safely be ignored. specifications, can safely be ignored.
......
import sys import sys
class UI: class UI(object):
def __init__(self, debug=False): def __init__(self, debug=False):
self._debug = debug self._debug = debug
...@@ -11,22 +11,22 @@ class UI: ...@@ -11,22 +11,22 @@ class UI:
return sys.stdout return sys.stdout
@property @property
def progress_rate(self) -> float: def progress_rate(self): # type: () -> float
return 0.33 return 0.33
def is_debugging(self) -> bool: def is_debugging(self): # type: () -> bool
return self._debug return self._debug
def indicate_progress(self) -> None: def indicate_progress(self): # type: () -> None
self.output.write('.') self.output.write('.')
def before_resolution(self) -> None: def before_resolution(self): # type: () -> None
self.output.write('Resolving dependencies...\n') self.output.write('Resolving dependencies...\n')
def after_resolution(self) -> None: def after_resolution(self): # type: () -> None
self.output.write('') self.output.write('')
def debug(self, message, depth) -> None: def debug(self, message, depth): # type: (...) -> None
if self.is_debugging(): if self.is_debugging():
debug_info = str(message) debug_info = str(message)
debug_info = '\n'.join([ debug_info = '\n'.join([
......
...@@ -17,7 +17,7 @@ class NoSuchDependencyError(ResolverError): ...@@ -17,7 +17,7 @@ class NoSuchDependencyError(ResolverError):
if sources: if sources:
message += ' depended upon by {}'.format(sources) message += ' depended upon by {}'.format(sources)
super().__init__(message) super(NoSuchDependencyError, self).__init__(message)
class CircularDependencyError(ResolverError): class CircularDependencyError(ResolverError):
...@@ -48,7 +48,7 @@ class VersionConflict(ResolverError): ...@@ -48,7 +48,7 @@ class VersionConflict(ResolverError):
for c in conflict_requirements: for c in conflict_requirements:
pairs.append((c, source)) pairs.append((c, source))
super().__init__( super(VersionConflict, self).__init__(
'Unable to satisfy the following requirements:\n\n' 'Unable to satisfy the following requirements:\n\n'
'{}'.format( '{}'.format(
'\n'.join('- "{}" required by "{}"'.format(r, d) '\n'.join('- "{}" required by "{}"'.format(r, d)
......
from typing import Any from typing import Any
class Action: class Action(object):
def __init__(self): def __init__(self):
self.previous = None self.previous = None
self.next = None self.next = None
@property @property
def action_name(self) -> str: def action_name(self): # type: () -> str
raise NotImplementedError() raise NotImplementedError()
def up(self, graph: 'DependencyGraph') -> Any: def up(self, graph): # type: (DependencyGraph) -> Any
""" """
Performs the action on the given graph. Performs the action on the given graph.
""" """
raise NotImplementedError() raise NotImplementedError()
def down(self, graph: 'DependencyGraph') -> None: def down(self, graph): # type: (DependencyGraph) -> None
""" """
Reverses the action on the given graph. Reverses the action on the given graph.
""" """
......
...@@ -7,16 +7,6 @@ _NULL = object() ...@@ -7,16 +7,6 @@ _NULL = object()
class AddVertex(Action): class AddVertex(Action):
def __init__(self, name, payload, root): def __init__(self, name, payload, root):
"""
:param name: The name of the vertex.
:type name: str
:param payload: The payload of he vertex
:type payload: Any
:param root: whether the vertex is root or not
:type root: bool
"""
super(AddVertex, self).__init__() super(AddVertex, self).__init__()
self._name = name self._name = name
......
# -*- coding: utf-8 -*-
import logging import logging
from copy import copy from copy import copy
...@@ -26,10 +27,11 @@ logger = logging.getLogger(__name__) ...@@ -26,10 +27,11 @@ logger = logging.getLogger(__name__)
class Resolution: class Resolution:
def __init__(self, def __init__(self,
provider: SpecificationProvider, provider, # type: SpecificationProvider
ui: UI, ui, # type: UI
requested: List[Any], requested, # type: List[Any]
base: DependencyGraph): base # type: DependencyGraph
):
self._provider = provider self._provider = provider
self._ui = ui self._ui = ui
self._requested = requested self._requested = requested
...@@ -43,26 +45,26 @@ class Resolution: ...@@ -43,26 +45,26 @@ class Resolution:
self._started_at = None self._started_at = None
@property @property
def provider(self) -> SpecificationProvider: def provider(self): # type: () -> SpecificationProvider
return self._provider return self._provider
@property @property
def ui(self) -> UI: def ui(self): # type: () -> UI
return self._ui return self._ui
@property @property
def requested(self) -> List[Any]: def requested(self): # type: () -> List[Any]
return self._requested return self._requested
@property @property
def base(self) -> DependencyGraph: def base(self): # type: () -> DependencyGraph
return self._base return self._base
@property @property
def activated(self) -> DependencyGraph: def activated(self): # type: () -> DependencyGraph
return self.state.activated return self.state.activated
def resolve(self) -> DependencyGraph: def resolve(self): # type: () -> DependencyGraph
""" """
Resolve the original requested dependencies into a full Resolve the original requested dependencies into a full
dependency graph. dependency graph.
...@@ -94,7 +96,7 @@ class Resolution: ...@@ -94,7 +96,7 @@ class Resolution:
finally: finally:
self._end() self._end()
def _start(self) -> None: def _start(self): # type: () -> None
""" """
Set up the resolution process. Set up the resolution process.
""" """
...@@ -110,7 +112,7 @@ class Resolution: ...@@ -110,7 +112,7 @@ class Resolution:
self._handle_missing_or_push_dependency_state(self._initial_state()) self._handle_missing_or_push_dependency_state(self._initial_state())
def _resolve_activated_specs(self) -> DependencyGraph: def _resolve_activated_specs(self): # type: () -> DependencyGraph
for vertex in self.activated.vertices.values(): for vertex in self.activated.vertices.values():
if not vertex.payload: if not vertex.payload:
continue continue
...@@ -132,7 +134,7 @@ class Resolution: ...@@ -132,7 +134,7 @@ class Resolution:
return self.activated return self.activated
def _end(self) -> None: def _end(self): # type: () -> None
""" """
Ends the resolution process Ends the resolution process
""" """
...@@ -147,7 +149,7 @@ class Resolution: ...@@ -147,7 +149,7 @@ class Resolution:
) )
) )
def _process_topmost_state(self) -> None: def _process_topmost_state(self): # type: () -> None
""" """
Processes the topmost available RequirementState on the stack. Processes the topmost available RequirementState on the stack.
""" """
...@@ -162,7 +164,7 @@ class Resolution: ...@@ -162,7 +164,7 @@ class Resolution:
self._unwind_for_conflict() self._unwind_for_conflict()
@property @property
def possibility(self) -> PossibilitySet: def possibility(self): # type: () -> PossibilitySet
""" """
The current possibility that the resolution is trying. The current possibility that the resolution is trying.
""" """
...@@ -170,7 +172,7 @@ class Resolution: ...@@ -170,7 +172,7 @@ class Resolution:
return self.state.possibilities[-1] return self.state.possibilities[-1]
@property @property
def state(self) -> DependencyState: def state(self): # type: () -> DependencyState
""" """
The current state the resolution is operating upon. The current state the resolution is operating upon.
""" """
...@@ -178,14 +180,14 @@ class Resolution: ...@@ -178,14 +180,14 @@ class Resolution:
return self._states[-1] return self._states[-1]
@property @property
def name(self) -> str: def name(self): # type: () -> str
return self.state.name return self.state.name
@property @property
def requirement(self) -> Any: def requirement(self): # type: () -> Any
return self.state.requirement return self.state.requirement
def _initial_state(self) -> DependencyState: def _initial_state(self): # type: () -> DependencyState
""" """
Create the initial state for the resolution, based upon the Create the initial state for the resolution, based upon the
requested dependencies. requested dependencies.
...@@ -221,7 +223,7 @@ class Resolution: ...@@ -221,7 +223,7 @@ class Resolution:
[] []
) )
def _unwind_for_conflict(self) -> None: def _unwind_for_conflict(self): # type: () -> None
""" """
Unwinds the states stack because a conflict has been encountered Unwinds the states stack because a conflict has been encountered
""" """
...@@ -260,7 +262,7 @@ class Resolution: ...@@ -260,7 +262,7 @@ class Resolution:
if uw.state_index < index if uw.state_index < index
] ]
def _raise_error_unless_state(self, conflicts) -> None: def _raise_error_unless_state(self, conflicts): # type: (dict) -> None
""" """
Raise a VersionConflict error, or any underlying error, Raise a VersionConflict error, or any underlying error,
if there is no current state if there is no current state
...@@ -278,7 +280,7 @@ class Resolution: ...@@ -278,7 +280,7 @@ class Resolution:
raise error raise error
def _build_details_for_unwind(self) -> UnwindDetails: def _build_details_for_unwind(self): # type: () -> UnwindDetails
""" """
Return the details of the nearest index to which we could unwind. Return the details of the nearest index to which we could unwind.
""" """
...@@ -333,7 +335,8 @@ class Resolution: ...@@ -333,7 +335,8 @@ class Resolution:
return current_detail return current_detail
def _unwind_options_for_requirements(self, binding_requirements): def _unwind_options_for_requirements(self, binding_requirements
): # type: (list) -> List[UnwindDetails]
unwind_details = [] unwind_details = []
trees = [] trees = []
...@@ -504,7 +507,8 @@ class Resolution: ...@@ -504,7 +507,8 @@ class Resolution:
return satisfied return satisfied
def _filter_possibilities_for_parent_unwind(self, def _filter_possibilities_for_parent_unwind(self,
unwind_details: UnwindDetails): unwind_details # type: UnwindDetails
):
""" """
Filter a state's possibilities to remove any that would (eventually) Filter a state's possibilities to remove any that would (eventually)
the requirements in the conflict we've just rewound from. the requirements in the conflict we've just rewound from.
...@@ -619,7 +623,7 @@ class Resolution: ...@@ -619,7 +623,7 @@ class Resolution:
def _binding_requirement_in_set(self, def _binding_requirement_in_set(self,
requirement, requirement,
possible_binding_requirements, possible_binding_requirements,
possibilities) -> bool: possibilities): # type: () -> bool
""" """
Return whether or not the given requirement is required Return whether or not the given requirement is required
to filter out all elements of the list of possibilities. to filter out all elements of the list of possibilities.
......
...@@ -11,22 +11,24 @@ from .resolution import Resolution ...@@ -11,22 +11,24 @@ from .resolution import Resolution
class Resolver: class Resolver:
def __init__(self, def __init__(self,
specification_provider: SpecificationProvider, specification_provider, # type: SpecificationProvider
resolver_ui: UI): resolver_ui # type: UI
):
self._specification_provider = specification_provider self._specification_provider = specification_provider
self._resolver_ui = resolver_ui self._resolver_ui = resolver_ui
@property @property
def specification_provider(self) -> SpecificationProvider: def specification_provider(self): # type: () -> SpecificationProvider
return self._specification_provider return self._specification_provider
@property @property
def ui(self) -> UI: def ui(self): # type: () -> UI
return self._resolver_ui return self._resolver_ui
def resolve(self, def resolve(self,
requested: List[Any], requested, # type: List[Any]
base: Union[DependencyGraph, None] = None) -> DependencyGraph: base=None # type: Union[DependencyGraph, None]
): # type: (...) -> DependencyGraph
if base is None: if base is None:
base = DependencyGraph() base = DependencyGraph()
......
from collections import namedtuple
class UnwindDetails: class UnwindDetails:
def __init__(self, def __init__(self,
......
...@@ -42,7 +42,7 @@ class GenericConstraint(BaseConstraint): ...@@ -42,7 +42,7 @@ class GenericConstraint(BaseConstraint):
self._version = version self._version = version
@property @property
def supported_operators(self) -> list: def supported_operators(self):
return list(self._trans_op_str.keys()) return list(self._trans_op_str.keys())
@property @property
...@@ -54,7 +54,7 @@ class GenericConstraint(BaseConstraint): ...@@ -54,7 +54,7 @@ class GenericConstraint(BaseConstraint):
return self._string_operator return self._string_operator
@property @property
def version(self) -> str: def version(self):
return self._version return self._version
def matches(self, provider): def matches(self, provider):
......
...@@ -9,14 +9,15 @@ from poetry.semver.version_parser import VersionParser ...@@ -9,14 +9,15 @@ from poetry.semver.version_parser import VersionParser
from .constraints.generic_constraint import GenericConstraint from .constraints.generic_constraint import GenericConstraint
class Dependency: class Dependency(object):
def __init__(self, def __init__(self,
name: str, name, # type: str
constraint: str, constraint, # type: str
optional: bool = False, optional=False, # type: bool
category: str = 'main', category='main', # type: str
allows_prereleases: bool = False): allows_prereleases=False # type: bool
):
self._name = name.lower() self._name = name.lower()
self._pretty_name = name self._pretty_name = name
self._parser = VersionParser() self._parser = VersionParser()
...@@ -67,7 +68,7 @@ class Dependency: ...@@ -67,7 +68,7 @@ class Dependency:
return self._python_versions return self._python_versions
@python_versions.setter @python_versions.setter
def python_versions(self, value: str): def python_versions(self, value):
self._python_versions = value self._python_versions = value
self._python_constraint = self._parser.parse_constraints(value) self._python_constraint = self._parser.parse_constraints(value)
...@@ -76,11 +77,11 @@ class Dependency: ...@@ -76,11 +77,11 @@ class Dependency:
return self._python_constraint return self._python_constraint
@property @property
def platform(self) -> str: def platform(self):
return self._platform return self._platform
@platform.setter @platform.setter
def platform(self, value: str): def platform(self, value):
self._platform = value self._platform = value
self._platform_constraint = GenericConstraint.parse(value) self._platform_constraint = GenericConstraint.parse(value)
...@@ -89,11 +90,11 @@ class Dependency: ...@@ -89,11 +90,11 @@ class Dependency:
return self._platform_constraint return self._platform_constraint
@property @property
def extras(self) -> list: def extras(self): # type: () -> list
return self._extras return self._extras
@property @property
def in_extras(self) -> list: def in_extras(self): # type: () -> list
return self._in_extras return self._in_extras
def allows_prereleases(self): def allows_prereleases(self):
...@@ -105,7 +106,7 @@ class Dependency: ...@@ -105,7 +106,7 @@ class Dependency:
def is_vcs(self): def is_vcs(self):
return False return False
def accepts(self, package: 'poetry.packages.Package') -> bool: def accepts(self, package): # type: (poetry.packages.Package) -> bool
""" """
Determines if the given package matches this dependency. Determines if the given package matches this dependency.
""" """
...@@ -115,7 +116,7 @@ class Dependency: ...@@ -115,7 +116,7 @@ class Dependency:
and (not package.is_prerelease() or self.allows_prereleases()) and (not package.is_prerelease() or self.allows_prereleases())
) )
def to_pep_508(self, with_extras=True) -> str: def to_pep_508(self, with_extras=True): # type: (bool) -> str
requirement = self.pretty_name requirement = self.pretty_name
if isinstance(self.constraint, MultiConstraint): if isinstance(self.constraint, MultiConstraint):
......
import json import json
import poetry.packages import poetry.packages
import poetry.repositories
from hashlib import sha256 from hashlib import sha256
from pathlib import Path
from typing import List from typing import List
from poetry.repositories import Repository from poetry.utils._compat import Path
from poetry.utils.toml_file import TomlFile from poetry.utils.toml_file import TomlFile
...@@ -20,14 +20,14 @@ class Locker: ...@@ -20,14 +20,14 @@ class Locker:
'source', 'source',
] ]
def __init__(self, lock: Path, local_config: dict): def __init__(self, lock, local_config): # type: (Path, dict) -> None
self._lock = TomlFile(lock) self._lock = TomlFile(lock)
self._local_config = local_config self._local_config = local_config
self._lock_data = None self._lock_data = None
self._content_hash = self._get_content_hash() self._content_hash = self._get_content_hash()
@property @property
def lock(self) -> TomlFile: def lock(self): # type: () -> TomlFile
return self._lock return self._lock
@property @property
...@@ -37,7 +37,7 @@ class Locker: ...@@ -37,7 +37,7 @@ class Locker:
return self._lock_data return self._lock_data
def is_locked(self) -> bool: def is_locked(self): # type: () -> bool
""" """
Checks whether the locker has been locked (lockfile found). Checks whether the locker has been locked (lockfile found).
""" """
...@@ -46,7 +46,7 @@ class Locker: ...@@ -46,7 +46,7 @@ class Locker:
return 'package' in self.lock_data return 'package' in self.lock_data
def is_fresh(self) -> 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.
""" """
...@@ -58,15 +58,16 @@ class Locker: ...@@ -58,15 +58,16 @@ class Locker:
return False return False
def locked_repository(self, with_dev_reqs: bool = False) -> Repository: def locked_repository(self, with_dev_reqs=False
): # type: (bool) -> poetry.repositories.Repository
""" """
Searches and returns a repository of locked packages. Searches and returns a repository of locked packages.
""" """
if not self.is_locked(): if not self.is_locked():
return Repository() return poetry.repositories.Repository()
lock_data = self.lock_data lock_data = self.lock_data
packages = Repository() packages = poetry.repositories.Repository()
if with_dev_reqs: if with_dev_reqs:
locked_packages = lock_data['package'] locked_packages = lock_data['package']
...@@ -106,7 +107,7 @@ class Locker: ...@@ -106,7 +107,7 @@ class Locker:
return packages return packages
def set_lock_data(self, def set_lock_data(self,
root, packages) -> bool: root, packages): # type: () -> bool
hashes = {} hashes = {}
packages = self._lock_packages(packages) packages = self._lock_packages(packages)
# Retrieving hashes # Retrieving hashes
...@@ -141,7 +142,7 @@ class Locker: ...@@ -141,7 +142,7 @@ class Locker:
self._lock.write(data) self._lock.write(data)
self._lock_data = None self._lock_data = None
def _get_content_hash(self) -> str: def _get_content_hash(self): # type: () -> str
""" """
Returns the sha256 hash of the sorted content of the composer file. Returns the sha256 hash of the sorted content of the composer file.
""" """
...@@ -157,7 +158,7 @@ class Locker: ...@@ -157,7 +158,7 @@ class Locker:
return content_hash return content_hash
def _get_lock_data(self) -> 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'
...@@ -166,7 +167,8 @@ class Locker: ...@@ -166,7 +167,8 @@ class Locker:
return self._lock.read(True) return self._lock.read(True)
def _lock_packages(self, def _lock_packages(self,
packages: List['poetry.packages.Package']) -> list: packages
): # type: (List['poetry.packages.Package']) -> list
locked = [] locked = []
for package in sorted(packages, key=lambda x: x.name): for package in sorted(packages, key=lambda x: x.name):
...@@ -176,7 +178,8 @@ class Locker: ...@@ -176,7 +178,8 @@ class Locker:
return locked return locked
def _dump_package(self, package: 'poetry.packages.Package') -> dict: def _dump_package(self, package
): # 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():
......
# -*- coding: utf-8 -*-
import copy
import re import re
from typing import Union from typing import Union
from poetry.semver.constraints import Constraint from poetry.semver.constraints import Constraint
...@@ -16,7 +19,7 @@ from .vcs_dependency import VCSDependency ...@@ -16,7 +19,7 @@ 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: class Package(object):
AVAILABLE_PYTHONS = { AVAILABLE_PYTHONS = {
'2', '2',
...@@ -138,18 +141,18 @@ class Package: ...@@ -138,18 +141,18 @@ class Package:
return '{} {}'.format(self._pretty_version, self.source_reference) return '{} {}'.format(self._pretty_version, self.source_reference)
@property @property
def authors(self) -> list: def authors(self): # type: () -> list
return self._authors return self._authors
@property @property
def author_name(self) -> str: def author_name(self): # type: () -> str
return self._get_author()['name'] return self._get_author()['name']
@property @property
def author_email(self) -> str: def author_email(self): # type: () -> str
return self._get_author()['email'] return self._get_author()['email']
def _get_author(self) -> dict: def _get_author(self): # type: () -> dict
if not self._authors: if not self._authors:
return { return {
'name': None, 'name': None,
...@@ -171,7 +174,7 @@ class Package: ...@@ -171,7 +174,7 @@ class Package:
return self._python_versions return self._python_versions
@python_versions.setter @python_versions.setter
def python_versions(self, value: str): def python_versions(self, value):
self._python_versions = value self._python_versions = value
self._python_constraint = self._parser.parse_constraints(value) self._python_constraint = self._parser.parse_constraints(value)
...@@ -180,11 +183,11 @@ class Package: ...@@ -180,11 +183,11 @@ class Package:
return self._python_constraint return self._python_constraint
@property @property
def platform(self) -> str: def platform(self): # type: () -> str
return self._platform return self._platform
@platform.setter @platform.setter
def platform(self, value: str): def platform(self, value): # type: (str) -> None
self._platform = value self._platform = value
self._platform_constraint = GenericConstraint.parse(value) self._platform_constraint = GenericConstraint.parse(value)
...@@ -207,7 +210,7 @@ class Package: ...@@ -207,7 +210,7 @@ class Package:
@property @property
def all_classifiers(self): def all_classifiers(self):
classifiers = self.classifiers.copy() classifiers = copy.copy(self.classifiers)
# Automatically set python classifiers # Automatically set python classifiers
parser = VersionParser() parser = VersionParser()
...@@ -241,9 +244,10 @@ class Package: ...@@ -241,9 +244,10 @@ class Package:
return self._stability != 'stable' return self._stability != 'stable'
def add_dependency(self, def add_dependency(self,
name: str, name, # type: str
constraint: Union[str, dict, None] = None, constraint=None, # type: Union[str, dict, None]
category: str = 'main') -> Dependency: category='main' # type: str
): # type: (...) -> Dependency
if constraint is None: if constraint is None:
constraint = '*' constraint = '*'
......
import posixpath import posixpath
import urllib.parse
import urllib.request try:
import urllib.parse as urlparse
except ImportError:
import urlparse
import re import re
from .utils import path_to_url from .utils import path_to_url
...@@ -79,23 +83,23 @@ class Link: ...@@ -79,23 +83,23 @@ class Link:
@property @property
def filename(self): def filename(self):
_, netloc, path, _, _ = urllib.parse.urlsplit(self.url) _, netloc, path, _, _ = urlparse.urlsplit(self.url)
name = posixpath.basename(path.rstrip('/')) or netloc name = posixpath.basename(path.rstrip('/')) or netloc
name = urllib.parse.unquote(name) name = urlparse.unquote(name)
assert name, ('URL %r produced no filename' % self.url) assert name, ('URL %r produced no filename' % self.url)
return name return name
@property @property
def scheme(self): def scheme(self):
return urllib.parse.urlsplit(self.url)[0] return urlparse.urlsplit(self.url)[0]
@property @property
def netloc(self): def netloc(self):
return urllib.parse.urlsplit(self.url)[1] return urlparse.urlsplit(self.url)[1]
@property @property
def path(self): def path(self):
return urllib.parse.unquote(urllib.parse.urlsplit(self.url)[2]) return urlparse.unquote(urlparse.urlsplit(self.url)[2])
def splitext(self): def splitext(self):
return splitext(posixpath.basename(self.path.rstrip('/'))) return splitext(posixpath.basename(self.path.rstrip('/')))
...@@ -106,8 +110,8 @@ class Link: ...@@ -106,8 +110,8 @@ class Link:
@property @property
def url_without_fragment(self): def url_without_fragment(self):
scheme, netloc, path, query, fragment = urllib.parse.urlsplit(self.url) scheme, netloc, path, query, fragment = urlparse.urlsplit(self.url)
return urllib.parse.urlunsplit((scheme, netloc, path, query, None)) return urlparse.urlunsplit((scheme, netloc, path, query, None))
_egg_fragment_re = re.compile(r'[#&]egg=([^&]*)') _egg_fragment_re = re.compile(r'[#&]egg=([^&]*)')
......
import os import os
import posixpath import posixpath
import re import re
import urllib.parse
import urllib.request try:
import urllib.parse as urlparse
except ImportError:
import urlparse
try:
import urllib.request as urllib2
except ImportError:
import urllib2
BZ2_EXTENSIONS = ('.tar.bz2', '.tbz') BZ2_EXTENSIONS = ('.tar.bz2', '.tbz')
...@@ -33,7 +42,7 @@ def path_to_url(path): ...@@ -33,7 +42,7 @@ def path_to_url(path):
quoted path parts. quoted path parts.
""" """
path = os.path.normpath(os.path.abspath(path)) path = os.path.normpath(os.path.abspath(path))
url = urllib.parse.urljoin('file:', urllib.request.pathname2url(path)) url = urlparse.urljoin('file:', urllib2.pathname2url(path))
return url return url
...@@ -116,8 +125,6 @@ def convert_markers(markers): ...@@ -116,8 +125,6 @@ def convert_markers(markers):
requirements = {} requirements = {}
def _group(_groups, or_=False): def _group(_groups, or_=False):
nonlocal requirements
for group in _groups: for group in _groups:
if isinstance(group, tuple): if isinstance(group, tuple):
variable, op, value = group variable, op, value = group
......
...@@ -20,12 +20,12 @@ class VCSDependency(Dependency): ...@@ -20,12 +20,12 @@ class VCSDependency(Dependency):
self._tag = tag self._tag = tag
self._rev = rev self._rev = rev
super().__init__( super(VCSDependency, self).__init__(
name, '*', optional=optional, allows_prereleases=True name, '*', optional=optional, allows_prereleases=True
) )
@property @property
def vcs(self) -> str: def vcs(self):
return self._vcs return self._vcs
@property @property
...@@ -45,11 +45,11 @@ class VCSDependency(Dependency): ...@@ -45,11 +45,11 @@ class VCSDependency(Dependency):
return self._rev return self._rev
@property @property
def reference(self) -> str: def reference(self): # type: () -> str
return self._branch or self._tag or self._rev return self._branch or self._tag or self._rev
@property @property
def pretty_constraint(self) -> str: def pretty_constraint(self): # type: () -> str
if self._branch: if self._branch:
what = 'branch' what = 'branch'
version = self._branch version = self._branch
...@@ -62,7 +62,7 @@ class VCSDependency(Dependency): ...@@ -62,7 +62,7 @@ class VCSDependency(Dependency):
return '{} {}'.format(what, version) return '{} {}'.format(what, version)
def is_vcs(self) -> bool: def is_vcs(self): # type: () -> bool
return True return True
def accepts_prereleases(self): def accepts_prereleases(self):
......
import json from __future__ import absolute_import
from __future__ import unicode_literals
from pathlib import Path import json
import jsonschema import jsonschema
...@@ -12,6 +13,7 @@ from .packages import Package ...@@ -12,6 +13,7 @@ from .packages import Package
from .repositories import Pool from .repositories import Pool
from .repositories.pypi_repository import PyPiRepository from .repositories.pypi_repository import PyPiRepository
from .spdx import license_by_id from .spdx import license_by_id
from .utils._compat import Path
from .utils.toml_file import TomlFile from .utils.toml_file import TomlFile
...@@ -20,10 +22,11 @@ class Poetry: ...@@ -20,10 +22,11 @@ class Poetry:
VERSION = __version__ VERSION = __version__
def __init__(self, def __init__(self,
file: Path, file, # type: Path
config: dict, config, # type: dict
package: Package, package, # type: Package
locker: Locker): locker # type: Locker
):
self._file = TomlFile(file) self._file = TomlFile(file)
self._package = package self._package = package
self._config = config self._config = config
...@@ -42,23 +45,23 @@ class Poetry: ...@@ -42,23 +45,23 @@ class Poetry:
return self._file return self._file
@property @property
def package(self) -> Package: def package(self): # type: () -> Package
return self._package return self._package
@property @property
def config(self) -> dict: def config(self): # type: () -> dict
return self._config return self._config
@property @property
def locker(self) -> Locker: def locker(self): # type: () -> Locker
return self._locker return self._locker
@property @property
def pool(self) -> Pool: def pool(self): # type: () -> Pool
return self._pool return self._pool
@classmethod @classmethod
def create(cls, cwd) -> 'Poetry': def create(cls, cwd): # type: () -> Poetry
poetry_file = Path(cwd) / 'pyproject.toml' poetry_file = Path(cwd) / 'pyproject.toml'
if not poetry_file.exists(): if not poetry_file.exists():
...@@ -138,7 +141,7 @@ class Poetry: ...@@ -138,7 +141,7 @@ class Poetry:
return cls(poetry_file, local_config, package, locker) return cls(poetry_file, local_config, package, locker)
@classmethod @classmethod
def check(cls, config: dict, strict: bool = False): def check(cls, config, strict=False): # type: (dict, bool) -> bool
""" """
Checks the validity of a configuration Checks the validity of a configuration
""" """
......
...@@ -3,7 +3,7 @@ class SolverProblemError(Exception): ...@@ -3,7 +3,7 @@ class SolverProblemError(Exception):
def __init__(self, error): def __init__(self, error):
self._error = error self._error = error
super().__init__(str(error)) super(SolverProblemError, self).__init__(str(error))
@property @property
def error(self): def error(self):
......
...@@ -3,8 +3,8 @@ from .operation import Operation ...@@ -3,8 +3,8 @@ from .operation import Operation
class Install(Operation): class Install(Operation):
def __init__(self, package, reason: str = None) -> None: def __init__(self, package, reason=None):
super().__init__(reason) super(Install, self).__init__(reason)
self._package = package self._package = package
...@@ -16,7 +16,7 @@ class Install(Operation): ...@@ -16,7 +16,7 @@ class Install(Operation):
def job_type(self): def job_type(self):
return 'install' return 'install'
def __str__(self) -> str: def __str__(self):
return 'Installing {} ({})'.format( return 'Installing {} ({})'.format(
self.package.pretty_name, self.package.pretty_name,
self.format_version(self.package) self.format_version(self.package)
......
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from typing import Union
class Operation:
def __init__(self, reason: str = None) -> None: class Operation(object):
def __init__(self, reason=None): # type: (Union[str, None]) -> None
self._reason = reason self._reason = reason
self._skipped = False self._skipped = False
self._skip_reason = None self._skip_reason = None
@property @property
def job_type(self) -> str: def job_type(self): # type: () -> str
raise NotImplementedError raise NotImplementedError
@property @property
def reason(self) -> str: def reason(self): # type: () -> str
return self._reason return self._reason
@property @property
def skipped(self) -> bool: def skipped(self): # type: () -> bool
return self._skipped return self._skipped
@property @property
def skip_reason(self): def skip_reason(self): # type: () -> Union[str, None]
return self._skip_reason return self._skip_reason
def format_version(self, package) -> str: def format_version(self, package): # type: (...) -> str
return package.full_pretty_version return package.full_pretty_version
def skip(self, reason: str) -> 'Operation': def skip(self, reason): # type: (str) -> Operation
self._skipped = True self._skipped = True
self._skip_reason = reason self._skip_reason = reason
......
...@@ -2,7 +2,6 @@ import os ...@@ -2,7 +2,6 @@ import os
import shutil import shutil
from functools import cmp_to_key from functools import cmp_to_key
from pathlib import Path
from tempfile import mkdtemp from tempfile import mkdtemp
from typing import Dict from typing import Dict
from typing import List from typing import List
...@@ -19,6 +18,7 @@ from poetry.repositories import Pool ...@@ -19,6 +18,7 @@ from poetry.repositories import Pool
from poetry.semver import less_than from poetry.semver import less_than
from poetry.utils._compat import Path
from poetry.utils.toml_file import TomlFile from poetry.utils.toml_file import TomlFile
from poetry.utils.venv import Venv from poetry.utils.venv import Venv
...@@ -29,7 +29,11 @@ class Provider(SpecificationProvider): ...@@ -29,7 +29,11 @@ class Provider(SpecificationProvider):
UNSAFE_PACKAGES = {'setuptools', 'distribute', 'pip'} UNSAFE_PACKAGES = {'setuptools', 'distribute', 'pip'}
def __init__(self, package: Package, pool: Pool, io): def __init__(self,
package, # type: Package
pool, # type: Pool
io
):
self._package = package self._package = package
self._pool = pool self._pool = pool
self._io = io self._io = io
...@@ -38,24 +42,24 @@ class Provider(SpecificationProvider): ...@@ -38,24 +42,24 @@ class Provider(SpecificationProvider):
self._search_for = {} self._search_for = {}
@property @property
def pool(self) -> Pool: def pool(self): # type: () -> Pool
return self._pool return self._pool
@property @property
def name_for_explicit_dependency_source(self) -> str: def name_for_explicit_dependency_source(self): # type: () -> str
return 'pyproject.toml' return 'pyproject.toml'
@property @property
def name_for_locking_dependency_source(self) -> str: def name_for_locking_dependency_source(self): # type: () -> str
return 'pyproject.lock' return 'pyproject.lock'
def name_for(self, dependency: Dependency) -> str: def name_for(self, dependency): # type: (Dependency) -> str
""" """
Returns the name for the given dependency. Returns the name for the given dependency.
""" """
return dependency.name return dependency.name
def search_for(self, dependency: Dependency) -> List[Package]: def search_for(self, dependency): # type: (Dependency) -> List[Package]
""" """
Search for the specifications that match the given dependency. Search for the specifications that match the given dependency.
...@@ -86,7 +90,7 @@ class Provider(SpecificationProvider): ...@@ -86,7 +90,7 @@ class Provider(SpecificationProvider):
return self._search_for[dependency] return self._search_for[dependency]
def search_for_vcs(self, dependency: VCSDependency) -> List[Package]: def search_for_vcs(self, dependency): # type: (VCSDependency) -> List[Package]
""" """
Search for the specifications that match the given VCS dependency. Search for the specifications that match the given VCS dependency.
...@@ -171,7 +175,7 @@ class Provider(SpecificationProvider): ...@@ -171,7 +175,7 @@ class Provider(SpecificationProvider):
return [package] return [package]
def dependencies_for(self, package: Package): def dependencies_for(self, package): # type: (Package) -> List[Dependency]
if package.source_type == 'git': if package.source_type == 'git':
# Information should already be set # Information should already be set
pass pass
...@@ -185,9 +189,10 @@ class Provider(SpecificationProvider): ...@@ -185,9 +189,10 @@ class Provider(SpecificationProvider):
] ]
def is_requirement_satisfied_by(self, def is_requirement_satisfied_by(self,
requirement: Dependency, requirement, # type: Dependency
activated: DependencyGraph, activated, # type: DependencyGraph
package: Package) -> bool: package # type: Package
): # type: (...) -> bool
""" """
Determines whether the given requirement is satisfied by the given Determines whether the given requirement is satisfied by the given
spec, in the context of the current activated dependency graph. spec, in the context of the current activated dependency graph.
...@@ -210,9 +215,10 @@ class Provider(SpecificationProvider): ...@@ -210,9 +215,10 @@ class Provider(SpecificationProvider):
) )
def sort_dependencies(self, def sort_dependencies(self,
dependencies: List[Dependency], dependencies, # type: List[Dependency]
activated: DependencyGraph, activated, # type: DependencyGraph
conflicts: Dict[str, List[Conflict]]): conflicts # type: Dict[str, List[Conflict]]
): # type: (...) -> List[Dependency]
return sorted(dependencies, key=lambda d: [ return sorted(dependencies, key=lambda d: [
0 if activated.vertex_named(d.name).payload else 1, 0 if activated.vertex_named(d.name).payload else 1,
0 if activated.vertex_named(d.name).root else 1, 0 if activated.vertex_named(d.name).root else 1,
......
...@@ -25,7 +25,7 @@ class Solver: ...@@ -25,7 +25,7 @@ class Solver:
self._locked = locked self._locked = locked
self._io = io self._io = io
def solve(self, requested, fixed=None) -> List[Operation]: def solve(self, requested, fixed=None): # type: (...) -> List[Operation]
resolver = Resolver( resolver = Resolver(
Provider(self._package, self._pool, self._io), Provider(self._package, self._pool, self._io),
UI(self._io) UI(self._io)
......
...@@ -4,17 +4,17 @@ from poetry.mixology.contracts import UI as BaseUI ...@@ -4,17 +4,17 @@ from poetry.mixology.contracts import UI as BaseUI
class UI(BaseUI): class UI(BaseUI):
def __init__(self, io: CleoStyle): def __init__(self, io): # type: (CleoStyle) -> None
self._io = io self._io = io
self._progress = None self._progress = None
super().__init__(self._io.is_debug()) super(UI, self).__init__(self._io.is_debug())
@property @property
def output(self): def output(self):
return self._io return self._io
def before_resolution(self) -> None: def before_resolution(self):
self._io.write('<info>Resolving dependencies</>') self._io.write('<info>Resolving dependencies</>')
if self.is_debugging(): if self.is_debugging():
...@@ -24,10 +24,10 @@ class UI(BaseUI): ...@@ -24,10 +24,10 @@ class UI(BaseUI):
if not self.is_debugging(): if not self.is_debugging():
self._io.write('.') self._io.write('.')
def after_resolution(self) -> None: def after_resolution(self):
self._io.new_line() self._io.new_line()
def debug(self, message, depth) -> None: def debug(self, message, depth):
if self.is_debugging(): if self.is_debugging():
debug_info = str(message) debug_info = str(message)
debug_info = '\n'.join([ debug_info = '\n'.join([
......
class BaseRepository: class BaseRepository(object):
SEARCH_FULLTEXT = 0 SEARCH_FULLTEXT = 0
SEARCH_NAME = 1 SEARCH_NAME = 1
......
...@@ -7,7 +7,7 @@ from .repository import Repository ...@@ -7,7 +7,7 @@ from .repository import Repository
class InstalledRepository(Repository): class InstalledRepository(Repository):
@classmethod @classmethod
def load(cls, venv: Venv) -> 'InstalledRepository': def load(cls, venv): # type: (Venv) -> InstalledRepository
""" """
Load installed packages. Load installed packages.
......
...@@ -86,7 +86,8 @@ class LegacyRepository(PyPiRepository): ...@@ -86,7 +86,8 @@ class LegacyRepository(PyPiRepository):
return packages return packages
def package(self, name, version, extras=None) -> 'poetry.packages.Package': def package(self, name, version, extras=None
): # type: (...) -> poetry.packages.Package
""" """
Retrieve the release information. Retrieve the release information.
...@@ -148,7 +149,7 @@ class LegacyRepository(PyPiRepository): ...@@ -148,7 +149,7 @@ class LegacyRepository(PyPiRepository):
return package return package
def get_release_info(self, name: str, version: str) -> dict: def get_release_info(self, name, version): # type: (str, str) -> dict
""" """
Return the release information given a package name and a version. Return the release information given a package name and a version.
...@@ -160,7 +161,7 @@ class LegacyRepository(PyPiRepository): ...@@ -160,7 +161,7 @@ class LegacyRepository(PyPiRepository):
lambda: self._get_release_info(name, version) lambda: self._get_release_info(name, version)
) )
def _get_release_info(self, name: str, version: str) -> dict: def _get_release_info(self, name, version): # type: (str, str) -> dict
from pip.req import InstallRequirement from pip.req import InstallRequirement
from pip.exceptions import InstallationError from pip.exceptions import InstallationError
......
...@@ -9,7 +9,7 @@ from .repository import Repository ...@@ -9,7 +9,7 @@ from .repository import Repository
class Pool(BaseRepository): class Pool(BaseRepository):
def __init__(self, repositories: Union[list, None] = None): def __init__(self, repositories=None): # type: (Union[list, None]) -> None
if repositories is None: if repositories is None:
repositories = [] repositories = []
...@@ -18,13 +18,13 @@ class Pool(BaseRepository): ...@@ -18,13 +18,13 @@ class Pool(BaseRepository):
for repository in repositories: for repository in repositories:
self.add_repository(repository) self.add_repository(repository)
super().__init__() super(Pool, self).__init__()
@property @property
def repositories(self) -> List[Repository]: def repositories(self): # type: () -> List[Repository]
return self._repositories return self._repositories
def add_repository(self, repository: Repository) -> 'Pool': def add_repository(self, repository): # type: (Repository) -> Pool
""" """
Adds a repository to the pool. Adds a repository to the pool.
""" """
...@@ -32,7 +32,7 @@ class Pool(BaseRepository): ...@@ -32,7 +32,7 @@ class Pool(BaseRepository):
return self return self
def configure(self, source: dict) -> 'Pool': def configure(self, source): # type: (dict) -> Pool
""" """
Configures a repository based on a source Configures a repository based on a source
specification and add it to the pool. specification and add it to the pool.
......
from pathlib import Path
from typing import List from typing import List
from typing import Union from typing import Union
...@@ -13,6 +12,7 @@ from poetry.packages import Package ...@@ -13,6 +12,7 @@ from poetry.packages import Package
from poetry.semver.constraints import Constraint from poetry.semver.constraints import Constraint
from poetry.semver.constraints.base_constraint import BaseConstraint from poetry.semver.constraints.base_constraint import BaseConstraint
from poetry.semver.version_parser import VersionParser from poetry.semver.version_parser import VersionParser
from poetry.utils._compat import Path
from poetry.version.markers import InvalidMarker from poetry.version.markers import InvalidMarker
from .repository import Repository from .repository import Repository
...@@ -44,13 +44,13 @@ class PyPiRepository(Repository): ...@@ -44,13 +44,13 @@ class PyPiRepository(Repository):
cache=FileCache(str(release_cache_dir / '_packages')) cache=FileCache(str(release_cache_dir / '_packages'))
) )
super().__init__() super(PyPiRepository, self).__init__()
def find_packages(self, def find_packages(self,
name: str, name, # type: str
constraint: Union[Constraint, str, None] = None, constraint=None, # type: Union[Constraint, str, None]
extras: Union[list, None] = None extras=None # type: Union[list, None]
) -> List[Package]: ): # type: (...) -> List[Package]
""" """
Find packages on the remote server. Find packages on the remote server.
""" """
...@@ -79,9 +79,10 @@ class PyPiRepository(Repository): ...@@ -79,9 +79,10 @@ class PyPiRepository(Repository):
return packages return packages
def package(self, def package(self,
name: str, name, # type: str
version: str, version, # type: str
extras: Union[list, None] = None) -> Package: extras=None # type: (Union[list, None])
): # type: (...) -> Package
try: try:
index = self._packages.index(Package(name, version, version)) index = self._packages.index(Package(name, version, version))
...@@ -153,7 +154,7 @@ class PyPiRepository(Repository): ...@@ -153,7 +154,7 @@ class PyPiRepository(Repository):
return results return results
def get_package_info(self, name: str) -> dict: def get_package_info(self, name): # type: (str) -> dict
""" """
Return the package information given its name. Return the package information given its name.
...@@ -168,14 +169,14 @@ class PyPiRepository(Repository): ...@@ -168,14 +169,14 @@ class PyPiRepository(Repository):
lambda: self._get_package_info(name) lambda: self._get_package_info(name)
) )
def _get_package_info(self, name: str) -> dict: def _get_package_info(self, name): # type: (str) -> dict
data = self._get('pypi/{}/json'.format(name)) data = self._get('pypi/{}/json'.format(name))
if data is None: if data is None:
raise ValueError('Package [{}] not found.'.format(name)) raise ValueError('Package [{}] not found.'.format(name))
return data return data
def get_release_info(self, name: str, version: str) -> dict: def get_release_info(self, name, version): # type: (str, str) -> dict
""" """
Return the release information given a package name and a version. Return the release information given a package name and a version.
...@@ -190,7 +191,7 @@ class PyPiRepository(Repository): ...@@ -190,7 +191,7 @@ class PyPiRepository(Repository):
lambda: self._get_release_info(name, version) lambda: self._get_release_info(name, version)
) )
def _get_release_info(self, name: str, version: str) -> dict: def _get_release_info(self, name, version): # type: (str, str) -> dict
json_data = self._get('pypi/{}/{}/json'.format(name, version)) json_data = self._get('pypi/{}/{}/json'.format(name, version))
if json_data is None: if json_data is None:
raise ValueError('Package [{}] not found.'.format(name)) raise ValueError('Package [{}] not found.'.format(name))
...@@ -210,7 +211,7 @@ class PyPiRepository(Repository): ...@@ -210,7 +211,7 @@ class PyPiRepository(Repository):
return data return data
def _get(self, endpoint: str) -> Union[dict, None]: def _get(self, endpoint): # type: (str) -> Union[dict, None]
json_response = self._session.get(self._url + endpoint) json_response = self._session.get(self._url + endpoint)
if json_response.status_code == 404: if json_response.status_code == 404:
return None return None
......
import re
from poetry.semver.constraints import Constraint from poetry.semver.constraints import Constraint
from poetry.semver.constraints.base_constraint import BaseConstraint from poetry.semver.constraints.base_constraint import BaseConstraint
from poetry.semver.version_parser import VersionParser from poetry.semver.version_parser import VersionParser
...@@ -54,33 +52,6 @@ class Repository(BaseRepository): ...@@ -54,33 +52,6 @@ class Repository(BaseRepository):
return packages return packages
def search(self, query, mode=0):
regex = '(?i)(?:{})'.format('|'.join(re.split('\s+', query)))
matches = {}
for package in self.packages:
name = package.name
if name in matches:
continue
if (
re.match(regex, name) is not None
or (
mode == self.SEARCH_FULLTEXT
and isinstance(package, CompletePackage)
and re.match(regex, '')
)
):
matches[name] = {
'name': package.pretty_name,
'description': (package.description
if isinstance(package, CompletePackage)
else '')
}
return list(matches.values())
def has_package(self, package): def has_package(self, package):
package_id = package.unique_name package_id = package.unique_name
......
class BaseConstraint: class BaseConstraint(object):
def matches(self, provider): def matches(self, provider):
raise NotImplementedError() raise NotImplementedError()
...@@ -35,7 +35,7 @@ class Constraint(BaseConstraint): ...@@ -35,7 +35,7 @@ class Constraint(BaseConstraint):
OP_NE: '!=' OP_NE: '!='
} }
def __init__(self, operator: str, version: str): def __init__(self, operator, version): # type: (str, str) -> None
if operator not in self.supported_operators: if operator not in self.supported_operators:
raise ValueError( raise ValueError(
'Invalid operator "{}" given, ' 'Invalid operator "{}" given, '
...@@ -50,7 +50,7 @@ class Constraint(BaseConstraint): ...@@ -50,7 +50,7 @@ class Constraint(BaseConstraint):
self._version = str(parse_version(version)) self._version = str(parse_version(version))
@property @property
def supported_operators(self) -> list: def supported_operators(self): # type: () -> list
return list(self._trans_op_str.keys()) return list(self._trans_op_str.keys())
@property @property
...@@ -62,7 +62,7 @@ class Constraint(BaseConstraint): ...@@ -62,7 +62,7 @@ class Constraint(BaseConstraint):
return self._string_operator return self._string_operator
@property @property
def version(self) -> str: def version(self): # type: () -> str
return self._version return self._version
def matches(self, provider): def matches(self, provider):
...@@ -75,7 +75,8 @@ class Constraint(BaseConstraint): ...@@ -75,7 +75,8 @@ class Constraint(BaseConstraint):
# turn matching around to find a match # turn matching around to find a match
return provider.matches(self) return provider.matches(self)
def version_compare(self, a: str, b: str, operator: str) -> bool: def version_compare(self, a, b, operator
): # type: (str, str, str) -> bool
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, '
...@@ -99,7 +100,7 @@ class Constraint(BaseConstraint): ...@@ -99,7 +100,7 @@ class Constraint(BaseConstraint):
return version_compare(a, b, operator) return version_compare(a, b, operator)
def match_specific(self, provider: 'Constraint') -> bool: def match_specific(self, provider): # type: (Constraint) -> bool
no_equal_op = self._trans_op_int[self._operator].replace('=', '') no_equal_op = self._trans_op_int[self._operator].replace('=', '')
provider_no_equal_op = self._trans_op_int[provider.operator].replace('=', '') provider_no_equal_op = self._trans_op_int[provider.operator].replace('=', '')
......
...@@ -5,7 +5,7 @@ from .constraint import Constraint ...@@ -5,7 +5,7 @@ from .constraint import Constraint
class WilcardConstraint(Constraint): class WilcardConstraint(Constraint):
def __init__(self, constraint: str): 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
...@@ -18,7 +18,7 @@ class WilcardConstraint(Constraint): ...@@ -18,7 +18,7 @@ class WilcardConstraint(Constraint):
else: else:
operator = m.group(1) operator = m.group(1)
super().__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:]])
) )
...@@ -64,7 +64,7 @@ class WilcardConstraint(Constraint): ...@@ -64,7 +64,7 @@ class WilcardConstraint(Constraint):
def constraint(self): def constraint(self):
return self._constraint return self._constraint
def matches(self, provider) -> bool: def matches(self, provider): # type: (Constraint) -> bool
if isinstance(provider, self.__class__): if isinstance(provider, self.__class__):
return self._constraint.matches(provider.constraint) return self._constraint.matches(provider.constraint)
......
...@@ -85,7 +85,7 @@ def normalize_version(version): ...@@ -85,7 +85,7 @@ def normalize_version(version):
raise ValueError('Invalid version string "{}"'.format(version)) raise ValueError('Invalid version string "{}"'.format(version))
def normalize_stability(stability: str) -> str: def normalize_stability(stability): # type: (str) -> str
stability = stability.lower() stability = stability.lower()
if stability == 'rc': if stability == 'rc':
...@@ -94,7 +94,7 @@ def normalize_stability(stability: str) -> str: ...@@ -94,7 +94,7 @@ def normalize_stability(stability: str) -> str:
return stability return stability
def parse_stability(version: str) -> str: def parse_stability(version): # type: (str) -> str
""" """
Returns the stability of a version. Returns the stability of a version.
""" """
...@@ -123,7 +123,7 @@ def parse_stability(version: str) -> str: ...@@ -123,7 +123,7 @@ def parse_stability(version: str) -> str:
return 'stable' return 'stable'
def _expand_stability(stability: str) -> str: def _expand_stability(stability): # type: (str) -> str
stability = stability.lower() stability = stability.lower()
if stability == 'a': if stability == 'a':
......
import re import re
from typing import Tuple
from typing import Union
from .constraints.constraint import Constraint from .constraints.constraint import Constraint
from .constraints.base_constraint import BaseConstraint
from .constraints.empty_constraint import EmptyConstraint from .constraints.empty_constraint import EmptyConstraint
from .constraints.multi_constraint import MultiConstraint from .constraints.multi_constraint import MultiConstraint
from .constraints.wildcard_constraint import WilcardConstraint from .constraints.wildcard_constraint import WilcardConstraint
...@@ -19,7 +23,9 @@ class VersionParser: ...@@ -19,7 +23,9 @@ class VersionParser:
'stable', 'RC', 'beta', 'alpha', 'dev' 'stable', 'RC', 'beta', 'alpha', 'dev'
] ]
def parse_constraints(self, constraints: str): def parse_constraints(
self, constraints
): # type: (str) -> Union[Constraint, MultiConstraint]
""" """
Parses a constraint string into Parses a constraint string into
MultiConstraint and/or Constraint objects. MultiConstraint and/or Constraint objects.
...@@ -88,7 +94,9 @@ class VersionParser: ...@@ -88,7 +94,9 @@ class VersionParser:
return constraint return constraint
def _parse_constraint(self, constraint): def _parse_constraint(
self, constraint
): # type: (str) -> Union[Tuple[BaseConstraint], Tuple[BaseConstraint, BaseConstraint]]
m = re.match('(?i)^v?[xX*](\.[xX*])*$', constraint) m = re.match('(?i)^v?[xX*](\.[xX*])*$', constraint)
if m: if m:
return EmptyConstraint(), return EmptyConstraint(),
......
import json import json
import os import os
from urllib.request import urlopen try:
from urllib.request import urlopen
except ImportError:
from urllib2 import urlopen
class Updater: class Updater:
......
...@@ -2,10 +2,11 @@ ...@@ -2,10 +2,11 @@
""" """
A converter of python values to TOML Token instances. A converter of python values to TOML Token instances.
""" """
import codecs
import datetime import datetime
import re import re
from poetry.utils._compat import basestring
from .. import tokens from .. import tokens
from ..errors import TOMLError from ..errors import TOMLError
from ..tokens import Token from ..tokens import Token
...@@ -47,7 +48,7 @@ def create_primitive_token(value, multiline_strings_allowed=True): ...@@ -47,7 +48,7 @@ def create_primitive_token(value, multiline_strings_allowed=True):
return tokens.Token(tokens.TYPE_FLOAT, u'{}'.format(value)) return tokens.Token(tokens.TYPE_FLOAT, u'{}'.format(value))
elif isinstance(value, (datetime.datetime, datetime.date, datetime.time)): elif isinstance(value, (datetime.datetime, datetime.date, datetime.time)):
return tokens.Token(tokens.TYPE_DATE, value.isoformat()) return tokens.Token(tokens.TYPE_DATE, value.isoformat())
elif isinstance(value, str): elif isinstance(value, basestring):
return create_string_token(value, multiline_strings_allowed=multiline_strings_allowed) return create_string_token(value, multiline_strings_allowed=multiline_strings_allowed)
raise NotPrimitiveError("{} of type {}".format(value, type(value))) raise NotPrimitiveError("{} of type {}".format(value, type(value)))
...@@ -62,7 +63,7 @@ def create_string_token(text, bare_string_allowed=False, multiline_strings_allow ...@@ -62,7 +63,7 @@ def create_string_token(text, bare_string_allowed=False, multiline_strings_allow
Raises ValueError on non-string input. Raises ValueError on non-string input.
""" """
if not isinstance(text, str): if not isinstance(text, basestring):
raise ValueError('Given value must be a string') raise ValueError('Given value must be a string')
if text == '': if text == '':
...@@ -73,7 +74,7 @@ def create_string_token(text, bare_string_allowed=False, multiline_strings_allow ...@@ -73,7 +74,7 @@ def create_string_token(text, bare_string_allowed=False, multiline_strings_allow
# If containing two or more newlines or is longer than 80 characters we'll use the multiline string format # If containing two or more newlines or is longer than 80 characters we'll use the multiline string format
return _create_multiline_string_token(text) return _create_multiline_string_token(text)
else: else:
return tokens.Token(tokens.TYPE_STRING, '"{}"'.format(_escape_single_line_quoted_string(text))) return tokens.Token(tokens.TYPE_STRING, u'"{}"'.format(_escape_single_line_quoted_string(text)))
def _escape_single_line_quoted_string(text): def _escape_single_line_quoted_string(text):
...@@ -121,6 +122,6 @@ def create_whitespace(source_substring): ...@@ -121,6 +122,6 @@ def create_whitespace(source_substring):
def create_multiline_string(text, maximum_line_length=120): def create_multiline_string(text, maximum_line_length=120):
def escape(t): def escape(t):
return t.replace('"""', '\"\"\"') return t.replace(u'"""', u'\"\"\"')
source_substring = '"""\n{}"""'.format('\\\n'.join(chunkate_string(escape(text), maximum_line_length))) source_substring = u'"""\n{}"""'.format(u'\\\n'.join(chunkate_string(escape(text), maximum_line_length)))
return Token(tokens.TYPE_MULTILINE_STRING, source_substring) return Token(tokens.TYPE_MULTILINE_STRING, source_substring)
import sys import sys
try:
import pathlib2
from pathlib2 import Path
except ImportError:
from pathlib import Path
try: # Python 2
long = long
unicode = unicode
basestring = basestring
except NameError: # Python 3
long = int
unicode = str
basestring = str
PY2 = sys.version_info[0] == 2
PY36 = sys.version_info >= (3, 6) PY36 = sys.version_info >= (3, 6)
def decode(string, encodings=None):
if not PY2 and not isinstance(string, bytes):
return string
if PY2 and isinstance(string, unicode):
return string
encodings = encodings or ['utf-8', 'latin1', 'ascii']
for encoding in encodings:
try:
return string.decode(encoding)
except (UnicodeEncodeError, UnicodeDecodeError):
pass
return string.decode(encodings[0], errors='ignore')
def encode(string, encodings=None):
if not PY2 and isinstance(string, bytes):
return string
if PY2 and isinstance(string, str):
return string
encodings = encodings or ['utf-8', 'latin1', 'ascii']
for encoding in encodings:
try:
return string.encode(encoding)
except (UnicodeEncodeError, UnicodeDecodeError):
pass
return string.encode(encodings[0], errors='ignore')
...@@ -3,9 +3,9 @@ import re ...@@ -3,9 +3,9 @@ import re
_canonicalize_regex = re.compile('[-_.]+') _canonicalize_regex = re.compile('[-_.]+')
def canonicalize_name(name: str) -> str: def canonicalize_name(name): # type: (str) -> str
return _canonicalize_regex.sub('-', name).lower() return _canonicalize_regex.sub('-', name).lower()
def module_name(name: str) -> str: def module_name(name): # type: (str) -> str
return canonicalize_name(name).replace('-', '_') return canonicalize_name(name).replace('-', '_')
# -*- coding: utf-8 -*-
import toml import toml
from pathlib import Path
from poetry.toml import dumps from poetry.toml import dumps
from poetry.toml import loads from poetry.toml import loads
from poetry.toml import TOMLFile from poetry.toml import TOMLFile
from ._compat import Path
class TomlFile: class TomlFile:
...@@ -16,14 +17,14 @@ class TomlFile: ...@@ -16,14 +17,14 @@ class TomlFile:
def path(self): def path(self):
return self._path return self._path
def read(self, raw=False) -> dict: def read(self, raw=False): # type: (bool) -> dict
with self._path.open() as f: with self._path.open() as f:
if raw: if raw:
return toml.loads(f.read()) return toml.loads(f.read())
return loads(f.read()) return loads(f.read())
def write(self, data) -> None: def write(self, data): # type: (...) -> None
if not isinstance(data, TOMLFile): if not isinstance(data, TOMLFile):
data = toml.dumps(data) data = toml.dumps(data)
else: else:
......
...@@ -6,13 +6,12 @@ import sysconfig ...@@ -6,13 +6,12 @@ import sysconfig
import warnings import warnings
from contextlib import contextmanager from contextlib import contextmanager
from pathlib import Path
from subprocess import CalledProcessError from subprocess import CalledProcessError
from venv import EnvBuilder
from poetry.config import Config from poetry.config import Config
from poetry.locations import CACHE_DIR from poetry.locations import CACHE_DIR
from poetry.utils._compat import Path
from poetry.utils._compat import decode
class VenvError(Exception): class VenvError(Exception):
...@@ -22,15 +21,15 @@ class VenvError(Exception): ...@@ -22,15 +21,15 @@ class VenvError(Exception):
class VenvCommandError(VenvError): class VenvCommandError(VenvError):
def __init__(self, e: CalledProcessError): def __init__(self, e): # type: (CalledProcessError) -> None
message = 'Command {} errored with the following output: \n{}'.format( message = 'Command {} errored with the following output: \n{}'.format(
e.cmd, e.output.decode() e.cmd, e.output.decode()
) )
super().__init__(message) super(VenvCommandError, self).__init__(message)
class Venv: class Venv(object):
def __init__(self, venv=None): def __init__(self, venv=None):
self._venv = venv self._venv = venv
...@@ -48,7 +47,7 @@ class Venv: ...@@ -48,7 +47,7 @@ class Venv:
self._python_implementation = None self._python_implementation = None
@classmethod @classmethod
def create(cls, io, name=None) -> 'Venv': def create(cls, io, name=None): # type: (...) -> Venv
if 'VIRTUAL_ENV' not in os.environ: if 'VIRTUAL_ENV' not in os.environ:
# Not in a virtualenv # Not in a virtualenv
# Checking if we need to create one # Checking if we need to create one
...@@ -86,8 +85,8 @@ class Venv: ...@@ -86,8 +85,8 @@ class Venv:
name, str(venv_path) name, str(venv_path)
) )
) )
builder = EnvBuilder(with_pip=True)
builder.create(str(venv)) cls.build(str(venv))
else: else:
if io.is_very_verbose(): if io.is_very_verbose():
io.writeln( io.writeln(
...@@ -117,26 +116,41 @@ class Venv: ...@@ -117,26 +116,41 @@ class Venv:
return cls(venv) return cls(venv)
@classmethod
def build(cls, path):
try:
from venv import EnvBuilder
builder = EnvBuilder(with_pip=True)
build = builder.create
except ImportError:
# We fallback on virtualenv for Python 2.7
from virtualenv import create_environment
build = create_environment
build(path)
@property @property
def venv(self): def venv(self):
return self._venv return self._venv
@property @property
def python(self) -> str: def python(self): # type: () -> str
""" """
Path to current python executable Path to current python executable
""" """
return self._bin('python') return self._bin('python')
@property @property
def pip(self) -> str: def pip(self): # type: () -> str
""" """
Path to current pip executable Path to current pip executable
""" """
return self._bin('pip') return self._bin('pip')
@property @property
def version_info(self) -> tuple: def version_info(self): # type: () -> tuple
if self._version_info is not None: if self._version_info is not None:
return self._version_info return self._version_info
...@@ -201,7 +215,7 @@ class Venv: ...@@ -201,7 +215,7 @@ class Venv:
return value return value
def run(self, bin: str, *args, **kwargs): def run(self, bin, *args, **kwargs):
""" """
Run a command inside the virtual env. Run a command inside the virtual env.
""" """
...@@ -248,9 +262,9 @@ class Venv: ...@@ -248,9 +262,9 @@ class Venv:
except CalledProcessError as e: except CalledProcessError as e:
raise VenvCommandError(e) raise VenvCommandError(e)
return output.decode() return decode(output)
def exec(self, bin, *args, **kwargs): def execute(self, bin, *args, **kwargs):
if not self.is_venv(): if not self.is_venv():
return subprocess.call([bin] + list(args)) return subprocess.call([bin] + list(args))
else: else:
...@@ -287,7 +301,7 @@ class Venv: ...@@ -287,7 +301,7 @@ class Venv:
if shell in ('bash', 'zsh', 'fish'): if shell in ('bash', 'zsh', 'fish'):
return shell return shell
def _bin(self, bin) -> str: def _bin(self, bin): # type: (str) -> str
""" """
Return path to the given executable. Return path to the given executable.
""" """
...@@ -296,23 +310,23 @@ class Venv: ...@@ -296,23 +310,23 @@ class Venv:
return str(self._bin_dir / bin) + ('.exe' if self._windows else '') return str(self._bin_dir / bin) + ('.exe' if self._windows else '')
def is_venv(self) -> bool: def is_venv(self): # type: () -> bool
return self._venv is not None return self._venv is not None
class NullVenv(Venv): class NullVenv(Venv):
def __init__(self, execute=False): def __init__(self, execute=False):
super().__init__() super(NullVenv, self).__init__()
self.executed = [] self.executed = []
self._execute = execute self._execute = execute
def run(self, bin: str, *args): def run(self, bin, *args):
self.executed.append([bin] + list(args)) self.executed.append([bin] + list(args))
if self._execute: if self._execute:
return super().run(bin, *args) return super(NullVenv, self).run(bin, *args)
def _bin(self, bin): def _bin(self, bin):
return bin return bin
from pathlib import Path from poetry.utils._compat import Path
from .git import Git from .git import Git
def get_vcs(directory: Path): def get_vcs(directory): # type: (Path) -> Git
directory = directory.resolve() directory = directory.resolve()
for p in [directory] + list(directory.parents): for p in [directory] + list(directory.parents):
......
# -*- coding: utf-8 -*-
import re import re
import subprocess import subprocess
from poetry.utils._compat import decode
class GitConfig: class GitConfig:
def __init__(self): def __init__(self):
config_list = subprocess.check_output( config_list = decode(subprocess.check_output(
['git', 'config', '-l'], ['git', 'config', '-l'],
stderr=subprocess.STDOUT stderr=subprocess.STDOUT
).decode() ))
self._config = {} self._config = {}
...@@ -31,13 +35,13 @@ class Git: ...@@ -31,13 +35,13 @@ class Git:
self._work_dir = work_dir self._work_dir = work_dir
@property @property
def config(self) -> GitConfig: def config(self): # type: () -> GitConfig
return self._config return self._config
def clone(self, repository, dest) -> str: def clone(self, repository, dest): # type: (...) -> str
return self.run('clone', repository, dest) return self.run('clone', repository, dest)
def checkout(self, rev, folder=None) -> str: def checkout(self, rev, folder=None): # type: (...) -> str
args = [] args = []
if folder is None and self._work_dir: if folder is None and self._work_dir:
folder = self._work_dir folder = self._work_dir
...@@ -54,7 +58,7 @@ class Git: ...@@ -54,7 +58,7 @@ class Git:
return self.run(*args) return self.run(*args)
def rev_parse(self, rev, folder=None) -> str: def rev_parse(self, rev, folder=None): # type: (...) -> str
args = [] args = []
if folder is None and self._work_dir: if folder is None and self._work_dir:
folder = self._work_dir folder = self._work_dir
...@@ -71,7 +75,7 @@ class Git: ...@@ -71,7 +75,7 @@ class Git:
return self.run(*args) return self.run(*args)
def get_ignored_files(self, folder=None) -> list: def get_ignored_files(self, folder=None): # type: (...) -> list
args = [] args = []
if folder is None and self._work_dir: if folder is None and self._work_dir:
folder = self._work_dir folder = self._work_dir
...@@ -89,8 +93,8 @@ class Git: ...@@ -89,8 +93,8 @@ class Git:
return output.split('\n') return output.split('\n')
def run(self, *args) -> str: def run(self, *args): # type: (...) -> str
return subprocess.check_output( return decode(subprocess.check_output(
['git'] + list(args), ['git'] + list(args),
stderr=subprocess.STDOUT stderr=subprocess.STDOUT
).decode() ))
...@@ -25,7 +25,9 @@ _trans_op = { ...@@ -25,7 +25,9 @@ _trans_op = {
} }
def parse(version: str, strict: bool = False) -> Union[Version, LegacyVersion]: def parse(version, # type: str
strict=False # type: bool
): # type:(...) -> Union[Version, LegacyVersion]
""" """
Parse the given version string and return either a :class:`Version` object Parse the given version string and return either a :class:`Version` object
or a LegacyVersion object depending on if the given version is or a LegacyVersion object depending on if the given version is
...@@ -42,7 +44,8 @@ def parse(version: str, strict: bool = False) -> Union[Version, LegacyVersion]: ...@@ -42,7 +44,8 @@ def parse(version: str, strict: bool = False) -> Union[Version, LegacyVersion]:
return LegacyVersion(version) return LegacyVersion(version)
def version_compare(version1: str, version2: str, operator) -> bool: def version_compare(version1, version2, operator
): # type: (str, str, str) -> bool
if operator in _trans_op: if operator in _trans_op:
operator = _trans_op[operator] operator = _trans_op[operator]
elif operator in _trans_op.values(): elif operator in _trans_op.values():
......
...@@ -5,7 +5,11 @@ from __future__ import absolute_import, division, print_function ...@@ -5,7 +5,11 @@ from __future__ import absolute_import, division, print_function
import string import string
import re import re
import urllib.parse as urlparse
try:
import urllib.parse as urlparse
except ImportError:
from urlparse import urlparse
from pyparsing import ( from pyparsing import (
stringStart, stringEnd, originalTextFor, ParseException stringStart, stringEnd, originalTextFor, ParseException
......
...@@ -14,9 +14,9 @@ class VersionSelector(object): ...@@ -14,9 +14,9 @@ class VersionSelector(object):
self._parser = parser self._parser = parser
def find_best_candidate(self, def find_best_candidate(self,
package_name: str, package_name, # type: str
target_package_version: Union[str, None] = None target_package_version=None # type: Union[str, None]
) -> Union[Package, bool]: ): # type: (...) -> Union[Package, bool]
""" """
Given a package name and optional version, Given a package name and optional version,
returns the latest Package that matches returns the latest Package that matches
......
[tool.poetry] [tool.poetry]
name = "poetry" name = "poetry"
version = "0.7.1" version = "0.8.0a0"
description = "Python dependency management and packaging made easy." description = "Python dependency management and packaging made easy."
authors = [ authors = [
"Sébastien Eustace <sebastien@eustace.io>" "Sébastien Eustace <sebastien@eustace.io>"
...@@ -22,7 +22,7 @@ classifiers = [ ...@@ -22,7 +22,7 @@ classifiers = [
# Requirements # Requirements
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.4" python = "~2.7 || ^3.4"
cleo = "^0.6" cleo = "^0.6"
requests = "^2.18" requests = "^2.18"
toml = "^0.9" toml = "^0.9"
...@@ -37,8 +37,12 @@ cachecontrol = { version = "^0.12.4", extras = ["filecache"] } ...@@ -37,8 +37,12 @@ cachecontrol = { version = "^0.12.4", extras = ["filecache"] }
# zipfile36 is needed for Python 3.4 and 3.5 # zipfile36 is needed for Python 3.4 and 3.5
zipfile36 = { version = "^0.1", python = ">=3.4 <3.6" } zipfile36 = { version = "^0.1", python = ">=3.4 <3.6" }
# The typing module is not in the stdlib in Python 3.4 # The typing module is not in the stdlib in Python 2.7 and 3.4
typing = { version = "^3.6", python = "~3.4" } typing = { version = "^3.6", python = "~2.7 || ~3.4" }
# Use pathlib2 and virtualenv for Python 2.7
pathlib2 = { version = "^2.3", python = "~2.7" }
virtualenv = { version = "^15.2", python = "~2.7" }
# cachecontrol dependencies are badly set # cachecontrol dependencies are badly set
# and do not appear in PyPI JSON API # and do not appear in PyPI JSON API
......
...@@ -17,7 +17,7 @@ python-versions = "*" ...@@ -17,7 +17,7 @@ python-versions = "*"
platform = "*" platform = "*"
[package.requirements] [package.requirements]
python = ">= 2.7.0.0, < 2.8.0.0" python = ">= 2.4.0.0, < 2.5.0.0"
[[package]] [[package]]
name = "C" name = "C"
...@@ -32,7 +32,7 @@ platform = "*" ...@@ -32,7 +32,7 @@ platform = "*"
D = "^1.2" D = "^1.2"
[package.requirements] [package.requirements]
python = ">= 3.6.0.0, < 4.0.0.0" python = ">= 2.7.0.0, < 2.8.0.0 || >= 3.6.0.0, < 4.0.0.0"
[[package]] [[package]]
name = "D" name = "D"
...@@ -44,7 +44,7 @@ python-versions = "*" ...@@ -44,7 +44,7 @@ python-versions = "*"
platform = "*" platform = "*"
[package.requirements] [package.requirements]
python = ">= 3.6.0.0, < 4.0.0.0" python = ">= 2.7.0.0, < 2.8.0.0 || >= 3.6.0.0, < 4.0.0.0"
[metadata] [metadata]
python-versions = "~2.7 || ^3.4" python-versions = "~2.7 || ^3.4"
......
...@@ -17,7 +17,7 @@ python-versions = "*" ...@@ -17,7 +17,7 @@ python-versions = "*"
platform = "*" platform = "*"
[package.requirements] [package.requirements]
platform = "win32" platform = "custom"
[[package]] [[package]]
name = "C" name = "C"
......
...@@ -22,11 +22,11 @@ version = "1.2" ...@@ -22,11 +22,11 @@ version = "1.2"
description = "" description = ""
category = "main" category = "main"
optional = false optional = false
python-versions = "^3.6" python-versions = "~2.7 || ^3.6"
platform = "*" platform = "*"
[metadata] [metadata]
python-versions = "^3.4" python-versions = "~2.7 || ^3.4"
platform = "*" platform = "*"
content-hash = "123456789" content-hash = "123456789"
......
from __future__ import unicode_literals
import pytest import pytest
import toml import toml
import sys
from pathlib import Path
from poetry.installation import Installer as BaseInstaller from poetry.installation import Installer as BaseInstaller
from poetry.installation.noop_installer import NoopInstaller from poetry.installation.noop_installer import NoopInstaller
...@@ -11,6 +10,8 @@ from poetry.packages import Locker as BaseLocker ...@@ -11,6 +10,8 @@ from poetry.packages import Locker as BaseLocker
from poetry.repositories import Pool from poetry.repositories import Pool
from poetry.repositories import Repository from poetry.repositories import Repository
from poetry.repositories.installed_repository import InstalledRepository from poetry.repositories.installed_repository import InstalledRepository
from poetry.utils._compat import Path
from poetry.utils._compat import PY2
from poetry.utils.venv import NullVenv from poetry.utils.venv import NullVenv
from tests.helpers import get_dependency from tests.helpers import get_dependency
...@@ -23,6 +24,13 @@ class Installer(BaseInstaller): ...@@ -23,6 +24,13 @@ class Installer(BaseInstaller):
return NoopInstaller() return NoopInstaller()
class CustomInstalledRepository(InstalledRepository):
@classmethod
def load(cls, venv):
return cls()
class Locker(BaseLocker): class Locker(BaseLocker):
def __init__(self): def __init__(self):
...@@ -34,48 +42,45 @@ class Locker(BaseLocker): ...@@ -34,48 +42,45 @@ class Locker(BaseLocker):
def written_data(self): def written_data(self):
return self._written_data return self._written_data
def locked(self, is_locked=True) -> 'Locker': def locked(self, is_locked=True):
self._locked = is_locked self._locked = is_locked
return self return self
def mock_lock_data(self, data) -> None: def mock_lock_data(self, data):
self._lock_data = data self._lock_data = data
def is_locked(self) -> bool: def is_locked(self):
return self._locked return self._locked
def is_fresh(self) -> bool: def is_fresh(self):
return True return True
def _get_content_hash(self) -> str: def _get_content_hash(self):
return '123456789' return '123456789'
def _write_lock_data(self, data) -> None: def _write_lock_data(self, data):
for package in data['package']: for package in data['package']:
package['python-versions'] = str(package['python-versions']) python_versions = str(package['python-versions'])
package['platform'] = str(package['platform']) platform = str(package['platform'])
if PY2:
python_versions = python_versions.decode()
platform = platform.decode()
if 'requirements' in package:
requirements = {}
for key, value in package['requirements'].items():
requirements[key.decode()] = value.decode()
package['requirements'] = requirements
package['python-versions'] = python_versions
package['platform'] = platform
if not package['dependencies']: if not package['dependencies']:
del package['dependencies'] del package['dependencies']
self._written_data = data self._written_data = data
@pytest.fixture(autouse=True)
def setup():
# Mock python version and platform to get reliable tests
original = sys.version_info
original_platform = sys.platform
sys.version_info = (3, 6, 3, 'final', 0)
sys.platform = 'darwin'
yield
sys.version_info = original
sys.platform = original_platform
@pytest.fixture() @pytest.fixture()
def package(): def package():
return get_package('root', '1.0') return get_package('root', '1.0')
...@@ -96,12 +101,7 @@ def pool(repo): ...@@ -96,12 +101,7 @@ def pool(repo):
@pytest.fixture() @pytest.fixture()
def installed(): def installed():
original = InstalledRepository.load return CustomInstalledRepository()
InstalledRepository.load = lambda _: InstalledRepository()
yield
InstalledRepository.load = original
@pytest.fixture() @pytest.fixture()
...@@ -257,12 +257,12 @@ def test_add_with_sub_dependencies(installer, locker, repo, package): ...@@ -257,12 +257,12 @@ def test_add_with_sub_dependencies(installer, locker, repo, package):
def test_run_with_python_versions(installer, locker, repo, package): def test_run_with_python_versions(installer, locker, repo, package):
package.python_versions = '^3.4' package.python_versions = '~2.7 || ^3.4'
package_a = get_package('A', '1.0') package_a = get_package('A', '1.0')
package_b = get_package('B', '1.1') package_b = get_package('B', '1.1')
package_c12 = get_package('C', '1.2') package_c12 = get_package('C', '1.2')
package_c12.python_versions = '^3.6' package_c12.python_versions = '~2.7 || ^3.6'
package_c13 = get_package('C', '1.3') package_c13 = get_package('C', '1.3')
package_c13.python_versions = '~3.3' package_c13.python_versions = '~3.3'
...@@ -298,17 +298,20 @@ def test_run_with_optional_and_python_restricted_dependencies(installer, locker, ...@@ -298,17 +298,20 @@ def test_run_with_optional_and_python_restricted_dependencies(installer, locker,
repo.add_package(package_d) repo.add_package(package_d)
package.add_dependency('A', {'version': '~1.0', 'optional': True}) package.add_dependency('A', {'version': '~1.0', 'optional': True})
package.add_dependency('B', {'version': '^1.0', 'python': '~2.7'}) package.add_dependency('B', {'version': '^1.0', 'python': '~2.4'})
package.add_dependency('C', {'version': '^1.0', 'python': '^3.6'}) package.add_dependency('C', {'version': '^1.0', 'python': '~2.7 || ^3.6'})
installer.run() installer.run()
expected = fixture('with-optional-dependencies') expected = fixture('with-optional-dependencies')
import json
print(json.dumps(locker.written_data, indent=2, sort_keys=True))
print(json.dumps(expected, indent=2, sort_keys=True))
assert locker.written_data == expected assert locker.written_data == expected
installer = installer.installer installer = installer.installer
# We should only have 2 installs: # We should only have 2 installs:
# C,D since the mocked python version is not compatible # C,D since python version is not compatible
# with B's python constraint and A is optional # with B's python constraint and A is optional
assert len(installer.installs) == 2 assert len(installer.installs) == 2
assert installer.installs[0].name == 'd' assert installer.installs[0].name == 'd'
...@@ -330,7 +333,7 @@ def test_run_with_optional_and_platform_restricted_dependencies(installer, locke ...@@ -330,7 +333,7 @@ def test_run_with_optional_and_platform_restricted_dependencies(installer, locke
repo.add_package(package_d) repo.add_package(package_d)
package.add_dependency('A', {'version': '~1.0', 'optional': True}) package.add_dependency('A', {'version': '~1.0', 'optional': True})
package.add_dependency('B', {'version': '^1.0', 'platform': 'win32'}) package.add_dependency('B', {'version': '^1.0', 'platform': 'custom'})
package.add_dependency('C', {'version': '^1.0', 'platform': 'darwin'}) package.add_dependency('C', {'version': '^1.0', 'platform': 'darwin'})
installer.run() installer.run()
......
...@@ -16,7 +16,7 @@ static PyMethodDef module_methods[] = { ...@@ -16,7 +16,7 @@ static PyMethodDef module_methods[] = {
{NULL} {NULL}
}; };
#if PY_MAJOR_VERSION >= 3
static struct PyModuleDef moduledef = { static struct PyModuleDef moduledef = {
PyModuleDef_HEAD_INIT, PyModuleDef_HEAD_INIT,
"extended", "extended",
...@@ -28,17 +28,31 @@ static struct PyModuleDef moduledef = { ...@@ -28,17 +28,31 @@ static struct PyModuleDef moduledef = {
NULL, NULL,
NULL, NULL,
}; };
#endif
PyMODINIT_FUNC PyMODINIT_FUNC
#if PY_MAJOR_VERSION >= 3
PyInit_extended(void) PyInit_extended(void)
#else
init_extended(void)
#endif
{ {
PyObject *module; PyObject *module;
#if PY_MAJOR_VERSION >= 3
module = PyModule_Create(&moduledef); module = PyModule_Create(&moduledef);
#else
module = Py_InitModule3("extended", module_methods, NULL);
#endif
if (module == NULL) if (module == NULL)
#if PY_MAJOR_VERSION >= 3
return NULL; return NULL;
#else
return;
#endif
#if PY_MAJOR_VERSION >= 3
return module; return module;
#endif
} }
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import pytest import pytest
import re import re
import shutil import shutil
import tarfile import tarfile
import zipfile import zipfile
from pathlib import Path
from poetry import __version__ from poetry import __version__
from poetry.io import NullIO from poetry.io import NullIO
from poetry.masonry.builders import CompleteBuilder from poetry.masonry.builders import CompleteBuilder
from poetry.poetry import Poetry from poetry.poetry import Poetry
from poetry.utils._compat import Path
from poetry.utils._compat import decode
from poetry.utils.venv import NullVenv from poetry.utils.venv import NullVenv
fixtures_dir = Path(__file__).parent / 'fixtures' fixtures_dir = Path(__file__).parent / 'fixtures'
...@@ -44,7 +47,7 @@ def test_wheel_c_extension(): ...@@ -44,7 +47,7 @@ def test_wheel_c_extension():
assert 'extended-0.1/build.py' in tar.getnames() assert 'extended-0.1/build.py' in tar.getnames()
assert 'extended-0.1/extended/extended.c' in tar.getnames() assert 'extended-0.1/extended/extended.c' in tar.getnames()
whl = list((module_path / 'dist').glob('extended-0.1-cp3*-cp3*m-*.whl'))[0] whl = list((module_path / 'dist').glob('extended-0.1-cp*-cp*m-*.whl'))[0]
assert whl.exists() assert whl.exists()
...@@ -58,13 +61,13 @@ def test_wheel_c_extension(): ...@@ -58,13 +61,13 @@ def test_wheel_c_extension():
assert has_compiled_extension assert has_compiled_extension
try: try:
wheel_data = zip.read('extended-0.1.dist-info/WHEEL').decode() wheel_data = decode(zip.read('extended-0.1.dist-info/WHEEL'))
assert re.match("""(?m)^\ assert re.match("""(?m)^\
Wheel-Version: 1.0 Wheel-Version: 1.0
Generator: poetry {} Generator: poetry {}
Root-Is-Purelib: false Root-Is-Purelib: false
Tag: cp3\d-cp3\dm-.+ Tag: cp[23]\d-cp[23]\dm-.+
$""".format(__version__), wheel_data) is not None $""".format(__version__), wheel_data) is not None
finally: finally:
zip.close() zip.close()
...@@ -85,13 +88,13 @@ def test_complete(): ...@@ -85,13 +88,13 @@ def test_complete():
try: try:
entry_points = zip.read('my_package-1.2.3.dist-info/entry_points.txt') entry_points = zip.read('my_package-1.2.3.dist-info/entry_points.txt')
assert entry_points.decode() == """\ assert decode(entry_points.decode()) == """\
[console_scripts] [console_scripts]
my-2nd-script=my_package:main2 my-2nd-script=my_package:main2
my-script=my_package:main my-script=my_package:main
""" """
wheel_data = zip.read('my_package-1.2.3.dist-info/WHEEL').decode() wheel_data = decode(zip.read('my_package-1.2.3.dist-info/WHEEL'))
assert wheel_data == """\ assert wheel_data == """\
Wheel-Version: 1.0 Wheel-Version: 1.0
...@@ -99,7 +102,7 @@ Generator: poetry {} ...@@ -99,7 +102,7 @@ Generator: poetry {}
Root-Is-Purelib: true Root-Is-Purelib: true
Tag: py3-none-any Tag: py3-none-any
""".format(__version__) """.format(__version__)
wheel_data = zip.read('my_package-1.2.3.dist-info/METADATA').decode() wheel_data = decode(zip.read('my_package-1.2.3.dist-info/METADATA'))
assert wheel_data == """\ assert wheel_data == """\
Metadata-Version: 2.1 Metadata-Version: 2.1
......
...@@ -3,12 +3,11 @@ import pytest ...@@ -3,12 +3,11 @@ import pytest
import shutil import shutil
import tarfile import tarfile
from pathlib import Path
from poetry.io import NullIO from poetry.io import NullIO
from poetry.masonry.builders.sdist import SdistBuilder from poetry.masonry.builders.sdist import SdistBuilder
from poetry.packages import Package from poetry.packages import Package
from poetry.poetry import Poetry from poetry.poetry import Poetry
from poetry.utils._compat import Path
from poetry.utils.venv import NullVenv from poetry.utils.venv import NullVenv
from tests.helpers import get_dependency from tests.helpers import get_dependency
......
import pytest import pytest
import shutil import shutil
from pathlib import Path
from poetry.io import NullIO from poetry.io import NullIO
from poetry.masonry.builders import WheelBuilder from poetry.masonry.builders import WheelBuilder
from poetry.poetry import Poetry from poetry.poetry import Poetry
from poetry.utils._compat import Path
from poetry.utils.venv import NullVenv from poetry.utils.venv import NullVenv
......
import json import json
from pathlib import Path
from poetry.repositories.pypi_repository import PyPiRepository from poetry.repositories.pypi_repository import PyPiRepository
from poetry.utils._compat import Path
class MockRepository(PyPiRepository): class MockRepository(PyPiRepository):
...@@ -10,9 +9,12 @@ class MockRepository(PyPiRepository): ...@@ -10,9 +9,12 @@ class MockRepository(PyPiRepository):
FIXTURES = Path(__file__).parent / 'fixtures' / 'pypi.org' / 'json' FIXTURES = Path(__file__).parent / 'fixtures' / 'pypi.org' / 'json'
def __init__(self): def __init__(self):
super().__init__(url='http://foo.bar', disable_cache=True) super(MockRepository, self).__init__(
url='http://foo.bar',
disable_cache=True
)
def _get(self, url: str) -> dict: def _get(self, url):
fixture = self.FIXTURES / 'requests.json' fixture = self.FIXTURES / 'requests.json'
with fixture.open() as f: with fixture.open() as f:
......
import toml # -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import unicode_literals
from pathlib import Path import toml
from poetry.poetry import Poetry from poetry.poetry import Poetry
from poetry.utils._compat import Path
fixtures_dir = Path(__file__).parent / 'fixtures' fixtures_dir = Path(__file__).parent / 'fixtures'
......
# -*- coding: utf-8 -*-
from poetry.toml import dumps from poetry.toml import dumps
from poetry.toml import loads from poetry.toml import loads
......
import pytest import pytest
from pathlib import Path from poetry.utils._compat import Path
from poetry.utils.toml_file import TomlFile from poetry.utils.toml_file import TomlFile
......
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