Repository: python-poetry/poetry

Issue:
Can't use private repository in `poetry add`
Poetry version: 0.10.3
Python Version: 3.6.5

(Note: I redacted URL of my private repository)

pyproject.toml:

```toml
[tool.poetry]
name = "project"
version = "0.1.0"
description = ""
authors = []

[[tool.poetry.source]]
name = "private"
url = "<url>"

[tool.poetry.dependencies]
python = "^3.6"

[tool.poetry.dev-dependencies]
pytest = "^3.5"
```

I ran the following two commands:

* `poetry config repositories.private <url>`
* `poetry config http-basic.private <username>`

Checking the config files on disk, the values are correct.

When I run `poetry search <private package>` or `poetry add <private package>` poetry cannot find the package. Here's the output of `poetry -vvv add`:

```
poetry -vvv add <private package>
                                  
[ValueError]       
Package [<private package>] not found.  
                                  
Exception trace:
 /usr/local/lib/python3.6/site-packages/poetry/_vendor/cleo/application.py in run() at line 94
   status_code = self.do_run(input_, output_)
 /usr/local/lib/python3.6/site-packages/poetry/console/application.py in do_run() at line 87
   return super(Application, self).do_run(i, o)
 /usr/local/lib/python3.6/site-packages/poetry/_vendor/cleo/application.py in do_run() at line 197
   status_code = command.run(input_, output_)
 /usr/local/lib/python3.6/site-packages/poetry/console/commands/command.py in run() at line 72
   return super(BaseCommand, self).run(i, o)
 /usr/local/lib/python3.6/site-packages/poetry/_vendor/cleo/commands/base_command.py in run() at line 146
   status_code = self.execute(input_, output_)
 /usr/local/lib/python3.6/site-packages/poetry/_vendor/cleo/commands/command.py in execute() at line 107
   return self.handle()
 /usr/local/lib/python3.6/site-packages/poetry/console/commands/add.py in handle() at line 65
   packages, allow_prereleases=self.option("allow-prereleases")
 /usr/local/lib/python3.6/site-packages/poetry/console/commands/init.py in _determine_requirements() at line 215
   requirement["name"], allow_prereleases=allow_prereleases
 /usr/local/lib/python3.6/site-packages/poetry/console/commands/init.py in _find_best_version_for_package() at line 245
   name, required_version, allow_prereleases=allow_prereleases
 /usr/local/lib/python3.6/site-packages/poetry/version/version_selector.py in find_best_candidate() at line 28
   package_name, constraint, allow_prereleases=allow_prereleases
 /usr/local/lib/python3.6/site-packages/poetry/repositories/pool.py in find_packages() at line 83
   name, constraint, extras=extras, allow_prereleases=allow_prereleases
 /usr/local/lib/python3.6/site-packages/poetry/repositories/pypi_repository.py in find_packages() at line 90
   info = self.get_package_info(name)
 /usr/local/lib/python3.6/site-packages/poetry/repositories/pypi_repository.py in get_package_info() at line 225
   name, lambda: self._get_package_info(name)
 /usr/local/lib/python3.6/site-packages/poetry/_vendor/cachy/repository.py in remember_forever() at line 174
   val = value(callback)
 /usr/local/lib/python3.6/site-packages/poetry/_vendor/cachy/helpers.py in value() at line 6
   return val()
 /usr/local/lib/python3.6/site-packages/poetry/repositories/pypi_repository.py in <lambda>() at line 225
   name, lambda: self._get_package_info(name)
 /usr/local/lib/python3.6/site-packages/poetry/repositories/pypi_repository.py in _get_package_info() at line 231
   raise ValueError("Package [{}] not found.".format(name))

add [-D|--dev] [--git GIT] [--path PATH] [-E|--extras EXTRAS] [--optional] [--python PYTHON] [--platform PLATFORM] [--allow-prereleases] [--dry-run] [--] <name> (<name>)...
```

We use pypicloud for our private repository.


