Repository: pypa/pipenv

Issue:
Pipenv tries to resolve packages where their markers evaluates to false
### Issue description

In Pipfile, packages that were expected to become a dependency only if marker expressions evaluates to true, has unexpectedly become a dependecy when markers evaluates to false

### Expected result

Packages won't be resolved and installed under environment where markers evaluates to false.

### Actual result

Pipenv tries to resolve those packages

### Steps to replicate

OS is Archlinux

```bash
mkdir -p ~/temp
cat > ~/temp/Pipfile <<EOF
[packages]
pywin32 = {version = "==227", markers="sys_platform == 'win32'"}
EOF
pipenv install --verbose
```

`python 3.8` and `pipenv` are installed through Archlinux offical software repositories and its versions are:

```
% pacman -Qs | grep -E "(/python-pipenv )|(/python )"
local/python 3.8.3-1
local/python-pipenv 2020.6.2-1
```

<details>
<summary>Contents of `~/.pip/pip.conf`</summary>

```
[global]
trusted-host = mirrors.aliyun.com
index-url = https://pypi.doubanio.com/simple/
extra-index-url = 
	https://mirrors.aliyun.com/pypi/simple/
	https://pypi.tuna.tsinghua.edu.cn/simple

```
</details>

<details><summary>$ pipenv --support</summary>

Pipenv version: `'2020.6.2'`

Pipenv location: `'/usr/lib/python3.8/site-packages/pipenv'`

Python location: `'/usr/bin/python'`

Python installations found:

  - `3.8.3`: `/usr/bin/python3`
  - `3.8.3`: `/usr/bin/python3.8`
  - `2.7.18`: `/usr/bin/python2`
  - `2.7.18`: `/usr/bin/python2.7`

PEP 508 Information:

```
{'implementation_name': 'cpython',
 'implementation_version': '3.8.3',
 'os_name': 'posix',
 'platform_machine': 'x86_64',
 'platform_python_implementation': 'CPython',
 'platform_release': '5.7.2-arch1-1',
 'platform_system': 'Linux',
 'platform_version': '#1 SMP PREEMPT Wed, 10 Jun 2020 20:36:24 +0000',
 'python_full_version': '3.8.3',
 'python_version': '3.8',
 'sys_platform': 'linux'}
```

System environment variables:

  - `INVOCATION_ID`
  - `SSH_AUTH_SOCK`
  - `LANGUAGE`
  - `LANG`
  - `SSH_AGENT_PID`
  - `XDG_CURRENT_DESKTOP`
  - `GRADLE_HOME`
  - `ANDROID_HOME`
  - `WINDOWID`
  - `HG`
  - `CUDA_PATH`
  - `SESSION_MANAGER`
  - `QT_IM_MODULE`
  - `DESKTOP_SESSION`
  - `USER`
  - `XDG_MENU_PREFIX`
  - `HOME`
  - `OLDPWD`
  - `QT4_IM_MODULE`
  - `DBUS_SESSION_BUS_ADDRESS`
  - `XDG_VTNR`
  - `XDG_SEAT`
  - `GTK_MODULES`
  - `XDG_CONFIG_DIRS`
  - `WINDOWPATH`
  - `GTK_IM_MODULE`
  - `LC_TYPE`
  - `VTE_VERSION`
  - `JOURNAL_STREAM`
  - `MAIL`
  - `LOGNAME`
  - `LOCALE`
  - `UBUNTU_MENUPROXY`
  - `XDG_RUNTIME_DIR`
  - `XMODIFIERS`
  - `SHELL`
  - `XDG_SESSION_TYPE`
  - `PANEL_GDK_CORE_DEVICE_EVENTS`
  - `XDG_SESSION_ID`
  - `XDG_DATA_DIRS`
  - `PATH`
  - `QT_QPA_PLATFORMTHEME`
  - `SHLVL`
  - `PWD`
  - `XAUTHORITY`
  - `COLORTERM`
  - `XDG_SESSION_CLASS`
  - `TERM`
  - `DISPLAY`
  - `EDITOR`
  - `PAGER`
  - `LS_COLORS`
  - `LESS_TERMCAP_mb`
  - `LESS_TERMCAP_md`
  - `LESS_TERMCAP_me`
  - `LESS_TERMCAP_se`
  - `LESS_TERMCAP_so`
  - `LESS_TERMCAP_ue`
  - `LESS_TERMCAP_us`
  - `npm_config_prefix`
  - `CONDA_EXE`
  - `_CE_M`
  - `_CE_CONDA`
  - `CONDA_PYTHON_EXE`
  - `CONDA_SHLVL`
  - `_`
  - `PIP_DISABLE_PIP_VERSION_CHECK`
  - `PYTHONDONTWRITEBYTECODE`
  - `PIP_SHIMS_BASE_MODULE`
  - `PIP_PYTHON_PATH`
  - `PYTHONFINDER_IGNORE_UNSUPPORTED`

