Skip to content

Commit

Permalink
Add solutions for common errors
Browse files Browse the repository at this point in the history
  • Loading branch information
sdispater committed May 22, 2020
1 parent abee30f commit 2196064
Show file tree
Hide file tree
Showing 16 changed files with 233 additions and 50 deletions.
87 changes: 43 additions & 44 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions poetry/console/config/application_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from poetry.console.commands.env_command import EnvCommand
from poetry.console.logging.io_formatter import IOFormatter
from poetry.console.logging.io_handler import IOHandler
from poetry.utils._compat import PY36


class ApplicationConfig(BaseApplicationConfig):
Expand All @@ -46,6 +47,15 @@ def configure(self):
self.add_event_listener(PRE_HANDLE, self.register_command_loggers)
self.add_event_listener(PRE_HANDLE, self.set_env)

if PY36:
from poetry.mixology.solutions.providers import (
PythonRequirementSolutionProvider,
)

self._solution_provider_repository.register_solution_providers(
[PythonRequirementSolutionProvider]
)

def register_command_loggers(
self, event, event_name, _
): # type: (PreHandleEvent, str, Any) -> None
Expand Down
9 changes: 8 additions & 1 deletion poetry/mixology/failure.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
from typing import List
from typing import Tuple

from poetry.core.semver import parse_constraint

from .incompatibility import Incompatibility
from .incompatibility_cause import ConflictCause
from .incompatibility_cause import PythonCause
Expand Down Expand Up @@ -44,10 +46,15 @@ def write(self):
)
required_python_version_notification = True

root_constraint = parse_constraint(
incompatibility.cause.root_python_version
)
constraint = parse_constraint(incompatibility.cause.python_version)
buffer.append(
" - {} requires Python {}".format(
" - {} requires Python {}, so it will not be satisfied for Python {}".format(
incompatibility.terms[0].dependency.name,
incompatibility.cause.python_version,
root_constraint.difference(constraint),
)
)

Expand Down
Empty file.
1 change: 1 addition & 0 deletions poetry/mixology/solutions/providers/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .python_requirement_solution_provider import PythonRequirementSolutionProvider
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import re

from typing import List

from crashtest.contracts.has_solutions_for_exception import HasSolutionsForException
from crashtest.contracts.solution import Solution


class PythonRequirementSolutionProvider(HasSolutionsForException):
def can_solve(self, exception): # type: (Exception) -> bool
from poetry.puzzle.exceptions import SolverProblemError

if not isinstance(exception, SolverProblemError):
return False

m = re.match(
"^The current project's Python requirement (.+) is not compatible "
"with some of the required packages Python requirement",
str(exception),
)

if not m:
return False

return True

def get_solutions(self, exception): # type: (Exception) -> List[Solution]
from ..solutions.python_requirement_solution import PythonRequirementSolution

return [PythonRequirementSolution(exception)]
1 change: 1 addition & 0 deletions poetry/mixology/solutions/solutions/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .python_requirement_solution import PythonRequirementSolution
52 changes: 52 additions & 0 deletions poetry/mixology/solutions/solutions/python_requirement_solution.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
from crashtest.contracts.solution import Solution


class PythonRequirementSolution(Solution):
def __init__(self, exception):
from poetry.mixology.incompatibility_cause import PythonCause
from poetry.core.semver import parse_constraint

self._title = "Check your dependencies Python requirement."

failure = exception.error
version_solutions = []
for incompatibility in failure._incompatibility.external_incompatibilities:
if isinstance(incompatibility.cause, PythonCause):
root_constraint = parse_constraint(
incompatibility.cause.root_python_version
)
constraint = parse_constraint(incompatibility.cause.python_version)

version_solutions.append(
"For <fg=default;options=bold>{}</>, a possible solution would be "
'to set the `<fg=default;options=bold>python</>` property to <fg=yellow>"{}"</>'.format(
incompatibility.terms[0].dependency.name,
root_constraint.intersect(constraint),
)
)

description = (
"The Python requirement can be specified via the `<fg=default;options=bold>python</>` "
"or `<fg=default;options=bold>markers</>` properties"
)
if version_solutions:
description += "\n\n" + "\n".join(version_solutions)

description += "\n"

self._description = description

@property
def solution_title(self) -> str:
return self._title

@property
def solution_description(self):
return self._description

@property
def documentation_links(self):
return [
"https://python-poetry.org/docs/dependency-specification/#python-restricted-dependencies",
"https://python-poetry.org/docs/dependency-specification/#using-environment-markers",
]
Loading

0 comments on commit 2196064

Please sign in to comment.