Discussion:
have you tried changing if you're using the `/simple/` index (or some other equivalent), and then toggling the trailing slash? I've found that it's pretty finicky about which url goes where, and after running into your problem it just...fixed itself after a few different urls. (currently using `/simple` with no slash)

It'd be nice to have some attempted diagnostics (like wrong format vs 404/403 or something).
@ojii You might want to try the latest preview release (`0.11.0a4`), it should be fixed.
> have you tried changing if you're using the /simple/ index (or some other equivalent), and then toggling the trailing slash?

I'm using the exact same URL that works fine with `pip3`. 

> @ojii You might want to try the latest preview release (0.11.0a4), it should be fixed.
@sdispater I've upgraded to `Poetry 0.11.0-alpha.4` but still have the same issue.

Got same issue. Private repository configured step by step like described in https://poetry.eustace.io/docs/repositories/.

```
Updating dependencies
Resolving dependencies...
   1: fact: my-package is 0.1.0-alpha.0
   1: derived: my-package
   1: fact: my-package depends on my-private (*)
   1: selecting my-package (0.1.0-alpha.0)
   1: derived: my-private (*)
privatepypi: 0 packages found for my-private *
   1: fact: my-private doesn't exist
   1: conflict: my-private doesn't exist
   1: ! my-private (*) is satisfied by my-private (*)
   1: ! which is caused by "my-package depends on my-private (*)"
   1: ! thus: version solving failed
   1: Version solving took 0.440 seconds.
   1: Tried 1 solutions.

[SolverProblemError]
Because my-package depends on my-private (*) which doesn't exist, version solving failed.

Exception trace:
 /Users/ng/.pyenv/versions/3.6.5/lib/python3.6/site-packages/cleo/application.py in run() at line 94
   status_code = self.do_run(input_, output_)
 /Users/ng/.pyenv/versions/3.6.5/lib/python3.6/site-packages/poetry/console/application.py in do_run() at line 88
   return super(Application, self).do_run(i, o)
 /Users/ng/.pyenv/versions/3.6.5/lib/python3.6/site-packages/cleo/application.py in do_run() at line 197
   status_code = command.run(input_, output_)
 /Users/ng/.pyenv/versions/3.6.5/lib/python3.6/site-packages/poetry/console/commands/command.py in run() at line 72
   return super(BaseCommand, self).run(i, o)
 /Users/ng/.pyenv/versions/3.6.5/lib/python3.6/site-packages/cleo/commands/base_command.py in run() at line 146
   status_code = self.execute(input_, output_)
 /Users/ng/.pyenv/versions/3.6.5/lib/python3.6/site-packages/cleo/commands/command.py in execute() at line 107
   return self.handle()
 /Users/ng/.pyenv/versions/3.6.5/lib/python3.6/site-packages/poetry/console/commands/install.py in handle() at line 50
   return installer.run()
 /Users/ng/.pyenv/versions/3.6.5/lib/python3.6/site-packages/poetry/installation/installer.py in run() at line 76
   self._do_install(local_repo)
 /Users/ng/.pyenv/versions/3.6.5/lib/python3.6/site-packages/poetry/installation/installer.py in _do_install() at line 158
   ops = solver.solve(use_latest=self._whitelist)
 /Users/ng/.pyenv/versions/3.6.5/lib/python3.6/site-packages/poetry/puzzle/solver.py in solve() at line 31
   packages, depths = self._solve(use_latest=use_latest)
 /Users/ng/.pyenv/versions/3.6.5/lib/python3.6/site-packages/poetry/puzzle/solver.py in _solve() at line 130
   raise SolverProblemError(e)

install [--no-dev] [--dry-run] [-E|--extras EXTRAS] [--develop DEVELOP]
```