Pipenv–specific environment variables:


Debug–specific environment variables:

  - `PATH`: `/home/gnaggnoyil/anaconda3/condabin:/usr/local/sbin:/usr/local/bin:/usr/bin:/opt/android-sdk/emulator:/opt/android-sdk/build-tools/18.0.1/:/opt/android-sdk/platform-tools:/opt/android-sdk/tools:/opt/android-sdk/tools/bin:/opt/cuda/bin:/usr/lib/jvm/default/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl:/home/gnaggnoyil/.dotnet/tools:/home/gnaggnoyil/.npm/node_modules/bin`
  - `SHELL`: `/bin/zsh`
  - `EDITOR`: `vim`
  - `LANG`: `zh_CN.UTF-8`
  - `PWD`: `/home/gnaggnoyil/temp`


---------------------------

Contents of `Pipfile` ('/home/gnaggnoyil/temp/Pipfile'):

```toml
[packages]
pywin32 = {version = "==227", markers="sys_platform == 'win32'"}

```

</details>

<details>
<summary>$ pipenv install --verbose</summary>

```
Pipfile.lock not found, creating…
Locking [dev-packages] dependencies…
Locking [packages] dependencies…
Building requirements...
Resolving dependencies...
⠴ Locking...Traceback (most recent call last):
  File "/usr/lib/python3.8/site-packages/pipenv/resolver.py", line 807, in <module>
✘ Locking Failed! 
    main()
  File "/usr/lib/python3.8/site-packages/pipenv/resolver.py", line 802, in main
    _main(parsed.pre, parsed.clear, parsed.verbose, parsed.system, parsed.write,
  File "/usr/lib/python3.8/site-packages/pipenv/resolver.py", line 785, in _main
    resolve_packages(pre, clear, verbose, system, write, requirements_dir, packages)
  File "/usr/lib/python3.8/site-packages/pipenv/resolver.py", line 746, in resolve_packages
    results, resolver = resolve(
  File "/usr/lib/python3.8/site-packages/pipenv/resolver.py", line 728, in resolve
    return resolve_deps(
  File "/usr/lib/python3.8/site-packages/pipenv/utils.py", line 1378, in resolve_deps
    results, hashes, markers_lookup, resolver, skipped = actually_resolve_deps(
  File "/usr/lib/python3.8/site-packages/pipenv/utils.py", line 1090, in actually_resolve_deps
    resolver = Resolver.create(
  File "/usr/lib/python3.8/site-packages/pipenv/utils.py", line 647, in create
    constraints, skipped, index_lookup, markers_lookup = cls.get_metadata(
  File "/usr/lib/python3.8/site-packages/pipenv/utils.py", line 462, in get_metadata
    constraint_update, lockfile_update = cls.get_deps_from_req(
  File "/usr/lib/python3.8/site-packages/pipenv/utils.py", line 610, in get_deps_from_req
    best_match = pypi.find_best_match(req.ireq) if pypi else None
  File "/usr/lib/python3.8/site-packages/pipenv/patched/piptools/repositories/pypi.py", line 202, in find_best_match
    raise NoCandidateFound(ireq, all_candidates, self.finder)
pipenv.patched.piptools.exceptions.NoCandidateFound: Could not find a version that matches pywin32==227
No versions found
Were https://pypi.org/simple or https://mirrors.aliyun.com/pypi/simple/ or https://pypi.tuna.tsinghua.edu.cn/simple reachable?
Traceback (most recent call last):
  File "/usr/lib/python3.8/site-packages/pipenv/resolver.py", line 807, in <module>
    main()
  File "/usr/lib/python3.8/site-packages/pipenv/resolver.py", line 802, in main
    _main(parsed.pre, parsed.clear, parsed.verbose, parsed.system, parsed.write,
  File "/usr/lib/python3.8/site-packages/pipenv/resolver.py", line 785, in _main
    resolve_packages(pre, clear, verbose, system, write, requirements_dir, packages)
  File "/usr/lib/python3.8/site-packages/pipenv/resolver.py", line 746, in resolve_packages
    results, resolver = resolve(
  File "/usr/lib/python3.8/site-packages/pipenv/resolver.py", line 728, in resolve
    return resolve_deps(
  File "/usr/lib/python3.8/site-packages/pipenv/utils.py", line 1378, in resolve_deps
    results, hashes, markers_lookup, resolver, skipped = actually_resolve_deps(
  File "/usr/lib/python3.8/site-packages/pipenv/utils.py", line 1090, in actually_resolve_deps
    resolver = Resolver.create(
  File "/usr/lib/python3.8/site-packages/pipenv/utils.py", line 647, in create
    constraints, skipped, index_lookup, markers_lookup = cls.get_metadata(
  File "/usr/lib/python3.8/site-packages/pipenv/utils.py", line 462, in get_metadata
    constraint_update, lockfile_update = cls.get_deps_from_req(
  File "/usr/lib/python3.8/site-packages/pipenv/utils.py", line 610, in get_deps_from_req
    best_match = pypi.find_best_match(req.ireq) if pypi else None
  File "/usr/lib/python3.8/site-packages/pipenv/patched/piptools/repositories/pypi.py", line 202, in find_best_match
    raise NoCandidateFound(ireq, all_candidates, self.finder)
pipenv.patched.piptools.exceptions.NoCandidateFound: Could not find a version that matches pywin32==227
No versions found
Were https://pypi.org/simple or https://mirrors.aliyun.com/pypi/simple/ or https://pypi.tuna.tsinghua.edu.cn/simple reachable?
```
</details>



