Skip to content

Commit

Permalink
Added canonicalize_name() to console/commands/init.py (#5076)
Browse files Browse the repository at this point in the history
* Added canonicalize_name() to console/commands/init.py

* Removed unnecessary helper function calls

* Fixed capitalized package bug on poetry init

Used canonicalize_name to standardize the names of all packages in
poetry init with interactive dependencies. Given its importance, added a
test_canoncalize_name() test to tests/utils/test_helpers.py

* Split out _get_choice_list to a separate function

For testing purposes

* Tests working with canonicalized_name assigned outside of _generate_choice_list()

* Changed test_generate_choice_list

Parameterized a _generate_choice_list_packages fixture in order to call
the test with both > 10 and < 10 cases, verifying that output is <= 10
and the package_name has the desired package first in choices

* Added output message if choice_list is truncated

Also added cases for truncation and non-truncation in
test_generate_choice_list to ensure the message is printed in only the
correct cases

* Removed info_string calls

Moved info_string generation logic out of init._generate_choice_list

* Removed type hint for info_string
  • Loading branch information
evanrittenhouse authored Jan 29, 2022
1 parent c1c74b9 commit a17f1ba
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 20 deletions.
52 changes: 32 additions & 20 deletions src/poetry/console/commands/init.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@

from poetry.console.commands.command import Command
from poetry.console.commands.env_command import EnvCommand
from poetry.utils.helpers import canonicalize_name


if TYPE_CHECKING:
from poetry.core.packages.package import Package
from tomlkit.items import InlineTable

from poetry.repositories import Pool
Expand Down Expand Up @@ -242,6 +244,26 @@ def handle(self) -> int:

return 0

def _generate_choice_list(
self, matches: List["Package"], canonicalized_name: str
) -> List[str]:
choices = []
matches_names = [p.name for p in matches]
exact_match = canonicalized_name in matches_names
if exact_match:
choices.append(matches[matches_names.index(canonicalized_name)].pretty_name)

for found_package in matches:
if len(choices) >= 10:
break

if found_package.name == canonicalized_name:
continue

choices.append(found_package.pretty_name)

return choices

def _determine_requirements(
self,
requires: List[str],
Expand All @@ -254,7 +276,7 @@ def _determine_requirements(
package = self.ask(
"Search for package to add (or leave blank to continue):"
)
while package is not None:
while package:
constraint = self._parse_requirements([package])[0]
if (
"git" in constraint
Expand All @@ -267,34 +289,24 @@ def _determine_requirements(
package = self.ask("\nAdd a package:")
continue

matches = self._get_pool().search(constraint["name"])

canonicalized_name = canonicalize_name(constraint["name"])
matches = self._get_pool().search(canonicalized_name)
if not matches:
self.line("<error>Unable to find package</error>")
package = False
else:
choices = []
matches_names = [p.name for p in matches]
exact_match = constraint["name"] in matches_names
if exact_match:
choices.append(
matches[matches_names.index(constraint["name"])].pretty_name
)

for found_package in matches:
if len(choices) >= 10:
break

if found_package.name.lower() == constraint["name"].lower():
continue
choices = self._generate_choice_list(matches, canonicalized_name)

choices.append(found_package.pretty_name)

self.line(
info_string = (
f"Found <info>{len(matches)}</info> packages matching"
f" <c1>{package}</c1>"
)

if len(matches) > 10:
info_string += "\nShowing the first 10 matches"

self.line(info_string)

package = self.choice(
"\nEnter package # to add, or the complete package name if it"
" is not listed",
Expand Down
54 changes: 54 additions & 0 deletions tests/console/commands/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,22 @@
from pathlib import Path
from typing import TYPE_CHECKING
from typing import Iterator
from typing import List

import pytest

from cleo.testers.command_tester import CommandTester

from poetry.repositories import Pool
from poetry.utils._compat import decode
from poetry.utils.helpers import canonicalize_name
from tests.helpers import PoetryTestApplication
from tests.helpers import get_package


if TYPE_CHECKING:
from _pytest.fixtures import FixtureRequest
from poetry.core.packages.package import Package
from pytest_mock import MockerFixture

from poetry.poetry import Poetry
Expand Down Expand Up @@ -123,6 +127,7 @@ def test_interactive_with_dependencies(tester: CommandTester, repo: "TestReposit
repo.add_package(get_package("django-pendulum", "0.1.6-pre4"))
repo.add_package(get_package("pendulum", "2.0.0"))
repo.add_package(get_package("pytest", "3.6.0"))
repo.add_package(get_package("flask", "2.0.0"))

inputs = [
"my-package", # Package name
Expand All @@ -135,6 +140,9 @@ def test_interactive_with_dependencies(tester: CommandTester, repo: "TestReposit
"pendulu", # Search for package
"1", # Second option is pendulum
"", # Do not set constraint
"Flask",
"0",
"",
"", # Stop searching for packages
"", # Interactive dev packages
"pytest", # Search for package
Expand All @@ -158,6 +166,7 @@ def test_interactive_with_dependencies(tester: CommandTester, repo: "TestReposit
[tool.poetry.dependencies]
python = "~2.7 || ^3.6"
pendulum = "^2.0.0"
flask = "^2.0.0"
[tool.poetry.group.dev.dependencies]
pytest = "^3.6.0"
Expand Down Expand Up @@ -242,6 +251,51 @@ def test_interactive_with_git_dependencies(
assert expected in tester.io.fetch_output()


_generate_choice_list_packages_params: List[List["Package"]] = [
[
get_package("flask-blacklist", "1.0.0"),
get_package("Flask-Shelve", "1.0.0"),
get_package("flask-pwa", "1.0.0"),
get_package("Flask-test1", "1.0.0"),
get_package("Flask-test2", "1.0.0"),
get_package("Flask-test3", "1.0.0"),
get_package("Flask-test4", "1.0.0"),
get_package("Flask-test5", "1.0.0"),
get_package("Flask", "1.0.0"),
get_package("Flask-test6", "1.0.0"),
get_package("Flask-test7", "1.0.0"),
],
[
get_package("flask-blacklist", "1.0.0"),
get_package("Flask-Shelve", "1.0.0"),
get_package("flask-pwa", "1.0.0"),
get_package("Flask-test1", "1.0.0"),
get_package("Flask", "1.0.0"),
],
]


@pytest.fixture(params=_generate_choice_list_packages_params)
def _generate_choice_list_packages(request: "FixtureRequest") -> List["Package"]:
return request.param


@pytest.mark.parametrize("package_name", ["flask", "Flask", "flAsK"])
def test_generate_choice_list(
tester: CommandTester,
package_name: str,
_generate_choice_list_packages: List["Package"],
):
init_command = tester.command

packages = _generate_choice_list_packages
choices = init_command._generate_choice_list(
packages, canonicalize_name(package_name)
)

assert choices[0] == "Flask"


def test_interactive_with_git_dependencies_with_reference(
tester: CommandTester, repo: "TestRepository"
):
Expand Down
19 changes: 19 additions & 0 deletions tests/utils/test_helpers.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
from pathlib import Path
from typing import TYPE_CHECKING

import pytest

from poetry.core.utils.helpers import parse_requires

from poetry.utils.helpers import canonicalize_name
from poetry.utils.helpers import get_cert
from poetry.utils.helpers import get_client_cert

Expand Down Expand Up @@ -79,3 +82,19 @@ def test_get_client_cert(config: "Config"):
config.merge({"certificates": {"foo": {"client-cert": client_cert}}})

assert get_client_cert(config, "foo") == Path(client_cert)


test_canonicalize_name_cases = [
("flask", "flask"),
("Flask", "flask"),
("FLASK", "flask"),
("FlAsK", "flask"),
("fLaSk57", "flask57"),
("flask-57", "flask-57"),
]


@pytest.mark.parametrize("test, expected", test_canonicalize_name_cases)
def test_canonicalize_name(test: str, expected: str):
canonicalized_name = canonicalize_name(test)
assert canonicalized_name == expected

0 comments on commit a17f1ba

Please sign in to comment.