Interesting fact if in `pyproject.toml` define source with basic auth then everything work as expected (but I don't want to store credentials in repo).
```
[[tool.poetry.source]]
name = "privatepypi"
url = "https://username@password:party.jfrog.io/party/api/pypi/pypi/simple/"
```

As PyPI server we use Artifactory by JFrog.

And poetry version is `0.11.2`.
So as I understand from code base when `poetry` tries to access private repository for search or install command authentication credentials which configured and stored in `auth.toml` not used.

And for example in case of `publish` command `poetry` reads `auth.toml` and uses credentials from it https://github.com/sdispater/poetry/blob/master/poetry/masonry/publishing/publisher.py#L66.
@sdispater am I right?
`search` (and probably `install`) seem to completely ignore custom repositories.
Can it be fixed soon?
I've created a PR #307 with fix.
I am facing a similar issue (not able to add package from a private repository) though its not related to authentication.

- **OS version and name**: 4.17.5-1-MANJARO
- **Poetry version**: Poetry 0.11.2
- **Link of a [Gist](https://gist.github.com/) with the contents of your pyproject.toml file**: [toml](https://gist.github.com/lepisma/93b2c0d280d48859e5ad1007dd3332dc)

Trying to add -vvv gives this:

```
[IndexError]  
list index out of range    
                             
Exception trace:
 /home/lepisma/.miniconda/lib/python3.6/site-packages/poetry/_vendor/cleo/application.py in run() at line 94
   status_code = self.do_run(input_, output_)
 /home/lepisma/.miniconda/lib/python3.6/site-packages/poetry/console/application.py in do_run() at line 88
   return super(Application, self).do_run(i, o)
 /home/lepisma/.miniconda/lib/python3.6/site-packages/poetry/_vendor/cleo/application.py in do_run() at line 197
   status_code = command.run(input_, output_)
 /home/lepisma/.miniconda/lib/python3.6/site-packages/poetry/console/commands/command.py in run() at line 72
   return super(BaseCommand, self).run(i, o)
 /home/lepisma/.miniconda/lib/python3.6/site-packages/poetry/_vendor/cleo/commands/base_command.py in run() at line 146
   status_code = self.execute(input_, output_)
 /home/lepisma/.miniconda/lib/python3.6/site-packages/poetry/_vendor/cleo/commands/command.py in execute() at line 107
   return self.handle()
 /home/lepisma/.miniconda/lib/python3.6/site-packages/poetry/console/commands/add.py in handle() at line 137
   status = installer.run()
 /home/lepisma/.miniconda/lib/python3.6/site-packages/poetry/installation/installer.py in run() at line 76
   self._do_install(local_repo)
 /home/lepisma/.miniconda/lib/python3.6/site-packages/poetry/installation/installer.py in _do_install() at line 158
   ops = solver.solve(use_latest=self._whitelist)
 /home/lepisma/.miniconda/lib/python3.6/site-packages/poetry/puzzle/solver.py in solve() at line 31
   packages, depths = self._solve(use_latest=use_latest)
 /home/lepisma/.miniconda/lib/python3.6/site-packages/poetry/puzzle/solver.py in _solve() at line 121
   self._package, self._provider, locked=locked, use_latest=use_latest
 /home/lepisma/.miniconda/lib/python3.6/site-packages/poetry/mixology/__init__.py in resolve_version() at line 7
   return solver.solve()
 /home/lepisma/.miniconda/lib/python3.6/site-packages/poetry/mixology/version_solver.py in solve() at line 79
   next = self._choose_package_version()
 /home/lepisma/.miniconda/lib/python3.6/site-packages/poetry/mixology/version_solver.py in _choose_package_version() at line 378
   version = self._provider.complete_package(version)
 /home/lepisma/.miniconda/lib/python3.6/site-packages/poetry/puzzle/provider.py in complete_package() at line 323
   package.name, package.version.text, extras=package.requires_extras
 /home/lepisma/.miniconda/lib/python3.6/site-packages/poetry/repositories/pool.py in package() at line 67
   package = repository.package(name, version, extras=extras)
 /home/lepisma/.miniconda/lib/python3.6/site-packages/poetry/repositories/legacy_repository.py in package() at line 235
   release_info = self.get_release_info(name, version)
 /home/lepisma/.miniconda/lib/python3.6/site-packages/poetry/repositories/pypi_repository.py in get_release_info() at line 239
   "{}:{}".format(name, version), lambda: self._get_release_info(name, version)
 /home/lepisma/.miniconda/lib/python3.6/site-packages/poetry/_vendor/cachy/repository.py in remember_forever() at line 174
   val = value(callback)
 /home/lepisma/.miniconda/lib/python3.6/site-packages/poetry/_vendor/cachy/helpers.py in value() at line 6
   return val()
 /home/lepisma/.miniconda/lib/python3.6/site-packages/poetry/repositories/pypi_repository.py in <lambda>() at line 239
   "{}:{}".format(name, version), lambda: self._get_release_info(name, version)
 /home/lepisma/.miniconda/lib/python3.6/site-packages/poetry/repositories/legacy_repository.py in _get_release_info() at line 297
   default_link = links[0]

add [-D|--dev] [--git GIT] [--path PATH] [-E|--extras EXTRAS] [--optional] [--python PYTHON] [--platform PLATFORM] [--allow-prereleases] [--dry-run] [--] <name> (<name>)...
```

I tried to look into the problem and found that the `IndexError` gets thrown when it looks for `pytest` in my private repo (which is a `LegacyRepository`) while looping over the pool. I assume when we don't find anything in a repository from the pool, [we skip that repo and continue](https://github.com/sdispater/poetry/blob/1b7492e5659a43c0a05f10c6d60e90603c6c3406/poetry/repositories/pool.py#L68). This skipping is not capturing the `IndexError` (happening [here](https://github.com/sdispater/poetry/blob/1b7492e5659a43c0a05f10c6d60e90603c6c3406/poetry/repositories/legacy_repository.py#L297)).

As of now, I am adding a catch block for `IndexError` in pool.py and its working fine. Though @sdispater might want to take a look.
Any news on this? @sdispater?

Resolving patch:
diff --git a/poetry/repositories/legacy_repository.py b/poetry/repositories/legacy_repository.py
--- a/poetry/repositories/legacy_repository.py
+++ b/poetry/repositories/legacy_repository.py
@@ -298,6 +298,12 @@ def _get_release_info(self, name, version):  # type: (str, str) -> dict
         }
 
         links = list(page.links_for_version(Version.parse(version)))
+        if not links:
+            raise ValueError(
+                'No valid distribution links found for package: "{}" version: "{}"'.format(
+                    name, version
+                )
+            )
         urls = {}
         hashes = []
         default_link = links[0]


Test patch:
diff --git a/tests/repositories/fixtures/legacy/missing-version.html b/tests/repositories/fixtures/legacy/missing-version.html
new file mode 100644
--- /dev/null
+++ b/tests/repositories/fixtures/legacy/missing-version.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Links for poetry</title>
+  </head>
+  <body>
+    <h1>Links for poetry</h1>
+    <a href="poetry-0.1.0-py3-none-any.whl#sha256=1d85132efab8ead3c6f69202843da40a03823992091c29f8d65a31af68940163" data-requires-python="&gt;=3.6.0">poetry-0.1.0-py3-none-any.whl</a><br/>
+    </body>
+</html>
+<!--SERIAL 3907384-->
\ No newline at end of file
diff --git a/tests/repositories/test_legacy_repository.py b/tests/repositories/test_legacy_repository.py
--- a/tests/repositories/test_legacy_repository.py
+++ b/tests/repositories/test_legacy_repository.py
@@ -1,3 +1,5 @@
+import pytest
+
 from poetry.repositories.legacy_repository import LegacyRepository
 from poetry.repositories.legacy_repository import Page
 from poetry.utils._compat import Path
@@ -50,3 +52,10 @@ def test_http_basic_auth_repo(mocker):
 
     mock.assert_called_once_with("legacy")
     assert repo._session.auth == ("user1", "p4ss")
+
+
+def test_missing_version(mocker):
+    repo = MockRepository()
+
+    with pytest.raises(ValueError):
+        repo._get_release_info("missing_version", "1.1.0")