Discussion:
Ping.
Any advices yet?
I, too, am running into this issue... except I have

`pywin32 = {version = "*", markers = "platform_system == 'Windows'"}`

Same error, though.
Same here using WLS with sys_platform == 'win32'
Exact same issue on Ubuntu 18.04.

My workaround so far have been to do `pipenv lock` on a Windows machine and then `pipenv install` from the Linux machine to get it to install a new package.

This is not a viable approach for everyone unless they happen to have Windows readily available
I don't think this is an issue, the lock file should be generated **correctly for all possible platforms**. If a package can't be resolved on a specific platform, it should throw an error telling users "hey, I can't finish my job, you may need to resolve this on the right platform". Instead of skipping that package and leave an incomplete lock file.
@frostming I'm sorry but I don't quite understand your meaning of "generate correctly for all possible platforms". How does it have anything to do with platform-specific markers?

Resolving patch:
diff --git a/pipenv/utils.py b/pipenv/utils.py
--- a/pipenv/utils.py
+++ b/pipenv/utils.py
@@ -528,9 +528,10 @@ def get_deps_from_line(cls, line):
     @classmethod
     def get_deps_from_req(cls, req, resolver=None):
         # type: (Requirement, Optional["Resolver"]) -> Tuple[Set[str], Dict[str, Dict[str, Union[str, bool, List[str]]]]]
