Repository: conan-io/conan

Issue:
Ugly traceback when a python require is not found in the remotes
With a recipe with a python require that is not found in any configured remotes:

```
conan inspect . -a options
zlib/1.2.8@conan/stable: Not found in local cache, looking in remotes...
zlib/1.2.8@conan/stable: Trying with 'kk'...
zlib/1.2.8@conan/stable: Trying with 'rr'...
zlib/1.2.8@conan/stable: Trying with 'bincrafters'...
zlib/1.2.8@conan/stable: Trying with 'arti'...
zlib/1.2.8@conan/stable: Trying with 'virtual'...
zlib/1.2.8@conan/stable: Trying with 'c3i_PR-1_9fe37beb14d6c6ecfcec3127ea197805dcdda695'...
zlib/1.2.8@conan/stable: Trying with 'c3i_PR-1_20437a99db62349f366d19e8a571b7f1c5c1eafa'...
zlib/1.2.8@conan/stable: Trying with 'c3i_PR-1_a9da64e0861fb0a7fc7f2448a47f7ce97fda8a73'...
ERROR: Unable to load conanfile in /tmp/kk/conanfile.py
ValueError: not enough values to unpack (expected 7, got 1)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/luism/workspace/conan_sources/conans/client/conan_api.py", line 285, in inspect
    ref = ConanFileReference.loads(path)
  File "/home/luism/workspace/conan_sources/conans/model/ref.py", line 114, in loads
    "OpenCV/1.0.6@user/stable" % text)
conans.errors.ConanException: Wrong package recipe reference .
Write something like OpenCV/1.0.6@user/stable

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/luism/workspace/conan_sources/conans/client/loader.py", line 45, in load_class
    return self.cached_conanfiles[conanfile_path]
KeyError: '/tmp/kk/conanfile.py'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/luism/workspace/conan_sources/conans/client/graph/python_requires.py", line 33, in _look_for_require
    python_require = self._cached_requires[require]
KeyError: 'zlib/1.2.8@conan/stable'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/luism/workspace/conan_sources/conans/client/loader.py", line 254, in _parse_conanfile
    loaded = imp.load_source(module_id, conan_file_path)
  File "/home/luism/.virtualenvs/conan_use/lib/python3.6/imp.py", line 172, in load_source
    module = _load(spec)
  File "<frozen importlib._bootstrap>", line 684, in _load
  File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 678, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "/tmp/kk/conanfile.py", line 3, in <module>
    kk = python_requires("zlib/1.2.8@conan/stable")
  File "/home/luism/workspace/conan_sources/conans/client/graph/python_requires.py", line 58, in __call__
    python_req = self._look_for_require(require)
  File "/home/luism/workspace/conan_sources/conans/client/graph/python_requires.py", line 41, in _look_for_require
    recorder=ActionRecorder())
  File "/home/luism/workspace/conan_sources/conans/client/graph/proxy.py", line 33, in get_recipe
    result = self._get_recipe(ref, check_updates, update, remote_name, recorder)
  File "/home/luism/workspace/conan_sources/conans/client/graph/proxy.py", line 49, in _get_recipe
    remote, new_ref = self._download_recipe(ref, output, remote_name, recorder)
  File "/home/luism/workspace/conan_sources/conans/client/graph/proxy.py", line 155, in _download_recipe
    raise NotFoundException(msg)
conans.errors.NotFoundException: Unable to find 'zlib/1.2.8@conan/stable' in remotes
```


Discussion:

Resolving patch:
diff --git a/conans/client/graph/python_requires.py b/conans/client/graph/python_requires.py
--- a/conans/client/graph/python_requires.py
+++ b/conans/client/graph/python_requires.py
@@ -5,7 +5,7 @@
 from conans.client.recorder.action_recorder import ActionRecorder
 from conans.model.ref import ConanFileReference
 from conans.model.requires import Requirement
-from conans.errors import ConanException
+from conans.errors import ConanException, NotFoundException
 
 PythonRequire = namedtuple("PythonRequire", "ref module conanfile")
 
@@ -66,6 +66,9 @@ def _look_for_require(self, require):
     def __call__(self, require):
         if not self.valid:
             raise ConanException("Invalid use of python_requires(%s)" % require)
-        python_req = self._look_for_require(require)
-        self._requires.append(python_req)
-        return python_req.module
+        try:
+            python_req = self._look_for_require(require)
+            self._requires.append(python_req)
+            return python_req.module
+        except NotFoundException:
+            raise ConanException('Unable to find python_requires("{}") in remotes'.format(require))
diff --git a/conans/client/loader.py b/conans/client/loader.py
--- a/conans/client/loader.py
+++ b/conans/client/loader.py
@@ -41,14 +41,18 @@ def invalidate_caches(self):
         self._python_requires.invalidate_caches()
 
     def load_class(self, conanfile_path):
+        conanfile = self.cached_conanfiles.get(conanfile_path)
+        if conanfile:
+            return conanfile
+
         try:
-            return self.cached_conanfiles[conanfile_path]
-        except KeyError:
             self._python_requires.valid = True
             _, conanfile = parse_conanfile(conanfile_path, self._python_requires)
             self._python_requires.valid = False
             self.cached_conanfiles[conanfile_path] = conanfile
-        return conanfile
+            return conanfile
+        except ConanException as e:
+            raise ConanException("Error loading conanfile at '{}': {}".format(conanfile_path, e))
 
     def load_export(self, conanfile_path, name, version, user, channel):
         conanfile = self.load_class(conanfile_path)
@@ -274,6 +278,8 @@ def _parse_conanfile(conan_file_path):
                     if folder.startswith(current_dir):
                         module = sys.modules.pop(added)
                         sys.modules["%s.%s" % (module_id, added)] = module
+    except ConanException:
+        raise
     except Exception:
         import traceback
         trace = traceback.format_exc().split('\n')


Test patch:
diff --git a/conans/test/functional/command/inspect_test.py b/conans/test/functional/command/inspect_test.py
--- a/conans/test/functional/command/inspect_test.py
+++ b/conans/test/functional/command/inspect_test.py
@@ -1,5 +1,6 @@
 import json
 import os
+import textwrap
 import unittest
 
 from conans.test.utils.tools import TestClient, TestServer
@@ -33,6 +34,25 @@ class Pkg(base.Pkg):
         self.assertIn("Base/0.1@lasote/testing", client.out)
         self.assertIn("Pkg/0.1@lasote/testing", client.out)
 
+    def python_requires_not_found_test(self):
+        server = TestServer()
+        client = TestClient(servers={"default": server}, users={"default": [("user", "channel")]})
+        conanfile = textwrap.dedent("""
+            from conans import ConanFile, python_requires
+
+            base = python_requires("name/version@user/channel")
+
+            class MyLib(ConanFile):
+                pass
+            """)
+
+        client.save({'conanfile.py': conanfile})
+        client.run("inspect . -a options", assert_error=True)
+        self.assertIn("Error loading conanfile at ", client.out)
+        self.assertIn('Unable to find python_requires("name/version@user/channel")'
+                      ' in remotes', client.out)
+        self.assertEqual(3, len(str(client.out).splitlines()))
+
     def name_version_test(self):
         server = TestServer()
         client = TestClient(servers={"default": server}, users={"default": [("lasote", "mypass")]})