+        from .patched.piptools.exceptions import NoCandidateFound
         from .vendor.requirementslib.models.utils import _requirement_to_str_lowercase_name
         from .vendor.requirementslib.models.requirements import Requirement
-        from requirementslib.utils import is_installable_dir
+        from .vendor.requirementslib.utils import is_installable_dir
         # TODO: this is way too complex, refactor this
         constraints = set()  # type: Set[str]
         locked_deps = dict()  # type: Dict[str, Dict[str, Union[str, bool, List[str]]]]
@@ -607,13 +608,27 @@ def get_deps_from_req(cls, req, resolver=None):
                 req.requirement.marker and not req.requirement.marker.evaluate()
             ):
                 pypi = resolver.repository if resolver else None
-                best_match = pypi.find_best_match(req.ireq) if pypi else None
+                try:
+                    best_match = pypi.find_best_match(req.ireq) if pypi else None
+                except NoCandidateFound:
+                    best_match = None
                 if best_match:
                     hashes = resolver.collect_hashes(best_match) if resolver else []
                     new_req = Requirement.from_ireq(best_match)
                     new_req = new_req.add_hashes(hashes)
                     name, entry = new_req.pipfile_entry
                     locked_deps[pep423_name(name)] = translate_markers(entry)
+                    click_echo(
+                        "{} doesn't match your environment, "
+                        "its dependencies won't be resolved.".format(req.as_line()),
+                        err=True
+                    )
+                else:
+                    click_echo(
+                        "Could not find a version of {} that matches your environment, "
+                        "it will be skipped.".format(req.as_line()),
+                        err=True
+                    )
                 return constraints, locked_deps
             constraints.add(req.constraint_line)
             return constraints, locked_deps
@@ -1324,6 +1339,8 @@ def venv_resolve_deps(
             results = c.out.strip()
             if c.ok:
                 sp.green.ok(environments.PIPENV_SPINNER_OK_TEXT.format("Success!"))
+                if c.out.strip():
+                    click_echo(crayons.yellow("Warning: {0}".format(c.out.strip())), err=True)
             else:
                 sp.red.fail(environments.PIPENV_SPINNER_FAIL_TEXT.format("Locking Failed!"))
                 click_echo("Output: {0}".format(c.out.strip()), err=True)


Test patch:
diff --git a/tests/integration/test_lock.py b/tests/integration/test_lock.py
--- a/tests/integration/test_lock.py
+++ b/tests/integration/test_lock.py
@@ -105,13 +105,27 @@ def test_keep_outdated_doesnt_remove_lockfile_entries(PipenvInstance):
     with PipenvInstance(chdir=True) as p:
         p._pipfile.add("requests", "==2.18.4")
         p._pipfile.add("colorama", {"version": "*", "markers": "os_name=='FakeOS'"})
-        p.pipenv("install")
+        c = p.pipenv("install")
+        assert c.ok
+        assert "doesn't match your environment, its dependencies won't be resolved." in c.err
         p._pipfile.add("six", "*")
         p.pipenv("lock --keep-outdated")
         assert "colorama" in p.lockfile["default"]
         assert p.lockfile["default"]["colorama"]["markers"] == "os_name == 'FakeOS'"
 
 
+@pytest.mark.lock
+def test_resolve_skip_unmatched_requirements(PipenvInstance):
+    with PipenvInstance(chdir=True) as p:
+        p._pipfile.add("missing-package", {"markers": "os_name=='FakeOS'"})
+        c = p.pipenv("lock")
+        assert c.ok
+        assert (
+            "Could not find a version of missing-package; "
+            "os_name == 'FakeOS' that matches your environment"
+        ) in c.err
+
+
 @pytest.mark.lock
 @pytest.mark.keep_outdated
 def test_keep_outdated_doesnt_upgrade_pipfile_pins(PipenvInstance):